From 0f12083fdb14ae813e419500918b95cb83070586 Mon Sep 17 00:00:00 2001 From: Ian C Date: Thu, 9 Jun 2011 13:57:32 +0000 Subject: Added copies of old numbered releases. --- LICENSE | 341 ++++++ README | 33 + base.ini | 135 +++ config.h | 108 ++ debug.c | 212 ++++ debug.h | 66 ++ djgpp/file.c | 129 +++ djgpp/gfx.c | 535 +++++++++ djgpp/install | 31 + djgpp/install.c | 119 ++ djgpp/main.c | 34 + djgpp/mem.c | 325 ++++++ djgpp/platgui.c | 1975 ++++++++++++++++++++++++++++++++ djgpp/runcmd.c | 61 + djgpp/vstring.c | 42 + doc/bugs.htm | 40 + doc/building.htm | 90 ++ doc/ed_ex1.png | Bin 0 -> 262 bytes doc/ed_ex2.png | Bin 0 -> 304 bytes doc/ed_ex3.png | Bin 0 -> 327 bytes doc/ed_line.png | Bin 0 -> 7837 bytes doc/ed_lninf.png | Bin 0 -> 1267 bytes doc/ed_merge.png | Bin 0 -> 10423 bytes doc/ed_multi.png | Bin 0 -> 11443 bytes doc/ed_sect.png | Bin 0 -> 10062 bytes doc/ed_step.png | Bin 0 -> 9039 bytes doc/ed_thing.png | Bin 0 -> 10467 bytes doc/ed_vert.png | Bin 0 -> 8125 bytes doc/editing.htm | 1261 +++++++++++++++++++++ doc/glossary.htm | 127 +++ doc/index.htm | 45 + doc/license.htm | 362 ++++++ doc/mainmenu.htm | 111 ++ doc/overview.htm | 843 ++++++++++++++ doc/porting.htm | 1316 +++++++++++++++++++++ doc/thanks.htm | 70 ++ doom.cfg | 527 +++++++++ doom2.cfg | 72 ++ edit.c | 734 ++++++++++++ edit.h | 70 ++ editcord.c | 225 ++++ editcrse.c | 398 +++++++ editdraw.c | 346 ++++++ editevnt.c | 991 ++++++++++++++++ editgui.c | 470 ++++++++ editilst.c | 106 ++ editline.c | 3322 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ editmrg.c | 567 ++++++++++ editmult.c | 582 ++++++++++ editsect.c | 1577 ++++++++++++++++++++++++++ editsel.c | 133 +++ editsrot.c | 76 ++ editthng.c | 636 +++++++++++ editvar.c | 383 +++++++ editvar.h | 619 ++++++++++ editvert.c | 809 +++++++++++++ file.h | 58 + gfx.h | 314 ++++++ gfxtest.c | 430 +++++++ globals.c | 983 ++++++++++++++++ globals.h | 211 ++++ gui.c | 391 +++++++ gui.h | 88 ++ ini.c | 526 +++++++++ ini.h | 106 ++ linedefs.c | 371 ++++++ linedefs.h | 100 ++ list.c | 288 +++++ list.h | 104 ++ make/djgpp.cfg | 41 + makefile | 256 +++++ map.c | 162 +++ map.h | 86 ++ mem.h | 79 ++ platgui.h | 199 ++++ runcmd.h | 57 + sectors.c | 318 ++++++ sectors.h | 96 ++ texture.c | 594 ++++++++++ texture.h | 69 ++ things.c | 331 ++++++ things.h | 88 ++ vidoom.c | 723 ++++++++++++ vidoom.h | 44 + vstring.h | 44 + wad.c | 806 +++++++++++++ wad.h | 242 ++++ waddir.c | 75 ++ 88 files changed, 29334 insertions(+) create mode 100644 LICENSE create mode 100644 README create mode 100644 base.ini create mode 100644 config.h create mode 100644 debug.c create mode 100644 debug.h create mode 100644 djgpp/file.c create mode 100644 djgpp/gfx.c create mode 100644 djgpp/install create mode 100644 djgpp/install.c create mode 100644 djgpp/main.c create mode 100644 djgpp/mem.c create mode 100644 djgpp/platgui.c create mode 100644 djgpp/runcmd.c create mode 100644 djgpp/vstring.c create mode 100644 doc/bugs.htm create mode 100644 doc/building.htm create mode 100644 doc/ed_ex1.png create mode 100644 doc/ed_ex2.png create mode 100644 doc/ed_ex3.png create mode 100644 doc/ed_line.png create mode 100644 doc/ed_lninf.png create mode 100644 doc/ed_merge.png create mode 100644 doc/ed_multi.png create mode 100644 doc/ed_sect.png create mode 100644 doc/ed_step.png create mode 100644 doc/ed_thing.png create mode 100644 doc/ed_vert.png create mode 100644 doc/editing.htm create mode 100644 doc/glossary.htm create mode 100644 doc/index.htm create mode 100644 doc/license.htm create mode 100644 doc/mainmenu.htm create mode 100644 doc/overview.htm create mode 100644 doc/porting.htm create mode 100644 doc/thanks.htm create mode 100644 doom.cfg create mode 100644 doom2.cfg create mode 100644 edit.c create mode 100644 edit.h create mode 100644 editcord.c create mode 100644 editcrse.c create mode 100644 editdraw.c create mode 100644 editevnt.c create mode 100644 editgui.c create mode 100644 editilst.c create mode 100644 editline.c create mode 100644 editmrg.c create mode 100644 editmult.c create mode 100644 editsect.c create mode 100644 editsel.c create mode 100644 editsrot.c create mode 100644 editthng.c create mode 100644 editvar.c create mode 100644 editvar.h create mode 100644 editvert.c create mode 100644 file.h create mode 100644 gfx.h create mode 100644 gfxtest.c create mode 100644 globals.c create mode 100644 globals.h create mode 100644 gui.c create mode 100644 gui.h create mode 100644 ini.c create mode 100644 ini.h create mode 100644 linedefs.c create mode 100644 linedefs.h create mode 100644 list.c create mode 100644 list.h create mode 100644 make/djgpp.cfg create mode 100644 makefile create mode 100644 map.c create mode 100644 map.h create mode 100644 mem.h create mode 100644 platgui.h create mode 100644 runcmd.h create mode 100644 sectors.c create mode 100644 sectors.h create mode 100644 texture.c create mode 100644 texture.h create mode 100644 things.c create mode 100644 things.h create mode 100644 vidoom.c create mode 100644 vidoom.h create mode 100644 vstring.h create mode 100644 wad.c create mode 100644 wad.h create mode 100644 waddir.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..abd3cf7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/README b/README new file mode 100644 index 0000000..b3652b3 --- /dev/null +++ b/README @@ -0,0 +1,33 @@ + viDOOM v0.00 + + +viDOOM is released as Free Software. Please see LICENSE for conditions. + + + +To build viDOOM: + +1. Edit makfile. Follow the instructions for configuration at the top + of the makefile. + +2. Type 'make'. + + + +To install viDOOM: + +1. Type 'make install'. + + If install fails, or you wish to do it manully, simply copy the viDOOM + executable and the files doom.cfg and doom2.cfg to a directory. + Copy base.ini to the directory and rename it as vidoom.ini. + +2. In the directory into which viDOOM has been installed, edit vidoom.ini + to set the paths to various IWAD files. + See doc/overview.htm for details. + + + +-------------------------------------------------------------------------- + +$Id: README,v 1.4 2000/07/21 16:23:57 dosuser Exp dosuser $ diff --git a/base.ini b/base.ini new file mode 100644 index 0000000..69e203b --- /dev/null +++ b/base.ini @@ -0,0 +1,135 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program 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. +# +# This program is distributed in the hope that 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# +# viDOOM INI file +# +# $Id: base.ini,v 1.32 2000/07/28 16:21:28 dosuser Exp dosuser $ +# + +[Game] +game=doom +ask=no + +[Editor] +ask_middle_on_2sided=no +auto_block_linedefs=yes +bright=1.00 +clear_on_menu=no +clear_on_move=no +default_ceiling_height=256 +default_edit_mode=sector +default_floor_height=0 +default_light_level=200 +default_scale=5 +grid=yes +grid_lock=yes +grid_size=64 +hover_select=add +insert_select=add +linedef_select=2 +merge_linedef=ask +new_2sided_select=ask +sector_move=all +show_full_linedef_info=no +tag_highlight=yes +vertex_radius=8 +width=640 +height=480 + +[Check LINEDEF] +assume_yes=no +check_1side_lower=yes +check_1side_middle=yes +check_1side_upper=yes +check_2side_lower=yes +check_2side_middle=yes +check_2side_same_sector=yes +check_2side_upper=yes + +[viDOOM] +initial_empty_map=yes +load_flats=yes +load_sprites=yes +load_textures=yes +map_clear_warning=yes +map_exit_warning=yes +overwrite_warning=yes +show_titlepic=yes +sort_flat_names=yes +sort_texture_names=yes + +[Node Builder] +always_view_output=yes +command=bsp.exe +ignore=struct +in_before_out=yes +infile=% +outfile=-o % +use=no + +[GUI] +high=0xd2d2d2 +mid=0xb4b4b4 +low=0x8c8c8c +text=0xffffff +shadow=0x000000 +bold=0x000000 + + +[Doom] +iwad=c:\doom\doom.wad +pwad_dir=c:\wads\ +preload= +level_style=doom +vidoom_config=doom.cfg + +[Ultimate Doom] +iwad=c:\doom\ultdoom.wad +pwad_dir=c:\wads\ +preload= +level_style=ultimate doom +vidoom_config=doom.cfg + +[Doom 2] +iwad=c:\doom\doom2.wad +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +[TNT:Evilution] +iwad=c:\doom\tnt.wad +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +[Plutonia Experiment] +iwad=c:\doom\plutonia.wad +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +[ZDoom] +iwad=c:\doom\doom2.wad +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg diff --git a/config.h b/config.h new file mode 100644 index 0000000..43ba4b5 --- /dev/null +++ b/config.h @@ -0,0 +1,108 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Global config and macros + + $Id$ + +*/ + +#ifndef _CONFIG_H + +#define _CONFIG_H + +/* Usual constants +*/ +#include +#include +#include + + +/* Global viDOOM includes +*/ +#include "debug.h" +#include "vstring.h" + + +/* Version +*/ +#define VIDOOMVER "0.01" +#define VIDOOMRELEASE "(Build 05/08/2000)" + + +/* Basic, global machine types +*/ +typedef unsigned char Byte; +typedef unsigned short Word; +typedef signed short Short; +typedef unsigned long Long; + + +/* True/False +*/ +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + + +/* MIN,MAX,ABS and SGN +*/ +#ifndef MIN +# define MIN(a,b) ((a)<(b) ? (a):(b)) +#endif + +#ifndef MAX +# define MAX(a,b) ((a)>(b) ? (a):(b)) +#endif + +#ifndef ABS +# define ABS(a) ((a)<0 ? -(a):(a)) +#endif + +#ifndef SGN +# define SGN(a) ((a)<0 ? -1:(a)>0 ? 1:0) +#endif + + +/* String equalities +*/ +#define STREQ(a,b) (!StrCaseCmp((a),(b))) +#define STRNEQ(a,b) (!StrNCaseCmp((a),(b),strlen(a))) + + +/* String to integer +*/ +#define ATOI(s) ((int)strtol((s),NULL,0)) + + +/* Max path length +*/ +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + + +#endif diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..5b54b17 --- /dev/null +++ b/debug.c @@ -0,0 +1,212 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Debug output + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include +#include +#include + +#include "debug.h" + +static FILE *trace_fp=NULL; + +void _Debug(char *fmt,...) +{ + static char last[512]=""; + static char this[512]=""; + static int rep=0; + int f; + va_list va; + + if (!trace_fp) + { + trace_fp=fopen("trace.out","w"); + setbuf(trace_fp,NULL); + } + + if (trace_fp) + { + va_start(va,fmt); + vsprintf(this,fmt,va); + va_end(va); + + if (strcmp(last,this)==0) + { + rep++; + if (rep==3) + fprintf(trace_fp,"DEBUG: *** Repeating...\n"); + } + else + { + if (rep) + { + if (rep>2) + fprintf(trace_fp,"DEBUG: *** Repeated %d times\n",rep); + else + for(f=0;f2) + fprintf(trace_fp,"*** Repeated %d times\n",rep); + else + for(f=0;f=0) + { + if (val&(1<(sizeof(s)-10)) + { + sprintf(s+i,"<...>"); + return(s); + } + + size--; + addr++; + } + + s[i]=0; + return(s); +} + + +/* END OF FILE */ diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..b1b2a4b --- /dev/null +++ b/debug.h @@ -0,0 +1,66 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Debug output + + $Id$ + +*/ + +#ifndef _DEBUG_H + +#define _DEBUG_H + +#include + +#ifdef DEBUG +# define Debug(x) _Debug x +#else +# define Debug(x) +#endif + +/* Macro for function tracing. Use as: + void func(void) + { + int a; + + TRACE; + ... + } +*/ +#define TRACE _Trace(TRACEFORM) + +void _Debug(char *fmt,...); +void _Trace(char *fmt,...); + +/* Utils for debug users. Converts val to a n-character binary string +*/ +char *Binstr(int val,int n); + +/* Prints out memory as a string +*/ +char *MemStr(char *addr,int size); + +#endif + + +/* END OF FILE */ diff --git a/djgpp/file.c b/djgpp/file.c new file mode 100644 index 0000000..583a9df --- /dev/null +++ b/djgpp/file.c @@ -0,0 +1,129 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + File system interfaces + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include +#include + + +/* ---------------------------------------- PRIVATE FUNCS +*/ +static void ChangeDirsep(char *p) +{ + while(*p) + { + if (*p=='\\') + *p='/'; + + p++; + } +} + + +/* ---------------------------------------- EXPORTED FUNCS +*/ +char *Pwd(void) +{ + static char s[PATH_MAX]; + + getcwd(s,PATH_MAX); + + if (s[strlen(s)-1]!='\\') + strcat(s,"\\"); + + return(s); +} + +void Cd(char *path) +{ + chdir(path); +} + +char *Dirname(char *path) +{ + static char s[PATH_MAX]; + char *p; + + strcpy(s,path); + + p=s+strlen(s)-1; + + while((*p)&&(p>s)) + if ((*p=='/')||(*p=='\\')) + *(p+1)=0; + else + p--; + + return(s); +} + +char *Basename(char *path) +{ + static char s[PATH_MAX]; + char *p; + + strcpy(s,path); + + p=s+strlen(s)-1; + + while(p>s) + if ((*p=='/')||(*p=='\\')) + return(p+1); + else + p--; + + return(s); +} + +int FileExists(char *path) +{ + FILE *fp; + + if ((fp=fopen(path,"rb"))) + { + fclose(fp); + return(TRUE); + } + else + return(FALSE); +} + +int FilenamesEqual(char *path1, char *path2) +{ + char p1[PATH_MAX],p2[PATH_MAX]; + + strcpy(p1,path1); + strcpy(p2,path2); + + ChangeDirsep(p1); + ChangeDirsep(p2); + + return(!strcasecmp(p1,p2)); +} + + +/* END OF FILE */ diff --git a/djgpp/gfx.c b/djgpp/gfx.c new file mode 100644 index 0000000..8d8e849 --- /dev/null +++ b/djgpp/gfx.c @@ -0,0 +1,535 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Graphics functions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include +#include +#include +#include +#include +#include "gfx.h" +#include "gui.h" +#include "debug.h" + + +/* ---------------------------------------- VARS +*/ +#define COLDEP 16 +#define ACOL(c) (makecol_depth(COLDEP,((c)&0xff0000)>>16, \ + ((c)&0xff00)>>8, \ + ((c)&0xff))) + +static int init=FALSE; + +static BITMAP *bm; +static int width; +static int height; + +static int mbuttons; + +static int dirty_min_x; +static int dirty_max_x; +static int dirty_min_y; +static int dirty_max_y; + +#define DIRTY(x,y) do { \ + dirty_min_x=MIN(x,dirty_min_x); \ + dirty_min_y=MIN(y,dirty_min_y); \ + dirty_max_x=MAX((x)+1,dirty_max_x); \ + dirty_max_y=MAX((y)+1,dirty_max_y); \ + } while(0) + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ + +static void GetKey(GFXKey *key) +{ + static struct + { + int alleg; + int code; + } keym[]= { + {KEY_F1,GFX_F1}, + {KEY_F2,GFX_F2}, + {KEY_F3,GFX_F3}, + {KEY_F4,GFX_F4}, + {KEY_F5,GFX_F5}, + {KEY_F6,GFX_F6}, + {KEY_F7,GFX_F7}, + {KEY_F8,GFX_F8}, + {KEY_F9,GFX_F9}, + {KEY_F10,GFX_F10}, + {KEY_F11,GFX_F11}, + {KEY_F12,GFX_F12}, + {KEY_ESC,GFX_ESC}, + {KEY_INSERT,GFX_INSERT}, + {KEY_HOME,GFX_HOME}, + {KEY_PGUP,GFX_PGUP}, + {KEY_DEL,GFX_DELETE}, + {KEY_END,GFX_END}, + {KEY_PGDN,GFX_PGDN}, + {KEY_UP,GFX_UP}, + {KEY_DOWN,GFX_DOWN}, + {KEY_LEFT,GFX_LEFT}, + {KEY_RIGHT,GFX_RIGHT}, + {KEY_ENTER,GFX_ENTER}, + {KEY_BACKSPACE,GFX_BACKSPACE}, + {KEY_TAB,GFX_TAB}, + {-1,-1}, + }; + int f; + int k; + + while(TRUE) + { + k=readkey(); + + key->shift=key_shifts&KB_SHIFT_FLAG; + key->ctrl=key_shifts&KB_CTRL_FLAG; + key->alt=key_shifts&KB_ALT_FLAG; + + f=0; + while(keym[f].code!=-1) + { + if (keym[f].alleg==k>>8) + { + key->ascii=0; + key->code=keym[f].code; + return; + } + + f++; + } + + if (isprint(k&0xff)) + { + key->ascii=(k&0xff); + key->code=GFX_ASCII; + return; + } + } +} + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void GFX_init(void) +{ + if (!init) + { + init=TRUE; + allegro_init(); + + install_keyboard(); + + install_timer(); + + if ((mbuttons=install_mouse())==-1) + GFX_exit(EXIT_FAILURE,"Failed to install mouse handler\n"); + + set_color_depth(COLDEP); + } +} + + +void GFX_close(void) +{ + if (init) + { + allegro_exit(); + init=FALSE; + } +} + + +void GFX_open(int w,int h) +{ + height=h; + width=w; + + if (set_gfx_mode(GFX_AUTODETECT,w,h,0,0)<0) + GFX_exit(EXIT_FAILURE,"Couldn't open screen of %dx%d\n",w,h); + + if (!(bm=create_bitmap(w,h))) + GFX_exit(EXIT_FAILURE,"Couldn't create bitmap of %dx%d\n",w,h); + + show_mouse(screen); +} + + +void GFX_clear(int col) +{ + clear_to_color(bm,ACOL(col)); + dirty_min_x=0; + dirty_max_x=width; + dirty_min_y=0; + dirty_max_y=width; +} + + +void GFX_redraw(void) +{ + if (dirty_max_x1) + mb=0; + + while (TRUE) + { + if (keypressed()) + { + ev->type=GFX_KEY_EVENT; + GetKey(&ev->key); + return; + } + + if (mouse_b!=mb) + { + ev->mouse.shift=key_shifts&KB_SHIFT_FLAG; + ev->mouse.ctrl=key_shifts&KB_CTRL_FLAG; + ev->mouse.alt=key_shifts&KB_ALT_FLAG; + ev->mouse.x=mouse_x; + ev->mouse.y=mouse_y; + ev->mouse.b=mb=mouse_b; + ev->type=GFX_MOUSE_EVENT; + return; + } + } +} + + +void GFX_await_input_full(GFXEvent *ev) +{ + static time_t last_time=0; + static int mx,my,mb; + + /* Assume that a gap of 1-2 seconds means that this is a new await + input loop + */ + if (time(NULL)-last_time>1) + { + mx=-1; + my=-1; + mb=0; + } + + while (TRUE) + { + if (keypressed()) + { + ev->type=GFX_KEY_EVENT; + GetKey(&ev->key); + last_time=time(NULL); + return; + } + + if ((mouse_b!=mb)||(mouse_x!=mx)||(mouse_y!=my)) + { + ev->mouse.shift=key_shifts&KB_SHIFT_FLAG; + ev->mouse.ctrl=key_shifts&KB_CTRL_FLAG; + ev->mouse.alt=key_shifts&KB_ALT_FLAG; + ev->mouse.x=mx=mouse_x; + ev->mouse.y=my=mouse_y; + ev->mouse.b=mb=mouse_b; + ev->type=GFX_MOUSE_EVENT; + last_time=time(NULL); + return; + } + } +} + + +void GFX_exit(int code,char *fmt,...) +{ + va_list va; + + if (init) + allegro_exit(); + + va_start(va,fmt); + vfprintf(stderr,fmt,va); + va_end(va); + + exit(code); +} + + +GFX_IMAGE GFX_create_image(GFX_BITMAP *bm) +{ + BITMAP *b; + RLE_SPRITE *ret; + int x,y; + + if (!(b=create_bitmap(bm->w,bm->h))) + return(NULL); + + clear(b); + + for(x=0;xw;x++) + for(y=0;yh;y++) + putpixel(b,x,y,ACOL(bm->pal[*(bm->data+(y*bm->w)+(x))])); + + ret=get_rle_sprite(b); + destroy_bitmap(b); + + return((GFX_IMAGE)ret); +} + + +void GFX_destroy_image(GFX_IMAGE img) +{ + destroy_rle_sprite(img); +} + + +void GFX_draw_image(GFX_IMAGE i, int x, int y) +{ + RLE_SPRITE *s; + + s=i; + draw_rle_sprite(bm,s,x,y); + DIRTY(x,y); + DIRTY(x+s->w,y+s->h); +} + + +void GFX_fill_screen(GFX_IMAGE i) +{ + BITMAP *b; + RLE_SPRITE *s; + + s=i; + b=create_bitmap(s->w,s->h); + draw_rle_sprite(b,s,0,0); + + stretch_blit(b,bm,0,0,s->w,s->h,0,0,width,height); + destroy_bitmap(b); + + DIRTY(0,0); + DIRTY(width,height); +} + + +void GFX_save_screen(char *path) +{ + BITMAP *sub; + + sub=create_sub_bitmap(screen,0,0,width,height); + save_bmp(path,sub,NULL); + destroy_bitmap(sub); +} + + +/* END OF FILE */ diff --git a/djgpp/install b/djgpp/install new file mode 100644 index 0000000..754914f --- /dev/null +++ b/djgpp/install @@ -0,0 +1,31 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program 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. +# +# This program is distributed in the hope that 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# +# Install Makefile for DJGPP +# +# $Id: install,v 1.1 2000/07/19 14:05:45 dosuser Exp dosuser $ +# + +install: FORCE + $(CC) -o install.exe install.c + install.exe $(INSTALLDIR) + del install.exe + +FORCE: diff --git a/djgpp/install.c b/djgpp/install.c new file mode 100644 index 0000000..2639319 --- /dev/null +++ b/djgpp/install.c @@ -0,0 +1,119 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Install program for DOS/DJGPP version + +*/ +static const char rcs_id[]="$Id$"; + +#include +#include +#include + +/* This is done as an executable just because we can then ensure that the + slashes are the right way around +*/ +void Cmd(char *fmt, ...) +{ + char cmd[1024]; + va_list va; + + va_start(va,fmt); + vsprintf(cmd,fmt,va); + va_end(va); + + printf("*** %s\n",cmd); + strcat(cmd," > temp.$$$"); + system(cmd); + system("del temp.$$$"); +} + + +int main(int argc, char *argv[]) +{ + char path[1024]; + char *p,*pwd; + + if (argc!=2) + { + fprintf(stderr,"usage: install dir\n"); + exit(1); + } + + pwd=getcwd(NULL,1024); + + strcpy(path,argv[1]); + + if (path[strlen(path)-1]=='\\') + path[strlen(path)-1]=0; + + p=path; + + while(*p) + { + if (*p=='/') + *p='\\'; + + p++; + } + + if (chdir("..")) + exit(1); + + /* Do viDOOM + */ + mkdir(path); + + printf("===== Installing viDOOM to %s =====\n",path); + + Cmd("del %s\\vidoom.exe",path); + Cmd("del %s\\*.cfg",path); + Cmd("del %s\\vidoom.ini",path); + Cmd("copy vidoom.exe %s",path); + Cmd("copy LICENSE %s",path); + Cmd("copy *.cfg %s",path); + Cmd("copy base.ini %s",path); + Cmd("ren %s\\base.ini vidoom.ini",path); + + /* Do docs + */ + strcat(path,"\\doc"); + mkdir(path); + + Cmd("del %s\\*.htm",path); + Cmd("del %s\\*.png",path); + Cmd("copy doc\\*.htm %s",path); + Cmd("copy doc\\*.png %s",path); + + + /* Finish + */ + if (chdir(pwd)) + exit(1); + + free(pwd); + + return(0); +} + + +/* END OF FILE */ diff --git a/djgpp/main.c b/djgpp/main.c new file mode 100644 index 0000000..28a1e04 --- /dev/null +++ b/djgpp/main.c @@ -0,0 +1,34 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Startup code + +*/ +static const char rcs_id[]="$Id$"; + +#include "vidoom.h" + + +int main(int argc,char *argv[]) +{ + return(viDOOM(argc,argv)); +} diff --git a/djgpp/mem.c b/djgpp/mem.c new file mode 100644 index 0000000..f40c226 --- /dev/null +++ b/djgpp/mem.c @@ -0,0 +1,325 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Memory allocation code + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include +#include + +#include "mem.h" +#include "gfx.h" + +#include "debug.h" + +/* Comment out this define to switch off memory stats in the working version +*/ +#define MEMSTAT + +#ifdef MEMSTAT + +typedef struct + { + Long size; + Long realloc; + Long free; + char file[32]; + Long line; + } MemInfo; + +static Long grab_call=0; +static Long regrab_call=0; +static Long release_call=0; +static Long copy_call=0; +static Long strdup_call=0; +static Long total=0; +static Long total_grab=0; +static Long total_regrab=0; +static Long total_copy=0; +static Long total_free=0; +static Long total_strdup=0; + +static void status(void) +{ + Debug(("Total calls to Grab() : %lu\n",grab_call)); + Debug(("Total calls to Regrab() : %lu\n",regrab_call)); + Debug(("Total calls to Release() : %lu\n",release_call)); + Debug(("Total calls to Copy() : %lu\n",copy_call)); + Debug(("Total calls to Strdup() : %lu\n",strdup_call)); + Debug(("Total bytes allocated : %lu\n",total)); + Debug(("Total bytes allocated over life : %lu\n",total_grab)); + Debug(("Total bytes regrabbed over life : %lu\n",total_regrab)); + Debug(("Total bytes copied over life : %lu\n",total_copy)); + Debug(("Total bytes released over life : %lu\n",total_free)); + Debug(("Total bytes strdupped over life : %lu\n\n",total_strdup)); +} + +#endif + + +#ifdef MEMSTAT + +void *FGrab(char *fn, int line, int len) +{ + char *ptr; + MemInfo *mi; + + if (len==0) + len=1; + + if (!(ptr=malloc(len+sizeof(MemInfo)))) + { + status(); + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Grab(%d)\n",fn,line,len); + } + + mi=(MemInfo *)ptr; + mi->size=len; + mi->realloc=0; + mi->free=0; + ptr+=sizeof(MemInfo); + + grab_call++; + total_grab+=len; + total+=len; + + memset(ptr,0,len); + + return(ptr); +} + +#else + +void *FGrab(char *fn, int line, int len) +{ + void *ptr; + + if (len==0) + len=1; + + if (!(ptr=malloc(len))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Grab(%d)\n",fn,line,len); + + memset(ptr,0,len); + + return(ptr); +} + +#endif + + +#ifdef MEMSTAT + +void *FReGrab(char *fn, int line, void *ptr, int len) +{ + Long old; + MemInfo *mi; + char *p; + + if (len==0) + len=1; + + p=ptr; + + if (p) + p-=sizeof(MemInfo); + + if (!(p=realloc(p,len+sizeof(MemInfo)))) + { + status(); + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d ReGrab(%d)\n",fn,line,len); + } + + regrab_call++; + total_regrab+=len; + + mi=(MemInfo *)p; + old=mi->size; + mi->size=len; + mi->realloc++; + total-=old; + total+=len; + + p+=sizeof(MemInfo); + + return(p); +} + +#else + +void *FReGrab(char *fn, int line, void *ptr, int len) +{ + if (len==0) + len=1; + + if (!(ptr=realloc(ptr,len))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d ReGrab(%d)\n",fn,line,len); + + return(ptr); +} + +#endif + + +#ifdef MEMSTAT + +void FRelease(char *fn, int line, void *p) +{ + char *cp; + MemInfo *mi; + + if (!p) + return; + + cp=p; + cp-=sizeof(MemInfo); + mi=(MemInfo *)cp; + + if (mi->free==1) + Debug(("%p already freed!!! Current=%s:%d, previous=%s:%d\n", + p,fn,line,mi->file,mi->line)); + + release_call++; + + total_free+=mi->size; + total-=mi->size; + + strcpy(mi->file,fn); + mi->line=line; + mi->free=1; + + free(cp); +} + +#else + +void FRelease(char *fn, int line, void *p) +{ + free(p); +} + +#endif + + +#ifdef MEMSTAT + +void *FCopy(char *fn, int line, void *p,int len) +{ + char s[128]; + void *ptr; + + strcpy(s,fn); + strcat(s," [FCopy()]"); + + if (len==0) + ptr=FGrab(s,line,1); + else + ptr=FGrab(s,line,len); + + copy_call++; + total_copy+=len; + + if (len) + memcpy(ptr,p,len); + + return(ptr); +} + +#else + +void *FCopy(char *fn, int line, void *p,int len) +{ + void *ptr; + + if (len==0) + ptr=malloc(1); + else + ptr=malloc(len); + + if (!ptr) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Copy(%p,%d)\n",fn,line,p,len); + + if (len) + memcpy(ptr,p,len); + + return(ptr); +} + +#endif + + +#ifdef MEMSTAT + +char *FStrdup(char *fn, int line, char *p) +{ + char s[128]; + char *ptr; + + strcpy(s,fn); + strcat(s," [Strdup()]"); + + if (p) + { + ptr=FGrab(s,line,strlen(p)+1); + + strdup_call++; + total_strdup+=strlen(p)+1; + + strcpy(ptr,p); + return(ptr); + } + else + return(NULL); +} + +#else + +char *FStrdup(char *fn, int line, char *p) +{ + char *ptr; + + if (p) + { + if (!(ptr=malloc(strlen(p)+1))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Stdup(%s)\n",fn,line,p); + + strcpy(ptr,p); + return(ptr); + } + else + return(NULL); +} + +#endif + + +/* END OF FILE */ diff --git a/djgpp/platgui.c b/djgpp/platgui.c new file mode 100644 index 0000000..887ab9c --- /dev/null +++ b/djgpp/platgui.c @@ -0,0 +1,1975 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Platform specific GUI type routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "platgui.h" +#include "gfx.h" +#include "gui.h" +#include "mem.h" + +#include "debug.h" + +#define COLDEP 16 +#define ACOL(c) (makecol_depth(COLDEP,((c)&0xff0000)>>16, \ + ((c)&0xff00)>>8, \ + ((c)&0xff))) + +#define DIALOG_STRLEN 16 + +#define SMALL_BEVEL 1 /* Bevels on radio and flag boxes */ +#define BEVEL 2 /* All other bevels */ +#define TICK 2 + +/* ---------------------------------------- VARS +*/ +static int SCRW,SCRH; + +/* Global picklist data and the picklist dialog +*/ +#define PL_BORDER 0 +#define PL_TITLE 1 +#define PL_PICKLIST 2 +#define PL_END 3 + +static DIALOG picklist[PL_END+1]; +static int pick_no; +static char **pick_data; + + +/* Global image picklist data and the image picklist dialog +*/ +#define IPL_BORDER 0 +#define IPL_TITLE 1 +#define IPL_PICKLIST 2 +#define IPL_IMG_BORDER 3 +#define IPL_IMAGE 4 +#define IPL_END 5 + +static DIALOG img_picklist[IPL_END+1]; +static int img_pick_no; +static PLAT_IMG_PICKLIST + *img_pick_data; + + +typedef struct + { + int x; + int y; + int w; + int h; + } BoundBox; + + +/* ---------------------------------------- GUI OBJECT PROCS SUPPORT FUNCS +*/ +static void Rect3D(int x,int y,int w,int h, int invert,int bevel) +{ + int f; + int mid,lo,hi; + + mid=ACOL(GUI_MID); + + if (invert) + { + lo=ACOL(GUI_HI); + hi=ACOL(GUI_LO); + } + else + { + hi=ACOL(GUI_HI); + lo=ACOL(GUI_LO); + } + + rectfill(screen,x,y,x+w-1,y+h-1,mid); + + for(f=0;fox) + { + x--; + y--; + } + + for(f=0;fx, d->y, d->x+d->w, d->y+d->h, fg_color); + + /* possibly draw scrollbar + */ + if (listsize > height) + { + vline(screen, d->x+d->w-12, d->y+1, d->y+d->h-1, fg_color); + + /* create and draw the scrollbar + */ + pattern=create_bitmap(2,2); + + /* + putpixel(pattern,0,0,d->fg); + putpixel(pattern,1,1,d->fg); + putpixel(pattern,1,0,d->bg); + putpixel(pattern,0,1,d->bg); + */ + putpixel(pattern,0,0,ACOL(GUI_MID)); + putpixel(pattern,1,1,ACOL(GUI_MID)); + putpixel(pattern,1,0,ACOL(GUI_LO)); + putpixel(pattern,0,1,ACOL(GUI_LO)); + + i = ((d->h-4) * height + listsize/2) / listsize; + xx = d->x+d->w-11; + yy = d->y+2; + + if (offset > 0) + { + len = (((d->h-4) * offset) + listsize/2) / listsize; + drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0); + rectfill(screen, xx, yy, xx+10, yy+len-1, ACOL(GUI_MID)); + solid_mode(); + yy += len; + } + + if (yy+i < d->y+d->h-2) + { + Rect3D(xx, yy, 11, i, FALSE, BEVEL); + yy += i; + drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0); + rectfill(screen, xx, yy, xx+10, d->y+d->h-2, ACOL(GUI_MID)); + solid_mode(); + } + else + Rect3D(xx, yy, 11, i, FALSE, BEVEL); + + destroy_bitmap(pattern); + } +} + + +/* This code is copied from _draw_listbox() from guiproc.c in Allegro, so we + can force it to call DrawScrollableFrame() +*/ +static void DrawListbox(DIALOG *d) +{ + typedef char *(*getfuncptr)(int, int *); + int height, listsize, i, len, bar, x, y, w; + int fg_color, fg, bg; + char *sel = d->dp2; + char *s; + char store; + + (*(getfuncptr)d->dp)(-1, &listsize); + height = (d->h-3) / text_height(font); + bar = (listsize > height); + w = (bar ? d->w-14 : d->w-2); + + fg_color = (d->flags & D_DISABLED) ? gui_mg_color : d->fg; + + /* draw box contents + */ + for (i=0; id2+i < listsize) + { + if (d->d2+i == d->d1) + { + fg = d->bg; + bg = fg_color; + } + else if ((sel) && (sel[d->d2+i])) + { + fg = d->bg; + bg = gui_mg_color; + } + else + { + fg = fg_color; + bg = d->bg; + } + + s = (*(getfuncptr)d->dp)(i+d->d2, NULL); + x = d->x + 2; + y = d->y + 2 + i*text_height(font); + text_mode(bg); + rectfill(screen, x, y, x+7, y+text_height(font)-1, bg); + x += 8; + len = strlen(s); + store = 0; + while (text_length(font, s) >= d->w - (bar ? 22 : 10)) + { + s[len] = store; + len--; + store = s[len]; + s[len] = 0; + } + textout(screen, font, s, x, y, fg); + x += text_length(font, s); + s[len] = store; + if (x <= d->x+w) + rectfill(screen, x, y, d->x+w, y+text_height(font)-1, bg); + } + else + rectfill(screen, d->x+2, d->y+2+i*text_height(font), + d->x+w, d->y+1+(i+1)*text_height(font), d->bg); + } + + if (d->y+2+i*text_height(font) <= d->y+d->h-2) + rectfill(screen, d->x+2, d->y+2+i*text_height(font), + d->x+w, d->y+d->h-2, d->bg); + + /* draw frame, maybe with scrollbar + */ + DrawScrollableFrame(d, listsize, d->d2, height, fg_color, d->bg); +} + + +/* ---------------------------------------- GUI OBJECT PROCS + + Note that many of the functions are based on the source available + in guiproc.c in Allegro +*/ +static int d_3d_box(int msg, DIALOG *d, int c) +{ + if (msg==MSG_DRAW) + Rect3D(d->x,d->y,d->w,d->h,FALSE,BEVEL); + + return(D_O_K); +} + + +static int d_inv_3d_box(int msg, DIALOG *d, int c) +{ + if (msg==MSG_DRAW) + Rect3D(d->x,d->y,d->w,d->h,TRUE,BEVEL); + + return(D_O_K); +} + + +static int d_img_bmap_proc(int msg, DIALOG *d, int c) +{ + RLE_SPRITE *bm; + + if (msg==MSG_DRAW) + { + d_inv_3d_box(MSG_DRAW,&img_picklist[IPL_IMG_BORDER],0); + + if ((bm=d->dp)) + draw_rle_sprite(screen,bm,d->x,d->y); + else + gui_textout(screen,"No Image", + d->x+d->w/2,d->y+d->h/2,ACOL(BLACK),TRUE); + } + + return(D_O_K); +} + + +static int d_img_list_proc(int msg, DIALOG *d, int c) +{ + static int my_d_list_proc(int msg, DIALOG *d, int c); + int d1; + int ret; + + d1=img_picklist[IPL_PICKLIST].d1; + + ret=my_d_list_proc(msg,d,c); + + if (d1!=img_picklist[IPL_PICKLIST].d1) + { + img_picklist[IPL_IMAGE].dp= + img_pick_data[img_picklist[IPL_PICKLIST].d1].img; + + d_inv_3d_box(MSG_DRAW,&img_picklist[IPL_IMG_BORDER],0); + d_img_bmap_proc(MSG_DRAW,&img_picklist[IPL_IMAGE],0); + } + + return(ret); +} + + +int my_d_check_proc(int msg, DIALOG *d, int c) +{ + int x; + int fg; + + if (msg==MSG_DRAW) + { + fg = (d->flags & D_DISABLED) ? gui_mg_color : d->fg; + text_mode(d->bg); + gui_textout(screen, d->dp, d->x, + d->y+(d->h-(text_height(font)-gui_font_baseline))/2, + fg, FALSE); + + x=d->x+d->w-d->h; + + Rect3D(x,d->y,d->h,d->h,TRUE,SMALL_BEVEL); + rectfill(screen,x+SMALL_BEVEL,d->y+SMALL_BEVEL, + x+d->h-SMALL_BEVEL*2,d->y+d->h-SMALL_BEVEL*2, + ACOL(WHITE)); + + if (d->flags & D_SELECTED) + DrawTick(x+SMALL_BEVEL,d->y+SMALL_BEVEL, + d->h-SMALL_BEVEL*2,d->h-SMALL_BEVEL*2); + + return D_O_K; + } + + return d_button_proc(msg, d, 0); +} + + +int my_d_radio_proc(int msg, DIALOG *d, int c) +{ + int x,fg; + + switch(msg) + { + case MSG_DRAW: + fg=(d->flags & D_DISABLED) ? gui_mg_color : d->fg; + text_mode(d->bg); + gui_textout + (screen, + d->dp,d->x+d->h+text_height(font), + d->y+(d->h-(text_height(font)-gui_font_baseline))/2,fg,FALSE); + + x = d->x; + + Rect3D(x,d->y,d->h,d->h,TRUE,SMALL_BEVEL); + rectfill(screen,x+SMALL_BEVEL,d->y+SMALL_BEVEL, + x+d->h-SMALL_BEVEL*2,d->y+d->h-SMALL_BEVEL*2, + ACOL(WHITE)); + + if (d->flags & D_SELECTED) + { + rectfill(screen,x+SMALL_BEVEL+2,d->y+SMALL_BEVEL+2, + x+d->h-SMALL_BEVEL*2-2, + d->y+d->h-SMALL_BEVEL*2-2, + ACOL(BLACK)); + } + + break; + + default: + return(d_radio_proc(msg,d,c)); + break; + } + + return(D_O_K); +} + + +static int my_d_list_proc(int msg, DIALOG *d, int c) +{ + switch(msg) + { + case MSG_DRAW: + DrawListbox(d); + break; + + default: + return(d_list_proc(msg,d,c)); + break; + } + + return (D_O_K); +} + + +static int my_d_button_proc(int msg, DIALOG *d, int c) +{ + int inv; + + switch(msg) + { + case MSG_DRAW: + if (d->flags&D_SELECTED) + inv=TRUE; + else + inv=FALSE; + + Rect3D(d->x,d->y,d->w,d->h,inv,BEVEL); + text_mode(-1); + gui_textout(screen,d->dp,d->x+(d->w/2), + d->y+d->h/2-GFX_fh()/2,d->fg,TRUE); + + break; + + default: + return(d_button_proc(msg,d,c)); + break; + } + + return (D_O_K); +} + + +/* ---------------------------------------- FILE SELECTION CODE + + This code is a copy of the file selector code provided by Shawn Hargreaves + in his Allegro library (original filename fsel.c). The only changes are + to the file_selector[] DIALOG structure and some of the fs_*_proc() + callbacks to use my 3D buttons, etc. + + Shawn Hargreaves can be contacted at: + + http://www.talula.demon.co.uk/allegro/ + shawn@talula.demon.co.uk + + If this code causes problems, blame me, not Shawn! +*/ + + +#ifndef _USE_LFN +#define _USE_LFN 0 +#endif + +static int fs_edit_proc(int, DIALOG *, int ); +static int fs_flist_proc(int, DIALOG *, int ); +static int fs_dlist_proc(int, DIALOG *, int ); +static char *fs_flist_getter(int, int *); +static char *fs_dlist_getter(int, int *); + + +#define FLIST_SIZE 2048 + +typedef struct FLIST +{ + char dir[80]; + int size; + char *name[FLIST_SIZE]; +} FLIST; + +static FLIST *flist = NULL; + +static char *fext = NULL; + + + +static DIALOG file_selector[] = +{ + /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) */ + { d_3d_box, 0, 0, 304, 160, 0, 0, 0, 0, 0, 0, NULL }, + { d_inv_3d_box, 14, 26, 276, 12, 0, 0, 0, 0, 0, 0, NULL }, + { d_ctext_proc, 152, 8, 1, 1, 0, 0, 0, 0, 0, 0, NULL }, + { my_d_button_proc, 208, 107, 80, 16, 0, 0, 0, D_EXIT, 0, 0, "OK" }, + { my_d_button_proc, 208, 129, 80, 16, 0, 0, 27, D_EXIT, 0, 0, "Cancel" }, + { fs_edit_proc, 16, 28, 272, 8, 0, 0, 0, 0, 79, 0, NULL }, + { fs_flist_proc, 16, 46, 176, 99, 0, 0, 0, D_EXIT, 0, 0, fs_flist_getter }, + { fs_dlist_proc, 208, 46, 80, 51, 0, 0, 0, D_EXIT, 0, 0, fs_dlist_getter }, + { NULL } +}; + +#define FS_MESSAGE 2 +#define FS_OK 3 +#define FS_CANCEL 4 +#define FS_EDIT 5 +#define FS_FILES 6 +#define FS_DISKS 7 + + + +/* fs_dlist_getter: + * Listbox data getter routine for the file selector disk list. + */ +static char *fs_dlist_getter(int index, int *list_size) +{ + static char d[] = "A:\\"; + + if (index < 0) { + if (list_size) + *list_size = 26; + return NULL; + } + + d[0] = 'A' + index; + return d; +} + + + +/* fs_dlist_proc: + * Dialog procedure for the file selector disk list. + */ +static int fs_dlist_proc(int msg, DIALOG *d, int c) +{ + int ret; + char *s = file_selector[FS_EDIT].dp; + + if (msg == MSG_START) + d->d1 = d->d2 = 0; + + ret = my_d_list_proc(msg, d, c); + + if (ret == D_CLOSE) { + *(s++) = 'A' + d->d1; + *(s++) = ':'; + *(s++) = '\\'; + *s = 0; + show_mouse(NULL); + SEND_MESSAGE(file_selector+FS_FILES, MSG_START, 0); + SEND_MESSAGE(file_selector+FS_FILES, MSG_DRAW, 0); + SEND_MESSAGE(file_selector+FS_EDIT, MSG_START, 0); + SEND_MESSAGE(file_selector+FS_EDIT, MSG_DRAW, 0); + show_mouse(screen); + return D_O_K; + } + + return ret; +} + + + +/* fs_edit_proc: + * Dialog procedure for the file selector editable string. + */ +static int fs_edit_proc(int msg, DIALOG *d, int c) +{ + char *s = d->dp; + int ch; + int attr; + int x; + char b[80]; + + if (msg == MSG_START) { + if (s[0]) { + _fixpath(s, b); + errno = 0; + + x = s[strlen(s)-1]; + if ((x=='/') || (x=='\\')) + put_backslash(b); + + for (x=0; b[x]; x++) { + if (b[x] == '/') + s[x] = '\\'; + else + s[x] = toupper(b[x]); + } + s[x] = 0; + } + } + + if (msg == MSG_KEY) { + if (*s) + ch = s[strlen(s)-1]; + else + ch = 0; + if (ch == ':') + put_backslash(s); + else { + if ((ch != '/') && (ch != '\\')) { + if (file_exists(s, FA_RDONLY | FA_HIDDEN | FA_DIREC, &attr)) { + if (attr & FA_DIREC) + put_backslash(s); + else + return D_CLOSE; + } + else + return D_CLOSE; + } + } + show_mouse(NULL); + SEND_MESSAGE(file_selector+FS_FILES, MSG_START, 0); + SEND_MESSAGE(file_selector+FS_FILES, MSG_DRAW, 0); + SEND_MESSAGE(d, MSG_START, 0); + SEND_MESSAGE(d, MSG_DRAW, 0); + show_mouse(screen); + return D_O_K; + } + + if (msg==MSG_CHAR) { + ch = c & 0xff; + if ((ch >= 'a') && (ch <= 'z')) + c = (c & 0xffffff00L) | (ch - 'a' + 'A'); + else if (ch == '/') + c = (c & 0xffffff00L) | '\\'; + else if (_USE_LFN) { + if ((ch > 127) || ((ch < 32) && (ch != 8) && (ch != 0))) + return D_O_K; + } + else { + if ((ch != '\\') && (ch != '_') && (ch != ':') && (ch != '.') && + ((ch < 'A') || (ch > 'Z')) && ((ch < '0') || (ch > '9')) && + (ch != 8) && (ch != 127) && (ch != 0)) + return D_O_K; + } + } + + return d_edit_proc(msg, d, c); +} + + + +/* fs_flist_putter: + * Callback routine for for_each_file() to fill the file selector listbox. + */ +static void fs_flist_putter(char *str, int attrib) +{ + int c, c2; + char *s, *ext, *tok; + char tmp[80]; + static char ext_tokens[] = " ,;"; + + s = get_filename(str); + strupr(s); + + if ((fext) && (!(attrib & FA_DIREC))) { + strcpy(tmp, fext); + ext = get_extension(s); + tok = strtok(tmp, ext_tokens); + while (tok) { + if (stricmp(ext, tok) == 0) + break; + tok = strtok(NULL, ext_tokens); + } + if (!tok) + return; + } + + if ((flist->size < FLIST_SIZE) && (strcmp(s,".") != 0)) { + for (c=0; csize; c++) { + if (flist->name[c][strlen(flist->name[c])-1]=='\\') { + if (attrib & FA_DIREC) + if (strcmp(s, flist->name[c]) < 0) + break; + } + else { + if (attrib & FA_DIREC) + break; + if (strcmp(s, flist->name[c]) < 0) + break; + } + } + for (c2=flist->size; c2>c; c2--) + flist->name[c2] = flist->name[c2-1]; + + flist->name[c] = malloc(strlen(s) + ((attrib & FA_DIREC) ? 2 : 1)); + strcpy(flist->name[c], s); + if (attrib & FA_DIREC) + put_backslash(flist->name[c]); + flist->size++; + } +} + + + +/* fs_flist_getter: + * Listbox data getter routine for the file selector list. + */ +static char *fs_flist_getter(int index, int *list_size) +{ + if (index < 0) { + if (list_size) + *list_size = flist->size; + return NULL; + } + return flist->name[index]; +} + + + +/* fs_flist_proc: + * Dialog procedure for the file selector list. + */ +static int fs_flist_proc(int msg, DIALOG *d, int c) +{ + int i, ret; + int sel = d->d1; + char *s = file_selector[FS_EDIT].dp; + static int recurse_flag = 0; + + if (msg == MSG_START) { + if (!flist) + flist = malloc(sizeof(FLIST)); + else { + for (i=0; isize; i++) + if (flist->name[i]) + free(flist->name[i]); + } + if (!flist) { + errno = ENOMEM; + return D_CLOSE; + } + flist->size = 0; + for (i=0; isize; i++) + flist->name[i] = NULL; + strcpy(flist->dir, s); + *get_filename(flist->dir) = 0; + put_backslash(flist->dir); + strcat(flist->dir,"*.*"); + for_each_file(flist->dir, FA_RDONLY | FA_DIREC | FA_ARCH, fs_flist_putter, 0); + if (errno) + alert(NULL, "Disk error", NULL, "OK", NULL, 13, 0); + *get_filename(flist->dir) = 0; + d->d1 = d->d2 = 0; + sel = 0; + } + + if (msg == MSG_END) { + if (flist) { + for (i=0; isize; i++) + if (flist->name[i]) + free(flist->name[i]); + free(flist); + } + flist = NULL; + } + + recurse_flag++; + ret = my_d_list_proc(msg,d,c); /* call the parent procedure */ + recurse_flag--; + + if (((sel != d->d1) || (ret == D_CLOSE)) && (recurse_flag == 0)) { + strcpy(s, flist->dir); + *get_filename(s) = 0; + put_backslash(s); + strcat(s, flist->name[d->d1]); + show_mouse(NULL); + SEND_MESSAGE(file_selector+FS_EDIT, MSG_START, 0); + SEND_MESSAGE(file_selector+FS_EDIT, MSG_DRAW, 0); + show_mouse(screen); + + if (ret == D_CLOSE) + return SEND_MESSAGE(file_selector+FS_EDIT, MSG_KEY, 0); + } + + return ret; +} + + + +/* my_file_select: + * Displays the Allegro file selector, with the message as caption. + * Allows the user to select a file, and stores the selection in path + * (which should have room for at least 80 characters). The files are + * filtered according to the file extensions in ext. Passing NULL + * includes all files, "PCX;BMP" includes only files with .PCX or .BMP + * extensions. Returns zero if it was closed with the Cancel button, + * non-zero if it was OK'd. + */ +int my_file_select(char *message, char *path, char *ext) +{ + int ret; + char *p; + int f; + + f=0; + while(file_selector[f].proc) + { + switch(f) + { + case FS_EDIT: + case FS_FILES: + case FS_DISKS: + file_selector[f].fg=ACOL(BLACK); + file_selector[f].bg=ACOL(WHITE); + break; + + default: + file_selector[f].fg=gui_fg_color; + file_selector[f].bg=gui_bg_color; + break; + } + + f++; + } + + file_selector[FS_MESSAGE].dp = message; + file_selector[FS_EDIT].dp = path; + fext = ext; + + if (!path[0]) { + getcwd(path, 80); + for (p=path; *p; p++) + if (*p=='/') + *p = '\\'; + else + *p = toupper(*p); + + put_backslash(path); + } + + clear_keybuf(); + + do { + } while (mouse_b); + + centre_dialog(file_selector); + ret = do_dialog(file_selector, FS_EDIT); + + if ((ret == FS_CANCEL) || (*get_filename(path) == 0)) + return FALSE; + + p = get_extension(path); + if ((*p == 0) && (ext) && (!strpbrk(ext, " ,;"))) { + *p = '.'; + strcpy(p+1, ext); + } + + return TRUE; +} + + +/* ---------------------------------------- GUI MENU SUPPORT FUNCS +*/ +static void DrawMenuItem(BoundBox *b,char *txt,int sel) +{ + int fg; + + fg=ACOL(GUI_TEXT); + + if (sel) + Rect3D(b->x,b->y,b->w,b->h,FALSE,SMALL_BEVEL); + else + rectfill(screen,b->x,b->y,b->x+b->w-1,b->y+b->h-1,ACOL(GUI_MID)); + + text_mode(-1); + textout(screen,font,txt,b->x+SMALL_BEVEL+2,b->y+b->h/2-GFX_fh()/2,fg); +} + + +static int MouseInBox(BoundBox *box,int no) +{ + int f; + + for(f=0;f=box[f].x)&&(mouse_x=box[f].y)&&(mouse_ySCRW) + x=SCRW-w; + + if ((y+h)>SCRH) + y=SCRH-h; + + if ((x<0)||(y<0)) + { + alert("Cannot display menu:",title,"Menu is bigger than display!", + "OK",NULL,0,0); + + return(defval); + } + + cx=x+w/2; + + cur=0; + + /* Save screen contents + */ + show_mouse(NULL); + + if (!(under=create_bitmap(w+1,h+1))) + GFX_exit(EXIT_FAILURE,"No more memory to create MENU save under\n"); + + blit(screen,under,x,y,0,0,w+1,h+1); + + /* Draw menu border and title + */ + Rect3D(x,y,w,h,FALSE,BEVEL); + text_mode(-1); + textout_centre(screen,font,title,cx,y+BEVEL*2,ACOL(GUI_TEXTBOLD)); + + /* Draw menu items + */ + by=y+BEVEL*2+GFX_fh()+4; + + for(f=0;f>8) + { + case KEY_ESC: + quit=TRUE; + break; + + case KEY_ENTER: + done=TRUE; + break; + + case KEY_DOWN: + show_mouse(NULL); + DrawMenuItem(&box[cur],menu[cur].text,FALSE); + + cur=(cur+1)%no; + + DrawMenuItem(&box[cur],menu[cur].text,TRUE); + show_mouse(screen); + break; + + case KEY_UP: + show_mouse(NULL); + DrawMenuItem(&box[cur],menu[cur].text,FALSE); + + if (cur) + cur--; + else + cur=no-1; + + DrawMenuItem(&box[cur],menu[cur].text,TRUE); + show_mouse(screen); + break; + } + else + if ((lx!=mouse_x)||(ly!=mouse_y)) + { + int new; + + lx=mouse_x; + ly=mouse_y; + + new=MouseInBox(box,no); + + if ((new!=-1)&&(new!=cur)) + { + show_mouse(NULL); + DrawMenuItem(&box[cur],menu[cur].text,FALSE); + cur=new; + DrawMenuItem(&box[cur],menu[cur].text,TRUE); + show_mouse(screen); + } + } + } + + show_mouse(NULL); + blit(under,screen,0,0,x,y,w+1,h+1); + show_mouse(screen); + destroy_bitmap(under); + Release(box); + + if (!quit) + no=menu[cur].client_index; + else + no=defval; + + return(no); +} + + +char *GUI_fsel(char *title, char *default_path, char *filter) +{ + char path[PATH_MAX+1]; + + if ((filter)&&(*filter=='.')) + filter++; + + strcpy(path,default_path); + + GFX_bounce(); + if (my_file_select(title,path,filter)) + return(Strdup(path)); + + return(NULL); +} + + +int GUI_picklist(char *title,char *opt[]) +{ + extern void GFX_FORCE_REDRAW(void); + int ml; + int ret; + + pick_no=0; + + ml=gui_strlen(title); + + while(opt[pick_no]) + { + if (gui_strlen(opt[pick_no])>ml) + ml=gui_strlen(opt[pick_no]); + pick_no++; + } + + pick_data=opt; + + init_picklist_dialog(title,ml); + + GFX_bounce(); + ret=do_dialog(picklist,-1); + GFX_FORCE_REDRAW(); + + if (ret==-1) + return(-1); + + return(picklist[IPL_PICKLIST].d1); +} + + +int GUI_client_picklist(char *title,PLAT_PICKLIST opt[],int defval) +{ + extern void GFX_FORCE_REDRAW(void); + int ml; + int ret; + char **c_opt; + int f; + + pick_no=0; + + ml=gui_strlen(title); + + while(opt[pick_no].text) + { + if (gui_strlen(opt[pick_no].text)>ml) + ml=gui_strlen(opt[pick_no].text); + pick_no++; + } + + c_opt=Grab(sizeof(char *)*(pick_no+1)); + + for(f=0;fml) + ml=l; + + h+=GFX_fh()*4; + ml+=GFX_fw()*4; + x=SCRW/2-ml/2; + y=SCRH/2-h/2; + + /* Surrounding box + */ + d[0].proc=d_3d_box; + d[0].x=x; + d[0].y=y; + d[0].w=ml; + d[0].h=h; + d[0].fg=ACOL(GUI_TEXT); + d[0].bg=ACOL(GUI_MID); + d[0].key=0; + d[0].flags=0; + d[0].d1=d[0].d2=0; + d[0].dp=d[0].dp2=d[0].dp3=NULL; + + /* Title + */ + d[1].proc=d_ctext_proc; + d[1].x=SCRW/2; + d[1].w=ml-20; + d[1].y=y+10; + d[1].h=10; + d[1].fg=ACOL(GUI_TEXTBOLD); + d[1].bg=ACOL(GUI_MID); + d[1].key=0; + d[1].flags=0; + d[1].d1=d[1].d2=0; + d[1].dp=title; + d[1].dp2=d[1].dp3=NULL; + + /* OK + */ + d[2].proc=my_d_button_proc; + d[2].x=x+10; + d[2].y=y+h-15; + d[2].w=(ml/2)-20; + d[2].h=10+BEVEL; + d[2].fg=ACOL(GUI_TEXT); + d[2].bg=ACOL(GUI_MID); + d[2].key=0; + d[2].flags=D_EXIT; + d[2].d1=d[2].d2=0; + d[2].dp="OK"; + d[2].dp2=d[2].dp3=NULL; + + /* CANCEL + */ + d[3].proc=my_d_button_proc; + d[3].x=SCRW/2+10; + d[3].y=y+h-15; + d[3].w=(ml/2)-20; + d[3].h=10+BEVEL; + d[3].fg=ACOL(GUI_TEXT); + d[3].bg=ACOL(GUI_MID); + d[3].key=0; + d[3].flags=D_EXIT; + d[3].d1=d[3].d2=0; + d[3].dp="Cancel"; + d[3].dp2=d[3].dp3=NULL; + + /* Buttons + */ + for(f=0;fml) + ml=l; + + h+=GFX_fh()*4; + ml+=GFX_fw()*4; + x=SCRW/2-ml/2; + y=SCRH/2-h/2; + + /* Surrounding box + */ + d[0].proc=d_3d_box; + d[0].x=x; + d[0].y=y; + d[0].w=ml; + d[0].h=h; + d[0].fg=ACOL(GUI_TEXT); + d[0].bg=ACOL(GUI_MID); + d[0].key=0; + d[0].flags=0; + d[0].d1=d[0].d2=0; + d[0].dp=d[0].dp2=d[0].dp3=NULL; + + /* Title + */ + d[1].proc=d_ctext_proc; + d[1].x=SCRW/2; + d[1].w=ml-20; + d[1].y=y+10; + d[1].h=10; + d[1].fg=ACOL(GUI_TEXTBOLD); + d[1].bg=ACOL(GUI_MID); + d[1].key=0; + d[1].flags=0; + d[1].d1=d[1].d2=0; + d[1].dp=title; + d[1].dp2=d[1].dp3=NULL; + + /* OK + */ + d[2].proc=my_d_button_proc; + d[2].x=x+10; + d[2].y=y+h-15; + d[2].w=(ml/2)-20; + d[2].h=10+BEVEL; + d[2].fg=ACOL(GUI_TEXT); + d[2].bg=ACOL(GUI_MID); + d[2].key=0; + d[2].flags=D_EXIT; + d[2].d1=d[2].d2=0; + d[2].dp="OK"; + d[2].dp2=d[2].dp3=NULL; + + /* CANCEL + */ + d[3].proc=my_d_button_proc; + d[3].x=SCRW/2+10; + d[3].y=y+h-15; + d[3].w=(ml/2)-20; + d[3].h=10+BEVEL; + d[3].fg=ACOL(GUI_TEXT); + d[3].bg=ACOL(GUI_MID); + d[3].key=0; + d[3].flags=D_EXIT; + d[3].d1=d[3].d2=0; + d[3].dp="Cancel"; + d[3].dp2=d[3].dp3=NULL; + + /* Buttons + */ + for(f=0;fml)) + ml=l; + + ml+=text_length(font," ")*(DIALOG_STRLEN+3); + + h+=GFX_fh()*5; + x=SCRW/2-ml/2; + y=SCRH/2-h/2; + + /* Surrounding box + */ + d[0].proc=d_3d_box; + d[0].x=x; + d[0].y=y; + d[0].w=ml; + d[0].h=h; + d[0].fg=ACOL(GUI_TEXT); + d[0].bg=ACOL(GUI_MID); + d[0].key=0; + d[0].flags=0; + d[0].d1=d[0].d2=0; + d[0].dp=d[0].dp2=d[0].dp3=NULL; + + /* Title + */ + d[1].proc=d_ctext_proc; + d[1].x=SCRW/2; + d[1].w=ml-20; + d[1].y=y+3; + d[1].h=10; + d[1].fg=ACOL(GUI_TEXTBOLD); + d[1].bg=ACOL(GUI_MID); + d[1].key=0; + d[1].flags=0; + d[1].d1=d[1].d2=0; + d[1].dp=title; + d[1].dp2=d[1].dp3=NULL; + + /* OK + */ + d[2].proc=my_d_button_proc; + d[2].x=x+10; + d[2].w=(ml/2)-20; + d[2].h=GFX_fh()+3+BEVEL; + d[2].y=y+h-d[2].h-5-BEVEL; + d[2].fg=ACOL(GUI_TEXT); + d[2].bg=ACOL(GUI_MID); + d[2].key=0; + d[2].flags=D_EXIT; + d[2].d1=d[2].d2=0; + d[2].dp="OK"; + d[2].dp2=d[2].dp3=NULL; + + /* CANCEL + */ + d[3].proc=my_d_button_proc; + d[3].x=SCRW/2+10; + d[3].y=d[2].y; + d[3].w=(ml/2)-20; + d[3].h=d[2].h; + d[3].fg=ACOL(GUI_TEXT); + d[3].bg=ACOL(GUI_MID); + d[3].key=0; + d[3].flags=D_EXIT; + d[3].d1=d[3].d2=0; + d[3].dp="Cancel"; + d[3].dp2=d[3].dp3=NULL; + + /* Labels and text entries + */ + for(f=0;f +#include +#include + +int RunCommand(char *argv[], char *path) +{ + char cmd[PATH_MAX*2]; + int ret; + int f; + + tmpnam(path); + + f=0; + cmd[0]=0; + while(argv[f]) + { + strcat(cmd,argv[f]); + strcat(cmd," "); + f++; + } + + strcat(cmd,">> "); + strcat(cmd,path); + + ret=system(cmd); + + /* Assume that non-zero is error + */ + return(ret==0); +} + + +/* END OF FILE */ diff --git a/djgpp/vstring.c b/djgpp/vstring.c new file mode 100644 index 0000000..2cc5ee4 --- /dev/null +++ b/djgpp/vstring.c @@ -0,0 +1,42 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides portable versions of necessary string routines + +*/ +static const char rcs_id[]="$Id$"; + +#include + + +int StrCaseCmp(char *a, char *b) +{ + return(strcasecmp(a,b)); +} + +int StrNCaseCmp(char *a, char *b, int n) +{ + return(strncasecmp(a,b,n)); +} + + +/* END OF FILE */ diff --git a/doc/bugs.htm b/doc/bugs.htm new file mode 100644 index 0000000..40dcfc0 --- /dev/null +++ b/doc/bugs.htm @@ -0,0 +1,40 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

Bugs

+ +

If you find any additional bugs please try and send as much +information (including a surefire way of repeating the problem if +possible) here. +Include the VERSION file from the distribution with your message. +If the problem is more likely to be platform specific (e.g. a bug +in the screen or file handling) please contact the following +people:

+ + + + + + +
DJGPP/DOSianc@noddybox.demon.co.uk
+ Note: messages with any sort + of attachment will not be accepted.
+ +

 

+ +
+ +

Back to index

+ +

$Id: bugs.htm,v 1.4 2000/07/18 16:49:48 dosuser Exp dosuser $

+ + diff --git a/doc/building.htm b/doc/building.htm new file mode 100644 index 0000000..5dd09b0 --- /dev/null +++ b/doc/building.htm @@ -0,0 +1,90 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

Building

+ +

This part of the documentation simply expands slighty +on the contents of the README in the source distribution.

+ +
+ +

Notes

+ +

Note that the viDOOM makefile expects the include +command to be honoured.

+ +
+ +

Instructions

+ +

Step 1

+ +

Edit the makefile.

+ +

Step 2

+ +

Change the following line to the name of your platform:

+ +
+

MAKEPLAT=djgpp

+
+ +

The following platforms are currently supported:

+ +
+

DJGPP - Protected-mode 32-bit MSDOS + (Windows 9x / MSDOS + DPMI)

+
+ +

Step 3

+ +

If you are going to use the install script, then update the +following line:

+ +
+

INSTALLDIR=C:/viDOOM

+
+ +

so it points to the directory where you wish it to be +installed.

+ +

Step 4

+ +

Set the MKDS to the directory seperator for this platform. +This is used so that the makefile can safely access +subdirectories:

+ +
+

MKDS=/

+
+ +

Step 5

+ +

If you wish to build the debug version remove the comment +(hash character - #) from the start of the following line:

+ +
+

DEBUG=-DDEBUG

+
+ +

Step 6

+ +

To make viDOOM simply invoke the make program for your system. +To install viDOOM invoke the make program for your system, +telling it to build the rule install.

+ +
+ +

Back to the index

+ +

$Id: building.htm,v 1.4 2000/07/28 15:29:15 dosuser Exp dosuser $

+ + diff --git a/doc/ed_ex1.png b/doc/ed_ex1.png new file mode 100644 index 0000000..503fdbc Binary files /dev/null and b/doc/ed_ex1.png differ diff --git a/doc/ed_ex2.png b/doc/ed_ex2.png new file mode 100644 index 0000000..8e4986d Binary files /dev/null and b/doc/ed_ex2.png differ diff --git a/doc/ed_ex3.png b/doc/ed_ex3.png new file mode 100644 index 0000000..aee4bc6 Binary files /dev/null and b/doc/ed_ex3.png differ diff --git a/doc/ed_line.png b/doc/ed_line.png new file mode 100644 index 0000000..a4aa32a Binary files /dev/null and b/doc/ed_line.png differ diff --git a/doc/ed_lninf.png b/doc/ed_lninf.png new file mode 100644 index 0000000..46cbc8a Binary files /dev/null and b/doc/ed_lninf.png differ diff --git a/doc/ed_merge.png b/doc/ed_merge.png new file mode 100644 index 0000000..f08707a Binary files /dev/null and b/doc/ed_merge.png differ diff --git a/doc/ed_multi.png b/doc/ed_multi.png new file mode 100644 index 0000000..a1bbf59 Binary files /dev/null and b/doc/ed_multi.png differ diff --git a/doc/ed_sect.png b/doc/ed_sect.png new file mode 100644 index 0000000..3bd3fad Binary files /dev/null and b/doc/ed_sect.png differ diff --git a/doc/ed_step.png b/doc/ed_step.png new file mode 100644 index 0000000..ab4140f Binary files /dev/null and b/doc/ed_step.png differ diff --git a/doc/ed_thing.png b/doc/ed_thing.png new file mode 100644 index 0000000..d063772 Binary files /dev/null and b/doc/ed_thing.png differ diff --git a/doc/ed_vert.png b/doc/ed_vert.png new file mode 100644 index 0000000..5ab35dc Binary files /dev/null and b/doc/ed_vert.png differ diff --git a/doc/editing.htm b/doc/editing.htm new file mode 100644 index 0000000..3805271 --- /dev/null +++ b/doc/editing.htm @@ -0,0 +1,1261 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

Editing

+ +

Index

+ +

This page is split up into the following +sections:

+ + + +
+ +

The Basics

+ +

Once you start editing in viDOOM you should be +greeted by a screen similar to the following (no prizes for +guessing the map number):

+ +

+ +

At the top of the screen is a title bar which shows the +following information, going from left to right:

+ +
    +
  • The edit mode. This is either 'Sector', 'Linedef', + 'Thing' or 'Vertex'.
  • +
  • The position of the mouse pointer in the map.
  • +
  • The current scale
  • +
  • Whether movements are locked to the current grid scale.
  • +
  • The grid scale. The first number indicate the grid scale + that objects are snapped to. The second number indicates + how big the graphical grid displayed is (the blue lines + in the picture above). This second number changes + automatically as the display is zoomed in and out.
  • +
  • Below this is a line where specific edit modes can show + extra information.
  • +
+ +

The main central part of the screen is made up the map being +edited.

+ +

At the bottom (and sometimes the middle right) of the screen +are information boxes that display details of the object the +mouse pointer is currently over. The size and information in +these boxes changes with the edit mode.

+ +
+ +

Basic Mouse Operation

+ +

The mouse acts in exactly the same way, independent of the +mode. Simply left click over an object to select it. If the +control key is pressed while selecting the object the object is +selected in addition to any others currently selected.

+ +

If the shift key is pressed then while the left button is held +down a selection rectangle can be dragged out. Any objects within +this box once the button is released will be selected (DOOM map +designers note - in this instance objects are selected in order +from the lowest numbered object up). If the control key is +pressed along with the shift key then the objects in the box are +selected in addition to any others currently selected.

+ +

On pressing the right button a pop-up menu is displayed. If no +objects are currently selected then the menu just has the insert +option. If objects are selected when pressing the right mouse +button (please see the overview +to see how the right button can also be made to select objects +the pointer is currently over) then a menu is shown with options +specific to each edit mode.

+ +

If the left mouse button is pressed without the control key +and the pointer is not over any object then the current selection +is cleared.

+ +

If the mouse has a middle button then this can be used to move +objects once they have been selected. This basically a short cut +for pressing the right button then selecting the 'Move' option.

+ +
+ +

General Key Commands

+ +

There are a number of key commands that are common to all edit +modes in viDOOM. These are as follows:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
F1General Help (key commands and mouse + usage).
F2Help specific to the current edit mode
EscapeFinish Editting
Cursor KeysMove the map display
Shift + Cursor KeysMove the map display quickly
Page Up/DownZoom in/out
Q/WAlert the grid lock scale
GSwitch grid lines on/off
XSwith grid snapping on/off
Tab/Shift TabGoto next/previous edit mode
VVERTEX edit mode
LLINEDEF edit + mode
SSECTOR edit mode
TTHING edit mode
CMULTI edit mode
F9Deselect all objects
Shift + F9Invert current selection
F10Select all objects
Shift + F10Select all objects with a specific type + (not applicable to VERTEX objects).
F11/Shift + F11Locate the next or previous selected + object and display it in the centre of the screen.
DeleteDelete the selected objects Note + 1
InsertInsert a new object
F3Merge a map. See the map mergeing section for details.
F4Move selected objects
F5Rotate selected objects Note 2
[Rotate selected objects 5° to the left Note + 2
]Rotate selected objects 5° to the right + Note 2
F6Scale selected objects Note 2
{Scale selected objects by 90% Note + 2
}Scale selected objects by 110% Note + 2
F7Set tag number for this object (only + applicable to SECTOR and LINEDEF objects).
Shift + F7Select objects with a specific tag + number (only applicable to SECTOR and LINEDEF objects).
F8Locate a certain object and display in + the centre of the screen
Shift + F8Locate a certain object, display in the + centre of the screen and select it.
RRedraw the map display. Handy for + refreshing selected objects in SECTOR mode.
+ +

Note 1: Iin viDOOM it is not permissable to +delete objects that are still in use by other objects, i.e. it is +impossible to delete a vertex that is still used as one of the +anchor points for a linedef - the linedef must be deleted first.

+ +

Note 2: When scaleing or rotating multiple +objects the objects are rotated/scaled around the centre of the +imaginary box enclosing all the selected objects. Also grid +locking is not honoured in this mode.

+ +
+ +

Sector Edit Mode

+ +

For a basic description of a SECTOR see the glossary.

+ +

Display in Sector Mode

+ +

When in sector mode the display will look like this:

+ +

+ +

When in this mode sectors are drawn in red, vertexes are not +shown and things are drawn as a cross just to indicate their +position.

+ +

At the bottom of the sceen is a box which shows the details of +the sector the pointer is currently over.

+ +

Also note that if the tag highlighting mode is enabled any +linedefs that have a tag number matching the one for the sector +the pointer is over will be drawn in white. Note that the +highlighted linedef will not appear if is in a sector that's +selected and highlighted.

+ +

Extra Keys in Sector Mode

+ +

The following extra keys can be used while in sector mode. +Keys that work on selected sectors will temporarily select the +sector the pointer is over if no sectors are selected.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HToggle the tag highlighting mode on an off. See the display section for an example + of what this does.
MChange sector move mode. See overview for details.
, (comma)Decrease selected sectors floor height + by 8
. (period)Increase selected sectors floor height + by 8
<Decrease selected sectors ceiling height + by 8
>Increase selected sectors ceiling height + by 8
-Decrease selected sectors lighting level + by 16
+Increase selected sectors lighting level + by 16
+ +

Sector Insertion

+ +

When you insert a sector a popup menu is displayed where you +can select a type of sector to create.

+ + + + + + + + + + +
Create unbound sectorThis will create a sector that is + unbound to any linedefs/sidedefs. It will have a normal + type as defined in the config file, a tag + of zero and a floor height, ceiling height and light + level as defined in the config file. + The floor and ceiling flats will be set to the empty texture name. + After it's creation the sector number will be displayed + onscreen.

Note that no further editing of the sector + can take place until some sidedefs/linedefs have been + manually bound to the sector, as the sector cannot be + visibily selected until they have.

+
Create polygonOn selecting this you will be asked for + the number of sides to the polygon (3-64). After entering + this a cross hair will be displayed. Press the left mouse + button when the cross hair is over the point where you + want the centre of the sector. Then the sector will be + drawn and you can drag it into shape (defining it's size + and rotation) using the mouse. Note that when defining + the centre and size/rotation that grid snapping can be + toggled on/off and the usual zoom in/out and map + positioning cursor keys are active.

You will be asked + then for the following information:

+
    +
  • A class + and type + of linedef (e.g. scrolling walls, normal, + switches) out of those defined in the config + file.
  • +
  • The new sectors floor height, ceiling height and + light level. If the sector is being defined + inside another sector that sectors floor, ceiling + and light level will already be in the dialog + when it appears. Otherwise the default + values will be used.
  • +
  • A further linedef type that defines the linedef's + flags, as defined in the config file.
  • +
  • The style in which the sector should be painted + as defined in the config file.
  • +
  • If the sector is being defined within another + sector you will be asked if you wish make the + right sidedef point outwards from the new sector.
  • +
+
+ +

Sector Deletion

+ +

It is not possible to directly delete a sector in viDOOM as it +religiously enforces the fact that objects cannot be deleted if +other objects are still bound to them. And once all the linedefs +bound to a sector have been deleted, the sector is no longer +selectable! However, when saving, any sectors that have no +bounding linedefs will be automatically deleted.

+ +

Sector Popup Menu

+ +

On selecting sectors and pressing the right mouse button to +get the sector popup menu the following options will be +presented:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Change floor heightChange the height of the floor of the + selected sectors.
Change ceiling heightChange the height of the ceiling of the + selected sectors.
Change light levelAlter the light level of the sectors.
Change tagAlter the tag value of the sectors.
Change floorShows a picklist of the flats from which + the floor texture can be selected.
Change ceilingShows a picklist of the flats from which + the ceiling texture can be selected.
Change typeChanges the sector type. The classes and their sector types are + defined in the config file.
Paint sector in stylePaints the sector using the textures + described as being a style in the config file.
MoveMove the selected sectors.
DeleteDelete the selected sectors. This just + always shows a reminder that empty sectors will be + deleted when the map is saved.
+ +
+ +

Linedef Edit Mode

+ +

For a basic description of a LINEDEF see the glossary.

+ +

Display in Linedef Mode

+ +

When in linedef mode the display will look like this:

+ +

+ +

When in this mode lindefs are just drawn as grey lines with a +normal indicating which side is the 'right' side of the linedef. +Vertexes are not shown and things are drawn as a cross just to +indicate their position..

+ +

At the bottom of the sceen are three boxes which shows the +details of the linedef the pointer is currently over, and any +associated right and left sidedef. Note that in the screenshot +above the type of linedef is show as the hex number and the class of linedef. This +can be altered in the config file so +that the linedef type is show as as it's hex number and the name +defined for the linedef type +in the config file if you are using a display with an higher +resolution. An example of the alterative info for the same +linedef is shown below.

+ +

+ +

Also note this if the tag highlight mode is on then if the +linedef the pointer is over has a non-zero tag number any sectors +with the same tag number are highlighted in white. E.g. in the +display above the pointer is over a linedef set to teleport, the +tag indicating which sector the teleported object will arrive in. +The sector above and to the right of the line has this tag and is +highlighted. Note that only linedefs not already selected in the +highlighted sector will be highlighted.

+ +

Extra Keys in Linedef Mode

+ +

The following extra keys can be used while in linedef mode.

+ + + + + + + + + + +
HToggle the tag highlighting mode on an + off. See the display + section for an example of what this does.
F12Check the currently selected linedefs. + It checks and prompts for the following things:
    +
  • Removal of lower textures on 1-sided linedefs.
    + This check can be disabled in the config + file.
  • +
  • Removal of upper textures on 1-sided linedefs.
    + This check can be disabled in the config + file.
  • +
  • Addition of missing middle textures on 1-sided + linedefs.
    + This check can be disabled in the config + file.
  • +
  • Removal of all textures on 2-sided linedefs where + both sides of the linedef are in the same sector.
    + This check can be disabled in the config + file.
  • +
  • Removal of middle textures on 2-sided linedefs.
    + This check can be disabled in the config + file.
  • +
  • Addition of lower textures on 2-sided linedefs + where the floor heights are different on either + side. In this test the lower texture will be + removed if the floor heights are not different.
    + This check can be disabled in the config + file.
  • +
  • Addition of upper textures on 2-sided linedefs + where the ceiling heights are different on either + side. In this test the upper texture will be + removed if the ceiling heights are not different.
    + This check can be disabled in the config + file.
  • +
+

Note that whenever textures are to be added viDOOM + will display the picklist to request what texture to + paint, unless the LINEDEF_CHECK_DEFAULT section in the config file + is set up.

+

Important Note: That it may not be + advisable to use this on all linedefs if there are lots + of lifts in the level. viDOOM (due to wanting to remain + completely config file driven for types) is unable to + realise that some textures that look like they shouldn't + be there will come into play when the lift is activated. + This may be changed in the future so that sidedefs that + are pointing into a sector tagged to a linedef of a + specified class are not checked.

+
+ +

Linedef Insertion

+ +

When inserting a new linedef you will be asked for 2 vertcies +to link together. You will then be asked for the linedef type +(from the list defined in the config file) and the +middle texture for it. Note that the linedef is created bound to +sector zero. This must be manually changed if it is wrong.

+ +

Linedef Deletion

+ +

Linedefs can be safely deleted from the map at any time.

+ +

Linedef Popup Menu

+ +

On selecting things and pressing the right mouse button to get +the thing popup menu the following options will be presented:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Change linedef flagsAllows the flags of the selected + linedefs to be changed. On selecting this a dialog will + appear allowing any of flags (as defined by the config file) to to + toggled on or off.
Change linedef typeChange the type of the selected + linedefs. On selecting this a list will appear so a class + of linedef can be selected (classes are defined in the config file). + Once the class has been selected the a picklist will + appear from which a type of linedef from that class can + be selected. The types are also defined in the config file.
Swap sidesSwaps the sides of the linedef, so that + the linedef points in the other directions. Note that the + sidedefs are re-arranged so that the textureing and + sector numbers on the sides of the linedef are not + switched.
Split lineSplits the selected linedefs in the + middle.
Select trail from this + linedefSelects a trail from the last selected + linedef, staying within the same sector as the one on the + linedefs right sidedef, until the starting point is found + again or there are no more linedefs in the same + direction.

Note that this behaves differently if the + starting point is a 2-sided line wholly within one sector + - only 2-sided linedefs wholly within the sector too + connected from this one are selected.

+
Join linedefs with stepsAllows two selected linedefs to be + joined with steps. See the Stair + creation section for details.
Right SidedefThis will display a sub menu for operation for the + right sidedef. See the Sidedef + menu for details.
Left SidedefThis will display a sub menu for operation for the + left sidedef. See the Sidedef + menu for details.
Change tagChange the tag number for the selected + linedefs.
MoveMove the selected linedefs.
DeleteDelete the selected linedefs.
+ +

Sidedef Menu

+ +

On selecting the Right sidedef or Left +sidedef options above the following options can be +chosen.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Change upper textureAlter the upper texture on the selected + sidedef.
Change middle textureAlter the middle texture on the selected + sidedef.
Change lower textureAlter the lower texture on the selected + sidedef.
Change texture offsetSets the texture offset for the selected + sidedef.
Adjust texture offsetAdjusts the texture offset for the + selected sidedefs. ie. Entering '10' for X and '-10' for + Y will add 10 to all the X offsets and subtract 10 from + all the Y offsets.
Change sectorAlters the sector number the sidedef is + linked with.
Align texturesAligns the linedefs textures in the + selected sidedef. Note that when doing this the widest + texture out of the upper, middle and lower textures are + used to calculate the offsets. Also note that the + linedefs are aligned in the order they were selected, so + ensure you selected them in the order they appear.

Remember + that if doing the same set of linedefs then the order + should be reversed when doing the left sidedef over the + right sidedef.

+
+ +

Stair creation

+ +

This joins the two selected linedefs with steps. Before +starting this option a couple of caveats should be noted:

+ +
    +
  • Lines must be non-zero in length and not share any + vertices.
  • +
  • viDOOM assumes that the steps join up the left sidedef of + the linedefs together. This will generally be the case + anyway, and if it isn't remember to Swap sides + on the linedefs as required before starting (the sides + can be swapped back once the steps have been defined).
  • +
  • If the linedefs already have a left sidedef, this will be + deleted in preference for the new one facing onto the new + sectors.
  • +
  • Not too much error checking goes on. If you do define the + most bizarre looking steps you've never seen on an + automap before, there is a fair chance they won't work + when you play them.
  • +
  • If the steps pass through a sector, it must be the same + sector.
  • +
+ +

i.e. the following two examples are OK, L1 and L2 can be +joined with stairs:

+ +

+ +

+ +

But the following example, where stairs would cross both +sectors S3 and S4 is not allowed:

+ +

+ +

Having got the excuses over with we can now go onto the +process involved with creating the steps. On seleting this option +you will be presented with a display like the following:

+ +

+ +

As can be seen the steps have been drawn and their are a +couple of help boxes displayed. The box in the lower left of the +screen shows the following information:

+ +
    +
  • No of steps
  • +
  • The difference in floor height between each step
  • +
  • The difference in ceiling height between each step
  • +
  • The step drawing mode (Straight or Curve + mode).
  • +
  • Which side is being moved when in Curve + mode.
  • +
+ +

On the left is a box giving a quick help on the following +keys:

+ + + + + + + + + + + + + + + + + + + + + + +
+Increase the number of steps in the + staircase (maximum 128)
- Decrease the number of steps in the + staircase (minimum 1)
CChange between Straight + and Curve drawing mode. In straight mode + straight lines are drawn between the linked vertices on + the two linedefs. In curve mode a curve is defined + between the two points by moving the pointer.
SSwaps between the two walls when + defining the curve of the walls in curve + mode.
RSwap which vertices are paired up from + the two linedefs. For instance in the example above + switching the vertices would give the stairs a butterfly + shape rather than corrider seen above.
+ +

After moving the stairs to the position you want you can press +ESC to cancel the process or press a mouse button to lock the +stairs in position and carry on with the creation.

+ +

At this point you will be asked if the ceiling should also be +stepped. Selecting No means that the ceiling +will stay at a constant height (the highest ceiling height out of +the two linedef's sectors), otherwise the ceiling will be stepped +accordingly.

+ +

Now the steps are created. Note that in the created steps the +pegging modes defined for the sector style the stairs will be +painted in is ignored and pegging modes and Y texture offsets +will be set appropriately to line up textures on the sides of the +steps.

+ +
+ +

Thing Edit Mode

+ +

For a basic description of a THING see the glossary.

+ +

Display in Thing Mode

+ +

When in thing mode the display will look like this:

+ +

+ +

When in this mode lindefs are just drawn as grey lines, +vertexes are not shown and things are drawn as a circle +(indicating their size within the game - like the Spider +Mastermind above) with an arrow indicating their direction. Note +different classes of things are drawn in different colours (these +colour to class pairing are defined in the config file).

+ +

At the bottom of the sceen is a box which shows the details of +the thing the pointer is currently over.

+ +

Extra Keys in Thing Mode

+ +

There are no extra keys in thing edit mode.

+ +

Thing Insertion

+ +

When inserting a new thing into the map, the thing will be +inserted at the current pointer position using the values (type, +angle and flags) used when a thing was last edited. e.g.

+ +
    +
  • Insert a new thing.
  • +
  • Select the new thing and change it's type to be a + Cyberdemon (see the Popup Menu + for how to do this).
  • +
  • All newly inserted things will now be Cyberdemons, until + a further edit is made.
  • +
+ +

Thing Deletion

+ +

Things can be safely deleted from the map at any time.

+ +

Thing Popup Menu

+ +

On selecting things and pressing the right mouse button to get +the thing popup menu the following options will be presented:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Change typeChange the type of the selected things. + On selecting this a list will appear so a class of thing + can be selected (classes are defined in the config file). Once + the class has been selected the a picklist will appear + from which a type of thing from that class can be + selected. The types are also defined in the config file.
Change angleAllows the angle of the selected things + to be changed. On selecting this a dialog will appear + allowing any of 8 major compass points to be selected.
Change flagsAllows the flags of the selected things + to be changed. On selecting this a dialog will appear + allowing any of flags (as defined by the config file) to to + toggled on or off.
Snap selected thingsSnaps the selected things to the current + grid.
MoveMove the selected things. Follow the + on-screen prompts for details on how to move the things + or cancel the operation.
DeleteDelete the selected things.
+ +
+ +

Vertex Edit Mode

+ +

For a basic description of a VERTEX see the glossary.

+ +

Display in Vertex Mode

+ +

When in vertex mode the display will look like this:

+ +

+ +

When in this mode lindefs are drawn as grey arrows, the arrow +direction corresponding to direction of the linedef - i.e. the +right side of the linedef is on the right side of the arrow. +Vertices are displayed as white points with a grey selection box +around them.

+ +

At the bottom of the sceen is a box which shows the details of +the vertex the pointer is currently over.

+ +

Extra Keys in Vertex Mode

+ +

The following extra keys can be used while in linedef mode.

+ + + + + + +
F12Goes through all the vertices and delete + ones that are not bound to a linedef.
+ +

Vertex Insertion

+ +

Inserting a vertex simply inserts a new vertex unbound to any +linedefs at the pointer location.

+ +

Vertex Deletion

+ +

Vertices can only be deleted if they are not bound to any +linedefs. Linedefs must be deleted +before you can delete the vertex.

+ +

Vertex Popup Menu

+ +

On selecting vertices and pressing the right mouse button to +get the vertex popup menu the following options will be +presented:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Chain selected verticesSelecting this object will create + linedefs linking the currently selected vertices. Note + that the linedefs will be created such the the first + selected vertex is connected to the vertex selected, the + vertex selected second to the vertex selected third and + so on.

On selecting this option you will be first + prompted to selected a class and type of linedef + (e.g. scrolling walls, normal, switches) out of those + defined in the config file. Following this you will be + asked for a further linedef type that defines the + linedef's flags, as defined in the config file.

+

If the selected linedef type is one sided and the config file + options are set accordingly a middle texture for the + linedefs will be requested. After this you will be asked + if you wish to connect the last vertex to the first one + and the linedefs will be created and any textures aligned + on them.

+

Tip: One thing this option is very + useful for is creating pillars and the such like inside + sectors. Insert new vertexs (with the insert select + option in the config file enabled) in the shape you want + in an anti-clockwise direction. + Then select this option and a one-sided linedef type and + the result will be a column in the room.

+
Chain selected vertices + into a sectorSelecting this object will create + linedefs linking the currently selected vertices and bind + the linedefs to a newly created sector. Note that the + linedefs will be created such the the first selected + vertex is connected to the vertex selected, the vertex + selected second to the vertex selected third and so on. + It is important for this option to operate as described + below that the vertices are selected in a clockwise + direction.

You will be asked then for the following + information:

+
    +
  • A class + and type + of linedef (e.g. scrolling walls, normal, + switches) out of those defined in the config + file.
  • +
  • The new sectors floor height, ceiling height and + light level.
  • +
  • A further linedef type that defines the linedef's + flags, as defined in the config file.
  • +
  • The style in which the sector should be painted + as defined in the config file.
  • +
  • If the sector is being defined within another + sector you will be asked if you wish make the + right sidedef point outwards from the sector. + This is useful as things like teleport linedefs + only work if you cross from the right side to the + left side of the linedef. For this part to work + as described the vertices must have been selected + in a clockwiseorder.
  • +
+

Tip: If you select vertices that are + bound to linedefs in another sector, once the creation of + the sector has been completed viDOOM will ask you if you + want to merge the new linedef from the new sector with + the old one.

+
Merge selected verticesThe vertices selected second, third and + so on are deleted and all references to those vertices in + linedefs changed to the be the first selected vertex. + After doing this viDOOM will see if any linedefs are now + using the same vertex pair to define their position and + you can elect to merge these.
Snap selected verticesSnaps the selected vertices to the + current grid.
MoveMove the selected vertices. Follow the + on-screen prompts for details on how to move the vertices + or cancel the operation.
DeleteDelete the selected vertices.
+ +
+ +

Multi Edit Mode

+ +

Display

+ +

When in multi mode the display will look like this:

+ +

+ +

When in this mode lindefs are drawn as grey arrows, the arrow +direction corresponding to direction of the linedef - i.e. the +right side of the linedef is on the right side of the arrow. +Vertices are displayed as white points with a grey selection box +around them.

+ +

Things are drawn as a circle (indicating their size within the +game) with an arrow indicating their direction. Note different +classes of things are drawn in different colours (these colour to +class pairing are defined in the config file)

+ +

At the bottom of the sceen is a box which shows what object +type (vertex or thing) the pointer is currently over and it's +number.

+ +

 

+ +

Operation

+ +

Multi selection mode is given just as a way of manipulating +things and vertexes, allowing them to be moved, rotated and +scaled in unison. Note that linedefs and sectors are not +selectable as these are inherently moved just by moving the +vertices.

+ +

All keys are honoured in multi selection mode, but keys for +insertion and deletion are ignored. Also the locate object number +keys (F8 and Shift + F8) are ignored.

+ +
+ +

Mergeing Maps

+ +

Pressing F3 in any edit mode will allow a different map to be +merged in with the currently edited map.

+ +

First you will be asked if you wish to temporarily load a PWAD +and load the first map from it. If you select Yes +then you will be prompted for a PWAD file to read. If you select No +you will be asked for a level to load from the currently loaded +WADs.

+ +

Tip: The idea of this question is that you +can save PWAD files with a structure you wish to re-use in +multiple maps as the first map. Any linedefs in this map that +have a left sidedef bound to sector number -1 will have the +sector number reset to the sector in which the merged structure +has been placed. Note that if you do insert structures this way +it will generally be required to check the sidedefs to make sure +they have all their necessary textures and remember that the +strucutre will have it's original sector propertires (floor, +ceiling and light levels).

+ +

After choosing the map to merge in, a vector display +representing the linedefs from the map that can be moved around +the screen with the mouse is displayed as shown in the screen +below.

+ +

+ +

On the bottom left is a box giving a quick help on the +following keys:

+ + + + + + + + + + + + + + + + + + +
, (comma)Rotate the map 1° to the left.
. (period)Rotate the map 1° to the right.
<Rotate the map 10° to the left.
>Rotate the map 10° to the right.
+ +

Pressing ESC will cancel the operation while pressing a mouse +button will place the map where it currently is.

+ +

If the merged map is assumed to be a structure (i.e. it has +left sidedefs whose sector fields are set to -1) you are then +asked whether you wish to adjust the floor heights. If you do +select to adjust them then the sector that is in the middle of +the merged in WAD has it's floor height taken. The floors and +ceilings are adjusted in the new sectors so that the lowest floor +is at the same height as the surrounding floor, but the +difference in heights between the new sectors themselves are +maintained. After this you are asked whether to adjust the +ceiling heights. If you do the ceiling height of the same sector +is taken and the new sector's ceilings adjusted to match the +surrounding ceiling (note that ceilings will not be moved if +moving them places them lower than the floor).

+ +

You will then be asked whether tags within the map should stay +as they are or be adjusted so that they are different from tags +used in the map being edited. After this the map will be inserted +and then a notice displayed showing by how much the various +objects in the merged map where adjusted.

+ +
+ +

Back to index

+ +

$Id: editing.htm,v 1.8 2000/07/27 16:56:05 dosuser Exp dosuser $

+ + diff --git a/doc/glossary.htm b/doc/glossary.htm new file mode 100644 index 0000000..ef5912a --- /dev/null +++ b/doc/glossary.htm @@ -0,0 +1,127 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

Glossary

+ +

It is assumed that some knowledge of DOOM is known by the +reader, but in case here are some general terms that are used in +the documentation.

+ +

WAD

+ +

A WAD file is the name given to the files used to define the +graphics, sound, music and maps that make up a game of DOOM. WAD +files are split into two different types, IWAD +and PWAD files.

+ +

IWAD

+ +

An IWAD file is is the 'Internal WAD' file. The IWAD file is +the main WAD file as supplied by id Software. +Note that only id Software are meant to produce IWAD files.

+ +

PWAD

+ +

An PWAD file is is the 'Patch WAD' file. This WAD file is read +in by the game after the IWAD file, and an entries in it replace +entries defined in the IWAD file. So for instance a PWAD file +that has an entry for the first MAP will mean +that DOOM will read the first map from the PWAD file, rather than +it's own IWAD file.

+ +

Hmmmm.... Sure I could have explained that better.

+ +

MAP

+ +

A map is taken to mean a DOOM level. Note there is two naming +conventions for maps, ExMy +(where x is the episode number, and y the map +number in that episode) used in DOOM and Ultimate DOOM, and MAPnn +(where nn is a number between 01 and 32) used in DOOM 2 +and Final Doom.

+ +

A map is made up of a number of different elements, namely sectors, linedefs, sidedefs, things and vertexes. Following are some (very) basic +definitions for these things, but you would be better reading the +Unofficial DOOM specs for more +accurate definitions.

+ +

MAPs generated in viDOOM must be built with a Node +Builder before they can be used in DOOM.

+ +

VERTEX

+ +

A vertex is simply an X,Y co-ordinate in the DOOM world.

+ +

THING

+ +

Things are all the different objects on the DOOM map that are +not the actual walls and doors. All the monsters, weapons, ammo, +non-wall based scenery and even your starting point and teleport +locations are all counted as THINGS in DOOM.

+ +

LINEDEF

+ +

A LINEDEF is a line that connects two vertexes. +A LINEDEF at it's most basic is used to make up the walls that +make up the DOOM levels. A LINEDEF must always have a +right SIDEDEF associated with it. 2 sided +LINEDEFS will also have a left SIDEDEF associated with it.

+ +

In addition special types of LINEDEF can be used so that when +the player crosses or activates them actions happen in the DOOM +world - lighting changes, teleportation happens, doors open, +levels are exited and so on.

+ +

SIDEDEF

+ +

A SIDEDEF is basically used to describe the textures +that are painted upon a LINEDEF.

+ +

SECTOR

+ +

Though technically incorrect, it is simplest to picture a +SECTOR as an object enclosed by LINEDEFS. +A sector is used to define the floor and ceiling heights and flats used to draw the floor and ceiling, in +addition to the lighting for that area.

+ +

TEXTURE

+ +

A texture is the graphics used to paint the walls in DOOM.

+ +

FLAT

+ +

A flat is the graphics used to paint the floors and ceiling in +DOOM.

+ +

Node Builder

+ +

Does some of the nastier work of level building by creating +the extra information over and above the parts mentioned in MAPS so that DOOM can actually understand the +level data enough to play it.

+ +

BSP is perhaps the best known of +these, and the one that was used all through viDOOM's +development.

+ +

 

+ +
+ +

Back to index

+ +

$Id: glossary.htm,v 1.2 2000/07/18 16:49:48 dosuser Exp dosuser $

+ + diff --git a/doc/index.htm b/doc/index.htm new file mode 100644 index 0000000..477f32e --- /dev/null +++ b/doc/index.htm @@ -0,0 +1,45 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

viDOOM

+ +

"... but what I talk about is DOOM, +because in the end, DOOM is all that counts."
+The Dark Half - Stephen King

+ +

viDOOM is released as free software under the +GNU General License. See licence for +details.

+ +
+ +

Index

+ +
    +
  1. Acknowledgements and thanks
  2. +
  3. Simple glossary
  4. +
  5. Overview (Configuration, etc)
  6. +
  7. Main menu
  8. +
  9. Editing
  10. +
  11. Porting
  12. +
  13. Bug Reports
  14. +
  15. Building (only needs to be + read for the source distribution)
  16. +
+ +
+ +

viDOOM home +page

+ +

$Id: index.htm,v 1.6 2000/07/24 16:31:58 dosuser Exp dosuser $

+ + diff --git a/doc/license.htm b/doc/license.htm new file mode 100644 index 0000000..d07b0b8 --- /dev/null +++ b/doc/license.htm @@ -0,0 +1,362 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    
+    Copyright (C) 19yy  
+
+    This program 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.
+
+    This program is distributed in the hope that 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 this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  , 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+ + +
+ +

Back to index

+ +

$Id: license.htm,v 1.1 2000/07/13 15:05:48 dosuser Exp dosuser $

+ + diff --git a/doc/mainmenu.htm b/doc/mainmenu.htm new file mode 100644 index 0000000..0468a8a --- /dev/null +++ b/doc/mainmenu.htm @@ -0,0 +1,111 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

Main Menu

+ +

Depending on the setting in configuration +starting viDOOM you may be asked to pick the game type to edit. +Pick one of the games from the menu, or if the menu is cancelled +the default game type will +be used.

+ +

After this you will be presented with the main menu containing +the following options.

+ +

Edit The Current Level

+ +

Edit the current level. See editing +for details.

+ +

Load Level from open WADs

+ +

Selects a level to load from the open IWAD and PWAD files. +Note that the level is loaded from the most recent +WAD file opened that holds a map for the selected level. If you +already have a level open for editing and the Edit The +Current Level option has been used then confirmation +will be asked before allowing you to procede. This warning can be +disabled in the INI file (see overview).

+ +

Save Current Level

+ +

Saves the map you are currently editing into a PWAD file. This PWAD will only +contain the map, and nothing else. So if you have loaded the map +from a PWAD that contains any other information (e.g. music, +extra sounds, graphics patches) it is not a good idea to save +over the original PWAD file. If the saved PWAD filename matches a +PWAD that is already loaded, after saving the open PWAD will be +closed and then re-opened. This could be important to note as the +saved PWAD will now be at the top of the open PWADs.

+ +

Note that the saved map must be built with a node builder before it can be played +in DOOM if the node bulding +section in the config file has not been set up.

+ +

Important note: While saving viDOOM will +remove any deleted objects from the map, delete any sectors that +do no have linedefs attached to them and vertices that are not in +use. This is worth remembering as objects will be +renumbered if any have been deleted so that they fit together +contiguously after saving.

+ +

Create New Empty Level

+ +

Creates a completely empty level for editing. If you already +have a level open for editing and the Edit The Current +Level option has been used then confirmation will be +asked before allowing you to procede. This warning can be +disabled in the INI file (see overview).

+ +

Change Current Level Name

+ +

Allows the map to be assigned to a different map number. See +the glossary for some extra info +on map/level numbers.

+ +

Open PWAD file

+ +

Allows a PWAD file to be opened.

+ +

Close PWAD file

+ +

Closes one of the currently open PWAD files. Note that viDOOM +will not let you unload the IWAD +opened at startup.

+ +

Preview Level

+ +

Allows a level to be previewed without disturbing the level +currently being edited. Note that the preview is very +basic with linedefs shown as grey lines, vertexes as white pixels +and things as red blobs. While in the preview press F1 for help +on controlling the display.

+ +

About viDOOM

+ +

See who was responsible for this.

+ +

Quit

+ +

Exit viDOOM. If you have a level open for editing and the Edit +The Current Level option has been used then confirmation +will be asked before allowing you to procede. This warning can be +disabled in the INI file (see overview).

+ +
+ +

Back to index

+ +

$Id: mainmenu.htm,v 1.5 2000/07/19 16:39:26 dosuser Exp dosuser $

+ + diff --git a/doc/overview.htm b/doc/overview.htm new file mode 100644 index 0000000..f10576e --- /dev/null +++ b/doc/overview.htm @@ -0,0 +1,843 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

viDOOM Overview

+ +

Introduction

+ +

viDOOM is a Free Software DOOM editor. It supports the +following id produced +games:

+ +
    +
  • Doom
  • +
  • The Ultimate Doom
  • +
  • Doom 2 - Hell On Earth
  • +
  • Final Doom
  • +
+ +

Note that in accordance with id software's wishes you are only +allowed to generate edited levels for the game if you have a +full, registered version of the game.

+ +

viDOOM is fully configurable through config files, so it can +be expanded to accomadte the BOOM and ZDOOM extensions. Well, +once I've found out the slight difference in format of WAD file +that seems to accompany them too.

+ +
+ +

Why bother?

+ +

Good question. Anyone who has ever used them will know there +are a number of very good DOOM editors available (links to lots +of them can be found at Doomworld +and all good FTP servers).

+ +

However, I always felt a bit clumsy using them, and in true +hacker fashion I decided writing one I could use would be easier +then reading the instructions for the others. Hence viDOOM.

+ +

I reasonably like the way viDOOM works, so I release it on the +offchance other people may too.

+ +
+ +

Supported systems

+ +

As with most Free Software viDOOM is primarily distributed as +source code. The source is fairly ANSI C compliant, and therefore +the core of viDOOM should compile on all operating systems. The +current distribution includes the hardware dependent routines for +the following platforms:

+ +
    +
  • Protected-mode 32-bit MSDOS (Windows 9x / MSDOS + DPMI)
  • +
+ +
+ +

Initialisation Files

+ +

VIDOOM.INI

+ +

On starting viDOOM will look for a file in the current +directory called vidoom.ini. This file tells +viDOOM what version of DOOM it is expected to be editing, the +configuration for that version of DOOM and the editor +configuration. The general format of the INI file is:

+ +

[Section]
+identifier=value
+

+ +

Blank lines and lines starting with a comment character (#) +are ignored. The following sections and identifiers are explained +below.

+ + + +

After reading VIDOOM.INI, then a defined config file is also read.

+ +
+ +

[Game]

+ +

Controls for the version of DOOM

+ + + + + + + + + + +
gameUse this to say which version of DOOM + you will be editing. The following values are allowed:
    +
  • Doom
  • +
  • Ultimate Doom
  • +
  • Doom 2
  • +
  • TNT: Evilution
  • +
  • Plutonia Experiment
  • +
  • ZDoom
  • +
+
askIf set to yes then on starting + viDOOM will ask for the game type to edit.
+ +
+ +

[Editor]

+ +

Global editor configuraiton

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ask_middle_on_2sidedWhen creating a new sector and the + sector has a two-sided boundary asks whether a middle + texture should be asked for. Allowable values yes + and no
auto_block_linedefsWhen linedef flags are altered and this + is set to yes, linedefs that were + 2-sided and are now 1-sided have the impassible flags + automatically set.
+ Likewise linedefs that were 1-sided and are now 2-sided + have the impassible flag automatically cleared.
+ If set to no no action is taken when these events + happen.
brightDescribes a gamma value applied to any + textures, flats and sprites read in from the DOOM WAD + files. Allowable values are any floating point number.
clear_on_menuIf set to yes then once + the pop-up menu has been used to modify the selected + objects they are automatically unselected.
clear_on_moveIf set to yes then once + the selected objects have been moved they are + automatically unselected.
default_light_level
+
default_floor_height
+
default_ceiling_height
Describes the default light, floor and + ceiling height for created sectors. Note that if a sector + is created within another sector, the values for that + sector, rather than these defaults, are used.
default_edit_modeDefines the default edit mode when + loading a new map into the editor. Possible values are: +
default_scaleThe starting scale used in the editor.
gridUse this to say whether the grid will be + shown on screen while editing. Allowable values are yes + and no.
grid_lockUse this to say whether inserted and + moved object in the editor will be snapped on a grid. + Allowable values are yes and no. +
grid_sizeDescribes the size of the grid used by + the above items. Allowable values are integer values + greater than two.
hover_selectWhen editing object in a DOOM level this + alters the way that viDOOM works if the right mouse + button is used over an unselected object. The allowable + values, and their affects are:
    +
  • none - nothing is done. The + right mouse button works as expected.
  • +
  • add - the object the mouse is + over is added to the selected objects before + displaying the menu.
  • +
  • single - the object the mouse is + over is made the sole selected object before + displaying the menu.
  • +
+
insert_selectWhen inserting new objects in a DOOM + level this alters the way that viDOOM selects the objects + after creation. The allowable values, and their affects + are:
    +
  • none - nothing is done. The new + object is left inselected.
  • +
  • add - the new object is added to + the selected objects.
  • +
  • single - the new object is made + the sole selected object.
  • +
+
linedef_selectDefines who many pixels around a LINEDEF + the bounding box stretches when selecting a line.
merge_linedefIf you overlay vertexes on top of each + other you can merge vertexes. Once these vertexes are + merged checks are made to see whether linedefs share + these vertexes, and hence overlap. This option controls + what happens when these overlapping linedefs are found. + The possible values are:
    +
  • always - always merge the + overlapping linedefs without any prompting.
  • +
  • ask - confirms with the user + before mergeing linedefs or not as requested.
  • +
  • never - never merge overlapping + linedefs.
  • +
+
new_2sided_selectWhen linedefs have there flags set so + that a new left sidedef is added to it controls how the + altered linedefs are selected. Possible values are:
    +
  • select - clears the currently + selected linedefs (if any) and selects the + linedefs that have new double sides.
  • +
  • ask - confirms with the user. If + the user opts to select the linedefs, the current + selection is cleared and the altered linedefs + selected.
  • +
  • never - never select the altered + linedefs. Note that a notice is still displayed + so that you know new left sidedefs have been + created.
  • +
+
sector_moveDefines which linedefs are actually + moved when moving a sector. Possible values are:
    +
  • all - move all linedefs that + border the sector.
  • +
  • right - move only linedefs that + have this sector to their right.
  • +
  • left - move only linedefs that + have this sector to their left.
  • +
+
show_full_linedef_infoIf set to yes then in + the linedef edit + display the linedef type will be shown as the full + linedef name as defined in the config + file. If set to no then linedef type + will be displayed as a hex value and it's class.
tag_highlightIf set to yes then the + tag highlighting mode is enabled by default in sector and + linedef modes.
vertex_radiusDescribes the size of the box around a + VERTEX which is used to select the VERTEX while editing. + Recommended values are any integer greater than four.
width
+
height
Describes the size of the display used + by viDOOM. viDOOM expects a resolution of at least + 640x480.
+ +
+ +

[viDOOM]

+ +

Main menu configuration

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
initial_empty_mapIf set to yes then on + startup viDOOM will have an empty map, either MAP01 or + E1M1, ready for editing.
load_flatsIf set to yes then the graphics + for the flats will be loaded so they can be selected + graphically. If set to no then flats are selected + just using their name.
+ This is provided as the graphics reading is not very + effecient and can be slow on certain machines.
load_texturesIf set to yes then the graphics + for the textures will be loaded so they can be selected + graphically. If set to no then textures are + selected just using their name.
+ This is provided as the graphics reading is not very + effecient and can be slow on certain machines.
load_spritesIf set to yes then the graphics + for the things will be loaded so they can be selected + graphically. If set to no then things are selected + just using their name.
+ This is provided as the graphics reading is not very + effecient and can be slow on certain machines.
map_clear_warningIf set to yes then a warning is + displayed whenever an option is chosen that will replace + the currently edited map with another, if the editor has + been used since the level's loading/creation.
map_exit_warningIf set to yes then a warning is + displayed if exit is chosen and the editor option has + been used.
overwrite_warningIf set to yes then a warning is + displayed if you save a map over a file that already + exists.
show_titlepicIf set to yes then the title + picture for the version of DOOM you are editing will be + displayed on the main title screen.
sort_flat_namesIf set to yes then when selecting + ceiling or floor flats they will be sorted into + alphabetical order. If set to no they are simply + in the order they appear in the IWAD file.
sort_texture_namesIf set to yes then when selecting + wall textures they will be sorted into alphabetical + order. If set to no they are simply in the order + they appear in the IWAD file.
+ +
+ +

[Check LINEDEF]

+ +

This defines how the Check LINEDEF function +in the editor (see editing +for details) operates. Note that part of the configuration for +this command also occurs in the config +file. This is required as texture names can be different in +different versions of DOOM. The following options are defineable +within the INI file:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
assume_yesIf this is set to yes + then any time a question would be asked to see if it's OK + to remove a texture that viDOOM considers unneccessary + then it will be removed without asking. Likewise when + asking to add missing textures the texture picklist will + appear (with the lindef number and what is to be set in + the title) without any prompting.
check_1side_lowerIf set to yes then when + a sidedef is attached to a one-sided linedef and there is + a lower texture defined viDOOM will ask if it's OK to + remove it.
check_1side_middleIf set to yes then when + a sidedef is attached to a one-sided linedef and there is + no middle texture defined viDOOM will ask if it's OK to + define it.
check_1side_upperIf set to yes then when + a sidedef is attached to a one-sided linedef and there is + an upper texture defined viDOOM will ask if it's OK to + remove it.
check_2side_lowerIf set to yes then when + a sidedef is attached to a two-sided linedef which is + between two sectors with different floor heights and + there is no lower texture defined viDOOM will ask if it's + OK to define it.
check_2side_middleIf set to yes then when + a sidedef is attached to a two-sided linedef which is + between two sectors and there is a middle texture defined + viDOOM will ask if it's OK to remove it.
check_2side_upperIf set to yes then when + a sidedef is attached to a two-sided linedef which is + between two sectors with different ceiling heights and + there is no upper texture defined viDOOM will ask if it's + OK to define it.
check_2side_same_sectorIf set to yes then when + a sidedef is attached to a two-sided linedef which is + wholly within one sector and there are any textures + defined viDOOM will ask if it's OK to remove them.
+ +
+ +

[Node Builder]

+ +

Node Builder configuration - used to build nodes for maps +automatically when saving.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
always_view_outputNormally viDOOM will only show the + output from the build command if it fails for some + reason. Setting this to yes means any + output from the node builder will be displayed + regardless.
commandDefines the command used to execute the + node builder. e.g.

command=c:\bsp\bsp.exe

+
ignoreIf set, then any saved filename that + includes this string will not be passed through the node + builder. This is useful so that structures for mergeing + into other maps (see editing + for details) need not be put through the node building + process. e.g. if set to

ignore=str

+

Then saving a map named MAP01.WAD + will be passed through the node builder, whereas WALL_STRUCT.WAD + would not be.

+

Another important use for this is to leave a back door + where you can save a WAD without it being passed through + the node builder if anything goes wrong with trying to + build the map.

+
infileDefines the format for the infile + parameter to the node builder. Any occurance of the '%' + character will be replaced with the full path of the map + being saved. e.g.

infile=%

+
outfileDefines the format for the outfile + parameter to the node builder. Any occurance of the '%' + character will be replaced with the full path of the map + being saved. e.g.

outfile=-o %

+

Note that if your node builder does not allow the + input and output file to be the same then it is + permissible to put extra characters after + the % that will get tacked onto the end of the name, e.g.

+

outfile=-o %_NEW

+
in_before_outDefines the order of the the arguments + to the node builder. If set to yes then + the node builder is invoked as:

command infile + outfile

+

If set to no then the command is + built as:

+

command outfile infile

+
useIf set to yes then the + node builder described above is used on any maps being + saved. If set to no then the map is + saved and the nodes must be built outside of viDOOM.
+ +
+ +

[GUI]

+ +

GUI configuration. All the values in this section are an RGB +triplet defined as an hex number, i.e. 0xRRGGBB. The +following values can be set from the INI file.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
gui_hiThe brightest colour used to draw the 3D + looking interface.
gui_midThe medium colour used to draw the 3D + looking interface.
gui_loThe darkest colour used to draw the 3D + looking interface.
gui_textThe colour of text.
gui_textshadowThe colour of the shadow behind text. + This is only really used by viDOOM's own portable GUI + routines. If set to the same value as text + then no shadows are drawn.
gui_boldThe colour of bold text (used for + titles)
+ +
+ +

[Game name]

+ +

One of these sections appears for each possible setting of the +game variable in the [Game] section. These are:

+ +
    +
  • [Doom]
  • +
  • [Ultimate Doom]
  • +
  • [Doom 2]
  • +
  • [TNT:Evilution]
  • +
  • [Plutonia Experiment]
  • +
  • [ZDoom]
  • +
+ + + + + + + + + + + + + + + + + + + + + + +
iwadDefines the path to the IWAD for this + game.
pwad_dirDefines the default load/save directory + for editing PWAD files.
level_styleDefines the level naming convention for + the game. Allowable values are:
    +
  • Doom - allows level names E1M1 to E3M9
  • +
  • Ultimate Doom - allows level names E1M1 to + E4M9
  • +
  • Doom 2 - allows level names MAP01 to MAP32
  • +
+
preloadLists a number of PWAD files to preload + on startup. PWAD files are seperated by ; and the full + path is expected.
vidoom_configDefines the config + file for this version of DOOM. This defines the + values used for defining things, lindefs, sectors and so + on.
+ viDOOM is currently supplied with doom.cfg and doom2.cfg. +
+ It is planned to soon include a zdoom.cfg so that + ZDOOM/BOOM special features can be added to levels.
+ +
+ +

Config file

+ +

There is two config files supplied with viDOOM, doom.cfg +and doom2.cfg. Each file is comprised of +sections followed by the data expected in each section. Each +section is defined by a line like:

+ +

%SECTION_NAME

+ +

While the data lines are on individual lines with the pipe (|) +character used to seperate fields, e.g.

+ +

Field 1|Field 2

+ +

Blank lines and lines starting with a comment character (#) +are ignored. The following sections are defined:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
%INCLUDE_FILESDefines any other config files to + include before processing this one. Simply type the + filenames to be included on individual lines.
%THING_CLASSESDefines the classes to group THINGs into + in the editor picklists. Each line is in the form + "Class Name|Colour". Note that colour is + defined as an hexadecimal number with the most + significant byte for RED, the middle byte for BLUE and + the least significant byte for GREEN. e.g.

Monster|0xff0000

+
%LINEDEF_CLASSESDefines the classes to group LINEDEF + types into in the editor picklists. Each line is a class + name.
%SECTOR_CLASSESDefines the classes to group SECTOR + types into in the editor picklists. Each line is a class + name.
%THING_TYPESDefines the names and IDs of the THINGs + supported by DOOM. Each line is in the form + "Class|Name|ID|Radius|Sprite Name". e.g.

Monster|Former + Human|3004|20|POSSA1

+
%THING_FLAGSDefines the flags used when defining + THINGs. Each line is in the form "Bit + Number|Name|Shorthand Name". e.g.

0|Skill 1 + and 2|Sk 1/2

+
%LINEDEF_TYPESDefines the names and IDs of the LINEDEF + types supported by DOOM. Each line is in the form + "Class|ID|Name", e.g.

Special|48|Scrolling + wall

+

Note: Please note that the text for + the LINEDEF types in the supplied config files is taken + directly from the Unofficial Doom Specs (see the thanks page for details).

+
%LINEDEF_FLAGSDefines the flags used when defining + LINEDEFs. Each line is in the form "Bit + Number|Name|Shorthand Character". e.g.

0|Impassible|I

+
%LINEDEF_FLAGS_EXTRAConfiguration so that viDOOM knows which + bits control certain functions. If more that one line + appears in this section then the last one is used. The + form of the line is "Bit number controlling + 2-sided|Bit controlling Impassible|Bit controlling lower + unpegged|Bit controlling upper unpegged". e.g.

2|0|3|4

+
%LINEDEF_DEFAULTSThis section must not appear before + %LINEDEF_FLAGS_EXTRA and defines the bit patterns for + various linedef styles. These are used in the editor so + that defining a type of LINEDEF can be quickly done when + creating them. The format of each line is + "Name|Flags value", e.g.

2-sided + wall|0x47

+
%SECTOR_TYPESDefines the names and IDs for the + different sector types. Each line is in the form + "Class|ID|Long name|Short name". e.g.

Damage/Lights|4|Lose + -10/20% health & blink lights 0.5 sec|-10/20% & + 0.5 blink

+
%SECTOR_STYLESDefines styles for painting sectors + quickly. The form of each line is + "Mode|Name|Upper|Middle|Lower|Floor|Ceiling". + e.g.

0x19|Quarry|SP_ROCK1|SP_ROCK1|SP_ROCK1|RROCK09|F_SKY1

+

The mode is a bit significant number where the bits + have the following meaning:

+
    +
  • Bit 0 - Paint textures on the sidedefs facing + into this sector
  • +
  • Bit 1 - Paint textures on the sidedefs facing out + of this sector
  • +
  • Bit 2 - Leave current lower/upper settings
  • +
  • Bit 3 - Set upper unpegged if an upper texture is + painted
  • +
  • Bit 4 - Set lower unpegged if a lower texture is + painted
  • +
+

If neither bits 2, 3 or 4 are set it is assumed that + lower/upper unpegged will be cleared on painting those + textures.

+
%EMPTY_TEXTURE_NAMESimply defines the empty texture name + used by DOOM. This will generally just be the - + character, e.g.

%EMPTY_TEXTURE_NAME
+ -

+
%NORMAL_TYPESDefines the values that define the + normal linedefs and sectors. The form of the single line + of data is "Id for normal linedef|Id for normal + sector". In all current versions of Doom this is + zero, e.g.

%NORMAL_TYPES
+ 0|0

+
%LINEDEF_CHECK_DEFAULTProvides an optional default texture to + use when a texture is requested when checking linedefs. + If this value is defined to be the same as + EMPTY_TEXTURE_NAME then the user is prompted for a + texture to use, otherwise this texture is used instead, + e.g.

%LINEDEF_CHECK_DEFAULT
+ ASHWALL

+

See editing for + details on the check linedef operation.

+
+ +
+ +

Back to index

+ +

$Id: overview.htm,v 1.7 2000/08/05 21:30:12 dosuser Exp dosuser $

+ + diff --git a/doc/porting.htm b/doc/porting.htm new file mode 100644 index 0000000..1dd3725 --- /dev/null +++ b/doc/porting.htm @@ -0,0 +1,1316 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

Porting viDOOM

+ +

This document is provided in case anyone wishes to port viDOOM +to a new platform. Below is an indication of what OS dependent +routines must be provided and what configuration needs to be +done. It is requested that any ports are also released as Free +Software.

+ + + +
+ +

Makefile configuration

+ +

makefile

+ +

Set the variable MAKEPLAT +to the name of your platform, eg.

+ +

MAKEPLAT=OS

+ +

You will then need to create a matching file the make +subdirectoy called OS.cfg. Also all the OS dependent C +source should go into a subdirectory defined in the following +make config file by the PLATFORM variable. See +the Files section for an overview of these +files.

+ +

make config file

+ +

The following values need to be set in the file make/OS.cfg:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CCSet to the name of the C compiler.
LDThe name of the linker.
PLATFORMThe name of the subdirectory containing + the OS dependent C sources. The idea of defineing this + here, rather than using the MAKEPLAT variable defined in + the top level makefile, is so that different + configurations can share sources. i.e. An X11 port may + use the same code for all the unix platforms, but each + machine may require slightly different configuration + (library search paths for example).
EXE_EXTAn extension to add to the executable + name, e.g.
+ EXE_EXT=.EXE
OBJ_EXTThe extension used in this OS to denote + object files produced by the C compiler. Generally:
+ OBJ_EXT=.o
LIBSAny extra libraries to link in with + viDOOM for the OS dependent routines.
EXRACFAny extra C flags required when + compiling the sources. Use it to enable optimisations and + to include any extra include paths required by this OS.
EXTRALFAny extra flags required when linking + viDOOM. Use it to enable include any extra librarypaths + required by this OS.
DIRSEPThe directory seperator character for + this OS. The character must be included in quotes, e.g.
+
DIRSEP="/"
MATHLIBThe options required to include the + maths library when linking.
TRACEFORMThis variable is a printf format string + and the arguments to the format. This string is used to + provide a tracing function used to track bugs in the + editor. A simple, portable example is:
+ TRACEFORM="%s:%d",__FILE__,__LINE__

It + can just be defined to an empty string if you are not + compiling the debug version.

+
EXEFLAGThe flag to provide to the linker to + generate an exectuable. The flag is used in a rule + something like this:
+ $(LD) $(EXTRALF) $(EXEFLAG) vidoom$(EXE_EXT) + $(ALL+VIDOOM_OBJECTS)
OBJFLAGThe flag to provide to the C compiler to + generate an object file from the supplied C source. The + flag is used in a rule something like this:
+ $(CC) $(EXTRACF) $(OBJFLAG) file.c
DEFINEFLAGThe flag to provide to the C compiler + with pre-processor definition from the command line. The + flag is used in a rule something like this (note no space + after the DEFINEFLAG - if there is a space between the + switch and the argument put it in this variable + definition):
+ $(CC) $(EXTRACF) $(OBJFLAG) $(DEFINEFLAG)MACRO=value + file.c
INCFLAGThe flag to provide to the C compiler + with extra directories in which the pre-processor + searches for include files. The flag is used in a rule + something like this (note no space after the INCFLAG - if + there is a space between the switch and the argument put + it in this variable definition):
+ $(CC) $(EXTRACF) $(OBJFLAG) $(INCFLAG)include_dir + file.c
MAKEINSTALLThe command used to execute the install + makefile as described in the installation + script section. The command must define the + INSTALLDIR variable for the makefile and invoke the first + rule in the install makefile.

For instance, using a + normal unix/GCC type make command, this would be:
+ make INSTALL_DIR='$(INSTALL_DIR)' -f install

+
+ +
+ +

INI File

+ +

If your port requires or wants configuration to be set at +tun-time from the INI file, it is best to place it a +system-dependent section called the same as the OS value +you set MAKEPLAT to for this platform, +e.g.

+ +

[OS]
+guimode=3D

+ +
+ +

Files

+ +

The following files are the minimum that must be provided by +the platform:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
make/OS.cfgThe make config file. Described in the previous section.
main.cThis goes in the platform + directory and provides the startup + code for the operating system.
gfx.cThis goes in the platform + directory and provides the low level + graphics and input.
platgui.cThis goes in the platform + directory and provides the system + dependent GUI.
file.cThis goes in the platform + directory and provides the portable part of the file system interface.
mem.cThis goes in the platform + directory and provides the memory + handling.
runcmd.cThis goes in the platform + directory and provides the method for running external commands.
vstring.cThis goes in the platform + directory and provides functions for string comparisons.
installThis goes in the platform + directory and is the makefile invoked to install viDOOM.
+ +
+ +

Main entry point

+ +

main.c

+ +

The OS dependent code must provide it's own main (this is to +allow for various non-standard environments where main() is not +the standard entry point). The entry point must do any OS +dependent initialisations then invoke the following entry point +to start up viDOOM:

+ +

int viDOOM(int argv, char *argv[])

+ +

If the OS uses main() as an entry point the following example +could be enough:

+ +
int main(int argc,char *argv[])
+{
+    return (viDOOM(argc,argv));
+}
+ +
+ +

Graphics and input

+ +

gfx.c

+ +

This provides the low-level graphics access and interfaces to +keyboard and mouse. The GFX object is expected to work on a weak, +semi-event driven basis for keyboard/mouse access. The following +are the basic assumptions about the GFX interface:

+ +
    +
  • A true, or hicolor, display.
  • +
  • A Fixed font.
  • +
  • Default origin is in the top left of the display, with X + positve along and Y positive down.
  • +
  • A buffered display. The screen contents should not change + until GFX_redraw() is called. If not honoured viDOOM + should still work up to a point, but it's use of the XOR + mode may not be apparent to the user.
  • +
  • Colours are represented using an int, with 8 bits each + for the red, green and blue component. The int used to + define the colour, when viewed in hex, would look like 0xRRGGBB. + Some examples are:
      +
    • 0xFF0000 - Red
    • +
    • 0x00FF00 - Green
    • +
    • 0x0000FF - Blue
    • +
    • 0xFFFFFF - White
    • +
    • 0x808080 - 50% grey
    • +
    • 0x000000 - Black
    • +
    +
  • +
+ +

The following types are defined and used by the GFX object :

+ + + + + + + + + + + + + + + + + + + + + + +
typedef void *GFX_IMAGE; 
+
This is an opaque type provided to allow + the GFX object to provide whatever is required to + reference a bitmap on the machine.
typedef struct
+    {
+    int           w;
+    int           h;
+    int           pal[256];
+    unsigned char *data;
+    } GFX_BITMAP; 
+
This type represents the bitmap objects + that viDOOM defines. These bitmaps are converted into + GFX_IMAGE prior to use. The fields are: + + + + + + + + + + + + + + + + + + + + +
w-width of bitmap
h-height of bitmap
pal[256]-The pallete used to define the + bitmap. Each bitmap pixel is an index into this + array of RGB values. Each entry is an integer, + that when represented in hex would define the RGB + triplet as 0xRRGGBB.
*data-A pointer to the data of the + bitmap. This should be accessed using pointer + arithmetic as *(data+(x)+(y*w))
+
typedef struct
+    {
+    int    type;
+    int    shift;
+    int    ctrl;
+    int    alt;
+    char   ascii;
+    int    code;
+    } GFXKey;
+
This defines an object for reporting key + presses. The fields are: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
type-The type of event. This field is + just used to line up with the event union defined + later on. Should just hold GFX_KEY_EVENT.
shift-TRUE if the Shift key is being + pressed.
ctrl-TRUE if the Control key is being + pressed.
alt-TRUE if the Alt key is being + pressed.
ascii-The ASCII code of the character + read. If the key is not an ASCII key (e.g. a + function key) this field should be zero.
code-Holds the code for non-ASCII + keys, e.g. GFX_F1. This field should be set to + GFX_ASCII for key presses reported through the + ascii field.
+
typedef struct GFXMouse
+    {
+    int    type;
+    int    shift;
+    int    ctrl;
+    int    alt;
+    int    x;
+    int    y;
+    int    b;
+    } GFXMouse;
+
This defines the type for reporting + mouse movements and button presses. The fields are: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
type-The type of event. This field is + just used to line up with the event union defined + later on. Should just hold GFX_MOUSE_EVENT.
shift-TRUE if the Shift key is being + pressed.
ctrl-TRUE if the Control key is being + pressed.
alt-TRUE if the Alt key is being + pressed.
x-The X co-ordinate of the mouse, + relative to the top left of the display.
y-The Y co-ordinate of the mouse, + relative to the top left of the display.
b-The currently pressed buttons. + This should be made up of a bit mask composed + from GFX_BUTLEFT, GFX_BUTMIDDLE and GFX_BUTRIGHT.
+
typedef union GFXEvent
+    {
+    int      type;
+    GFXKey   key;
+    GFXMouse mouse;
+    } GFXEvent;
+
This defines the type for reporting + events (a combination of both mouse movements or key + presses). The fields are: + + + + + + + + + + + + + + + +
type-The type of event. This field is + just used to decide which of the other two fields + should be accessed to get the event information. + This field must be GFX_MOUSE_EVENT or + GFX_KEY_EVENT.
key-The GFXKey structure defining + the event if this is a GFX_KEY_EVENT.
mouse-The GFXMouse structure defining + the event if this is a GFX_MOUSE_EVENT.
+
+ +

The following interfaces must be supplied by the GFX object:

+ +

void GFX_init(void)

+ +
+

Initialises the GFX object. No other GFX interfaces are + called prior to this, with the possible (though current not + used) exception of GFX_exit().

+
+ +

void GFX_close(void)

+ +
+

Called when viDOOM is terminating. Note that other (none + system dependent) processing may go on between calling this + and then invoking exit() or return().

+
+ +

GFX_IMAGE GFX_create_image(GFX_BITMAP *bm)

+ +
+

Should create a GFX_IMAGE from the passed bitmap bm.

+
+ +

void GFX_destroy_image(GFX_IMAGE img)

+ +
+

Release the bitmap object pointed to by img.

+
+ +

void GFX_draw_image(GFX_IMAGE img, int x, int y)

+ +
+

Draws img with it's top-left co-ordinate + represented by x,y. This function should implement + any necessary clipping when drawing the bitmap.

+
+ +

void GFX_fill_screen(GFX_IMAGE img)

+ +
+

Should fill the screen with the image, scaled if + necessary. Note that this call is just used for the menu + backdrop, so if it cannot be honoured no harm will be done.

+
+ +

void GFX_open(int width, +int height)

+ +
+

Opens the display (or window or whatever) with the + specified width and height. Note that + failures in here should terminate the program.

+
+ +

void GFX_clear(int col)

+ +
+

This clears the display to the passed colour col.

+
+ +

void GFX_redraw(void)

+ +
+

This redraws the contents of the screen. All drawing + operations should not update the actual screen till this is + called (i.e. the display should be buffered).

+
+ +

void GFX_line(int x1, int y1, int x2, int y2, int +col)

+ +
+

Draw a line from x1,y1 to x2,y2 in + colour col.

+
+ +

void GFX_plot(int x, int y, int col)

+ +
+

Plot the point x,y in colour col.

+
+ +

void GFX_circle(int x, int y, int r, int col)
+void GFX_fcircle(int x, int y, int r, int col)

+ +
+

Draw a circle centred on x,y with a radius r + and in colour col. The fcircle + version should draw a filled circle.

+
+ +

void GFX_rect(int x, int y, int w, int h, int col)
+void GFX_frect(int x, int y, int w, int h, int col)

+ +
+

Draw a rectangle with one corner at x,y and the + other corner at (x+w),(y+h) in colour col. + Note that zero length and negative width and heights must be + allowed. The frect version should draw a + filled rectangle.

+
+ +

void GFX_set_XOR_mode(void)
+void GFX_clear_XOR_mode(void)

+ +
+

This should set and clear XOR mode. Normally all GFX + operations should set the pixels to the colour specified, but + when XOR mode is enabled the pixel values should be XORed + into place.

+
+ +

void GFX_print(int x, int y, int col, char *fmt, +...)

+ +
+

Print the printf style arguments (fmt and ...) + with their top left corner at x,y in colour col. + Note that text should rendered transparently.

+
+ +

int GFX_fh(void)
+int GFX_fw(void)

+ +
+

Return the height (GFX_fh) and width (GFX_fw) of the fixed + width font used for display purposes.

+
+ +

int GFX_mouse_buttons(void)

+ +
+

Returns the number of mouse buttons. This is just used as + check on initialisation as viDOOM expects at least 2 mouse + buttons.

+
+ +

int GFX_mouse(int *x, int *y)

+ +
+

Return the current point position in x and y. + If any of the passed pointers are NULL that variable should + be ignored.

+
+ +

void GFX_waitkey(GFXKEy *key)

+ +
+

Waits for a key to be pressed and returns the key + press in key. If key is NULL simply wait + for a key press.

+
+ +

int GFX_key(GFXKey *key)

+ +
+

Returns TRUE if a key has been pressed and returns the + keypress in key. Returns FALSE if there is no + outstanding keypresses, in which case the contents of key + are undefined.

+
+ +

void GFX_bounce(void)

+ +
+

Waits for all keys and mouse buttons to be released. On a + real event-driven system could be ignored, or flush any + outstanding events.

+
+ +

void GFX_await_input(GFXEvent *ev)

+ +
+

Waits for either a keypress or a mouse button to be + pressed and fills in ev accordingly.

+
+ +

void GFX_await_input_full(GFXEvent *ev)

+ +
+

Waits for either a keypress, a mouse button to be pressed + or the mouse to be moved and fills in ev + accordingly.

+
+ +

void GFX_exit(int code, char *fmt, ...)

+ +
+

This call should do any necessary tidying of the display + (switching from graphics mode, closing windows, whatever) + then display the printf style arguments (fmt and ...) + and the exit with the passed return code.

+
+ +

void GFX_save_screen(char *path)

+ +
+

This call need not be supported. It just allows screen + grabs to be captured when viDOOM is compiled with debug + information. If supported it should just save a bitmap in the + file pointed to by path.

+
+ +
+ +

Platform GUI

+ +

platgui.c

+ +

This provides access to the platform's GUI routines.

+ +

The following types are defined and used by the PLATGUI object +:

+ + + + + + + + + + + + + + + + + + + + + + +
typedef struct
+    {
+    char      *text;
+    GFX_IMAGE img;
+    int       client_index;
+    } PLAT_IMG_PICKLIST;
+
This structure is used to define a + picklist that has graphical images and client defined + values attached to them. This is used for selection of + textures, flats and sprites (things) in viDOOM.

The + fields in the structure are:

+ + + + + + + + + + + + + + + + +
text-This defines the text for a + picklist entry. NULL marks the end of the list of + picklist entries.
img-The GFX_IMAGE to associate with + this entry. Can be NULL to indicate show no + image.
client_index-The value returned if this item + is selected.
+
typedef struct
+    {
+    char   *text;
+    int    client_index;
+    } PLAT_PICKLIST;
+
This structure is used to define a + picklist that has client defined values attached to the + entries.

The fields in the structure are:

+ + + + + + + + + + + +
text-This defines the text for a + picklist entry. NULL marks the end of the list of + picklist entries.
client_index-The value returned if this item + is selected.
+
typedef struct
+    {
+    char  *text;
+    int   client_index;
+    } PLAT_MENU;
+
This structure is used to define menu + entries that have client defined values attached to them.

The + fields in the structure are:

+ + + + + + + + + + + +
text-This defines the text for the + menu entry. NULL marks the end of the list of + menu entries.
client_index-The value returned if this item + is selected.
+
typedef struct
+    {
+    char   *text;
+    int    client_index;
+    } PLAT_RADIO;
+
This structure is used to define entries + for a radio style picklist (i.e. where only one option + can be chosen) that have client defined values attached + to them.

The fields in the structure are:

+ + + + + + + + + + + +
text-This defines the text for the + radio button. NULL marks the end of the list of + radio button entries.
client_index-The value returned if this item + is selected.
+
typedef struct
+    {
+    char   *text;
+    int    type;
+    union /* Data */
+        {
+        int	i;
+        char	s[PLAT_DIAL_MAXSTRLEN+1];
+        double	d;
+        } data;
+    } PLAT_DIALOG;
+
This structure is used to define entries + for a simple dialog.

The fields in the structure are:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
text-This defines the text for this + field in the dialog. NULL marks the end of the + list of dialog entries.
type-The type of field this is. + Possible values are PLAT_DIAL_STRING, + PLAT_DIAL_INTEGER and PLAT_DIAL_DOUBLE.
data.i-This is the field that is + displayed and updated on exit if the type is + PLAT_DIAL_INTEGER.
data.s-This is the field that is + displayed and updated on exit if the type is + PLAT_DIAL_STRING.
data.d-This is the field that is + displayed and updated on exit if the type is + PLAT_DIAL_DOUBLE.
+
+ +

Note that along with the types, the following predifined +values are set (these are read from the INI file). Note that they +shold be considered to be unset until immediately prior to +viDOOM's call to GUI_setscreen():

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
GUI_HIThe brightest colour used to draw the 3D + looking interface.
GUI_MIDThe medium colour used to draw the 3D + looking interface.
GUI_LOThe darkest colour used to draw the 3D + looking interface.
GUI_TEXTThe colour of text.
GUI_TEXTSHADOWThe colour of the shadow behind text. + This is only really used by viDOOM's own portable GUI + routines.
GUI_BOLDThe colour of bold text (used for + titles).
+ +

Functions

+ +

The following interfaces are defined by the PLATGUI object. +Note that all these calls are assumed to not destory screen +contents (ie. the screen should be restored after displaying the +GUI object):

+ +

void GUI_setscreen(int width, int height)

+ +
+

Once the display has been opened with GFX_open() + then this is called to inform the platform's GUI routines of + the display size.

+
+ +

int GUI_yesno(char *question)

+ +
+

Display an alert with question in it and Yes + and No buttons. Returns TRUE if Yes is + pressed and FALSE if No is pressed.

+
+ +

int GUI_menu(char *title, int x, int y, PLAT_MENU +menu[], int defval)

+ +
+

Displays a menu with title title at position x,y. + The displayed items are taken from menu. The return + is the client_index field from the selected menu item, or defval + if the menu is cancelled.

+
+ +

char *GUI_fsel(char *title, char *default_path, +char filter)

+ +
+

Allows a file to be selected. The file selector should + have title for it's title and start selecting from + the default_path. If filter is NULL then + all files should be displayed, otherwise only files ending in + filter.

+

The return is NULL if the selector is cancelled. Otherwise + a pointer is returned containing the fully qualified path of + the selected file. This pointer must be dynamically allocated + and will be freed using FRelease().

+
+ +

int GUI_picklist(char *title, char *opts[])

+ +
+

Displays a picklist with title title. The options + are taken from the array of character pointers opts. + The return value is the index of the selected item in opts + if selected, or -1 if the picklist is cancelled.

+
+ +

int GUI_client_picklist(char *title, PLAT_PICKLIST +opts[], int defval)

+ +
+

Displays a picklist with title title. The text + items to display are taken from opts. The return is + the client_index field from the selected picklist item, or defval + if the picklist is cancelled.

+
+ +

int GUI_image_picklist(char *title, +PLAT_IMG_PICKLIST opts[], int defval)

+ +
+

Displays a picklist with title title. The text + items and associated image to display are taken from opts. + The return is the client_index field from the selected + picklist item, or defval if the picklist is + cancelled.

+
+ +

int GUI_radio_box(char *title, PLAT_RADIO opts[], +int current, int defval)

+ +
+

Displays a dialog containing radio buttons with title title. + The text to display is taken from opts. The selected + object when the the radio box is first displayed is the + option who's client_index field matchs current (or + the first item if there is no match). The return is the + client_index field from the selected radio button, or defval + if the radio box is cancelled.

+
+ +

int GUI_multi_box(char *title, char *opts[], int +*val)

+ +
+

Display a mutli-selection radio box. The items are + described opts, which terminates with a NULL + pointer. Val points to a value which is used to + enable/disable the options dependent on the integers bit + setting. The integer pointed to by val is updated on + exit of the multi-selection box if it is not cancelled.

+

Note that the bit patterns are matched bit number to opt + index. ie.

+
    +
  • val & 0x0001 corresponds to opts[0]
  • +
  • val & 0x0002 corresponds to opts[1] ...
  • +
  • val & 0x0010 corresponds to opts[4] ...
  • +
  • val & 0x0100 corresponds to opts[8] ...
  • +
  • val & 0x8000 corresponds to opts[15]
  • +
+

A maximum of 16 bits should be all that needs supporting + currently. The return is TRUE if the dialog is accepted, + otherwise FALSE.

+
+ +

int GUI_dialog(char *title, int no, PLAT_DIALOG +dial[])

+ +
+

Displays a dialog with the title title. The + fields for the dialog are extracted from dial, for + which there is expected to be no elements. The + return is TRUE if the dialog is accepted, or FALSE if it is + cancelled. On being cancelled the contents of the data union + withing the dial elements is undefined.

+
+ +
+ +

File interface

+ +

file.c

+ +

This provides access to various file system functions and also +provides some filename manipulation routines. The following +interfaces should be provided:

+ +

char *Pwd(void)

+ +
+

This call should return the current working directory. The + return should be static.

+
+ +

void Cd(char *path)

+ +
+

This call should change the current working directory to path.

+
+ +

char *Dirname(char *path)

+ +
+

This call should return the directory part of path + if any. The return should be static.

+
+ +

char *Basename(char *path)

+ +
+

This call should return the filname part of path. + The return should be static, or a pointer into the path + parameter.

+
+ +

int FileExists(char *path)

+ +
+

This call should return TRUE if the file pointed to by path + exists.

+
+ +

int FilenamesEqual(char *path1, char *path2)

+ +
+

This call should return TRUE if the file pointed to by path1 + and path2 are the same file. At it's most basic + (e.g. like in the DOS port) it can simply makes sure that + directory seperators are in the same form and then does strcasecmp() + on the paths.

+
+ +
+ +

Memory allocation

+ +

mem.c

+ +

This provides memory allocation. While memory allocation can +generally be done portably using malloc() providing this +library just covers for any possible OS dependent twist. Also +these routines are expected to handle errors internally. In all +the interfaces file and line parameters are +included so that errors can be reported more accurately.

+ +

The following interfaces should be provided:

+ +

void *FGrab (char *file, int line, int len)

+ +
+

This call should allocate len bytes and return a + pointer to it. A len of zero is valid. Memory should + be initialised to zero. Failure to allocate the memory should + terminate the program.

+
+ +

void *FReGrab (char *file, int line, void *ptr, +int len)

+ +
+

This call should re-allocate the memory pointed to by ptr + and return a new memory area of len bytes. The + original data pointed to by ptr should be copied to + the new memory area. Failure to allocate the memory should + terminate the program.

+
+ +

char *FStrdup (char *file, int line, char *str)

+ +
+

This call should allocate enough bytes to copy the nul + terminated str to it. The returned pointer should + point to the new copy of str. Failure to + allocate the memory should terminate the program.

+
+ +

void *FCopy (char *file, int line, void *ptr, int +len)

+ +
+

This call should allocate len bytes and copy len + bytes from ptr into the new area. The newly + allocated memory should be returned. Failure to allocate the + memory should terminate the program.

+
+ +

void FRelease (char *file, +int line, void *ptr)

+ +
+

This call should release the memory pointed to by ptr, + which will have been allocated by FGrab, FReGrab, FStrdup or + FCopy.

+
+ +
+ +

External command execution

+ +

runcmd.c

+ +

Provides a mechanism to run an external command. The following +interfaces should be provided:

+ +

int RunCommand(char *argv[], char *path)

+ +
+

Run a command. Te output from the command (if there is + any) should NOT disturb the screen contents. The call should + return TRUE if the call succeeds, FALSE otherwise.

+

The argv list is an array of pointers to various + sections of the command and it's arguemnts, terminated with a + NULL pointer. Note that arguments may contain more than one + argument in each line - the actual command is described + simply by concatanating all the pointers together, eg.

+

argv[0]="bsp"
+ argv[1]="file.wad"
+ argv[2]="-o file.wad"
+ argv[3]=NULL

+

The path argument is a place to copy the path to + a file where the output from the comand has been stored. If + this is not supported then the empty string should be + assigned to it. viDOOM will remove() the file after + it has read it.

+
+ +
+ +

Portable String routines

+ +

vstring.c

+ +

Provides common string functions that are not actually part of +the ANSI standard:

+ +

int StrCaseCmp(char *a, char *b)

+ +
+

Performs in exactly the same way as the ANSI strcmp() + function, save for the fact that the case of the strings + being compared is ignored.

+
+ +

int StrNCaseCmp(char *a, char *b)

+ +
+

Performs in exactly the same way as the ANSI strncmp() + function, save for the fact that the case of the strings + being compared is ignored.

+
+ +
+ +

Installation script

+ +

Each platform should provide a makefile called install. +This is invoked from the top level makefile like this:

+ +
+

cd $(PLATFORM) ; $(MAKEINSTALL)

+
+ +

Note that the install makefile will be invoked with the PLATFORM directory as the current working +directory.

+ +

The following files should be copied (where $SRC represents +the source build directory and $INSTALLDIR the install +directory):

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
$SRC/vidoom$INSTALLDIR/vidoom

Note that + this file may have a system specific extension (e.g. .EXE + in DOS)

+
$SRC/LICENSE$INSTALLDIR/LICENSE

The GNU + GPL must be copied into the + installation directory.

+
$SRC/base.ini$INSTALLDIR/vidoom.ini
$SRC/*.cfg$INSTALLDIR/*.cfg
$SRC/doc/*.htm$INSTALLDIR/doc/*.htm
$SRC/doc/*.png$INSTALLDIR/doc/*.png
+ +
+ +

Documentation

+ +

If you release a port of viDOOM to any platform please update doc/bugs.htm with a contact address +for problems on that platform.

+ +
+ +

Back to index

+ +

$Id: porting.htm,v 1.17 2000/08/05 19:58:21 dosuser Exp dosuser $

+ + diff --git a/doc/thanks.htm b/doc/thanks.htm new file mode 100644 index 0000000..0cd1173 --- /dev/null +++ b/doc/thanks.htm @@ -0,0 +1,70 @@ + + + + + +viDOOM - Free Software DOOM editor + + + + +

Acknowledgements and Thanks

+ +

viDOOM could not have been written without help from the +following sources. Please mail me if there are any errors or I +have been mis-informed on who actually did something.

+ +

Doom - id +Software
+Creators of DOOM, who thankfully wrote a terribly nice game and +then made it even nicer by making the WAD format simple and open. +

+ +

Unofficial Doom Specs - Matthew S Fell
+Writer and maintainer of the Unofficial +DOOM Specs. viDOOM would have been impossible without this +marvellous tome.

+ +

BSP - Colin Reed/ Lee Killough
+Developers of the BSP node builder. Without this viDOOM is +completely useless.

+ +

Maths help - Mathew Wilson
+Someone who knows much more maths than I ever will and writer of +the LinesCross() alogrithm - saviour of the LINEDEF selection +code.

+ +

More maths help - comp.graphics.algorithms +FAQ
+Provided a much better 'is a point in a polygon?' than my +original one ever was...

+ +

Music - C64 Audio
+Call me sad, call me mad, or call me a nutter who needs to get +out more and find a life, but some of the Commodore 64 CDs and +MP3's didn't half help the coding and vague stabs at +documentation along some evenings.

+ +

VIM - Various +authors
+VI iMproved. My favourite editor, and inspiration (well, the +original) for the name viDOOM. Now, if only all these flash IDEs +would realise that people may actually want to use something +other than their own bundled multi-coloured swap-shop editors...

+ +

 

+ +
+ +

Back to index

+ +

$Id: thanks.htm,v 1.4 2000/08/05 21:30:12 dosuser Exp dosuser $

+ + diff --git a/doom.cfg b/doom.cfg new file mode 100644 index 0000000..2f7c71d --- /dev/null +++ b/doom.cfg @@ -0,0 +1,527 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program 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. +# +# This program is distributed in the hope that 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# +# $Id: doom.cfg,v 1.26 2000/07/19 16:36:12 dosuser Exp dosuser $ +# +# Doom config file. The following sections may be present: +# +# %INCLUDE_FILES - include other config files +# %THING_CLASSES - classes of things (ammo, monsters, etc) +# %LINEDEF_CLASSES - classes of linedefs +# %SECTOR_CLASSES - classes of sectors +# %THING_TYPES - details types and IDs of things +# %THING_FLAGS - details flags and meaning for things +# %LINEDEF_FLAGS - details flags and meaning for linedefs +# %LINEDEF_FLAGS_EXTRA - details which flags indicate certain features +# %LINEDEF_TYPES - details types and IDs for linedefs +# %LINEDEF_DEFAULTS - default types for linedefs +# %SECTOR_STYLES - define texturing styles for linedefs +# %SECTOR_TYPES - details types and IDs of sectors +# %EMPTY_TEXTURE_NAME - name used for the empty texture +# %NORMAL_TYPES - values for normal sectors and linedefs +# %LINEDEF_CHECK_DEFAULT - optional textuire to use filling in missing +# textures when performing check linedefs +# + + +# THING_CLASSES +# +# Classes of things. Format is "class name|colour" +# +# Colour is defined as a hex number, each byte either R, G or B - 0xRRGGBB +# +# +%THING_CLASSES +Ammo|0x808000 +Dead Things|0x800000 +Health Items|0x00a000 +Other Items|0xa0a000 +Keys|0x00a0a0 +Monster|0xd01010 +Player Start|0xa000a0 +Scenery|0xa22a2a +Teleport|0x00a000 +Weapon|0xa0a000 + + +# LINEDEF_CLASSES +# +# Classes of linedefs. Format is "class name" +# +# +%LINEDEF_CLASSES +Normal +Local door +Remote door +Ceiling +Lift +Floor +Stair +Moving floor +Crushing ceiling +Exit level +Teleport +Light effect +Special + + +# SECTOR_CLASSES +# +# Classes of sectors. Format is "class name" +# +# +%SECTOR_CLASSES +Normal +Lights +Damage +Damage/Lights +Damage/Exit +Door +Secret + + +# THING_TYPES section. Each lines is "class|name|id|radius|sprite_name" +# +# Where class is a class from the %THING_CLASSES section +# +# sprite_name can be "-" to incidate no graphics +# +%THING_TYPES +Ammo|Ammo clip|2007|20|CLIPA0 +Ammo|Shotgun shells|2008|20|SHELA0 +Ammo|A rocket|2010|20|ROCKA0 +Ammo|Cell charge|2047|20|CELLA0 +Ammo|Box of ammo|2048|20|AMMOA0 +Ammo|Box of shells|2049|20|SBOXA0 +Ammo|Box of rockets|2046|20|BROKA0 +Ammo|Big cell charge|17|20|CELPA0 +Ammo|Backpack|8|20|BPAKA0 + +Dead Things|Exploded player|10|20|PLAYW0 +Dead Things|Bloody mess|12|20|PLAYW0 +Dead Things|Pool of blood and flesh|24|20|POL5A0 +Dead Things|Dead player|15|20|PLAYW0 +Dead Things|Dead former human|18|20|POSSU0 +Dead Things|Dead sergeant|19|20|SPOSU0 +Dead Things|Dead imp|20|20|TROOU0 +Dead Things|Dead demon|21|20|SARGN0 +Dead Things|Dead cacodemon|22|20|HEADL0 +Dead Things|Dead lost soul|23|20|SKULJ0 + +Health Items|Stimpak|2011|20|STIMA0 +Health Items|Medikit|2012|20|MEDIA0 +Health Items|Health potion|2014|20|BON1A0 +Health Items|Spirt armour|2015|20|BON2A0 +Health Items|Green armour|2018|20|ARM1A0 +Health Items|Blue armour|2019|20|ARM2A0 +Health Items|Soulsphere|2013|20|SOULA0 +Health Items|Berserk|2023|20|PSTRA0 + +Other Items|Invulnerable|2022|20|PINVA0 +Other Items|Invisibility|2024|20|PINSA0 +Other Items|Radiation suit|2025|20|SUITA0 +Other Items|Map|2026|20|PMAPA0 +Other Items|Light amplification goggles|2045|20|PVISA0 + +Keys|Blue keycard|5|20|BKEYA0 +Keys|Blue skullkey|40|20|BSKUA0 +Keys|Red keycard|13|20|RKEYA0 +Keys|Red skullkey|38|20|RSKUA0 +Keys|Yellow keycard|6|20|YKEYA0 +Keys|Yellow skullkey|39|20|YSKUA0 + +Monster|Former Human|3004|20|POSSA1 +Monster|Former Sergeant|9|20|SPOSA1 +Monster|Imp|3001|20|TROOA1 +Monster|Demon|3002|30|SARGA1 +Monster|Spectre|58|30|SARGA1 +Monster|Lost soul|3006|16|SKULA1 +Monster|Cacodemon|3005|31|HEADA1 +Monster|Baron of Hell|3003|24|BOSSA1 +Monster|Spider Mastermind|7|128|SPIDA1D1 +Monster|Cyberdemon|16|40|CYBRA1 +Monster|Barrel|2035|16|BAR1A0 + +Player Start|Player 1 start|1|16|PLAYA1 +Player Start|Player 2 start|2|16|PLAYA1 +Player Start|Player 3 start|3|16|PLAYA1 +Player Start|Player 4 start|4|16|PLAYA1 +Player Start|Deatchmatch start|11|16|PLAYA1 + +Scenery|Tall techno pillar|48|16|ELECA0 +Scenery|Tall green pillar|30|16|COL1A0 +Scenery|Tall red pillar|32|16|COL3A0 +Scenery|Short green pillar|31|16|COL2A0 +Scenery|Short green pillar with beating heart|36|16|COL5A0 +Scenery|Short red pillar|33|16|COL4A0 +Scenery|Short red pillar with skull|37|16|COL6A0 +Scenery|Small brown pointy stump|47|16|SMITA0 +Scenery|Gray tree|43|16|TRE1A0 +Scenery|Large brown tree|54|32|TRE2A0 +Scenery|Floor lamp|2028|16|COLUA0 +Scenery|Candle|34|16|CANDA0 +Scenery|Candelabra|35|16|CBRAA0 +Scenery|Tall blue firestick|44|16|TBLUA0 +Scenery|Tall green firestick|45|16|TGRNA0 +Scenery|Tall red firestick|46|16|TREDA0 +Scenery|Short blue firestick|55|16|SMBTA0 +Scenery|Short green firestick|56|16|SMGTA0 +Scenery|Short red firestick|57|16|SMRTA0 +Scenery|Evil Eye|41|16|CEYEA0 +Scenery|Flaming skull rock|42|16|FSKUA0 + +Scenery|Hanging victim, twitching|49|16|GOR1A0 +Scenery|Hanging victim, twitching (let thru)|63|16|GOR1A0 +Scenery|Hanging victim, arms out|50|16|GOR2A0 +Scenery|Hanging victim, arms out (let thru)|59|16|GOR2A0 +Scenery|Hanging pair of legs|52|16|GOR4A0 +Scenery|Hanging pair of legs (let thru)|60|16|GOR4A0 +Scenery|Hanging victim, 1-legged|51|16|GOR3A0 +Scenery|Hanging victim, 1-legged (let thru)|61|16|GOR3A0 +Scenery|Hanging leg|53|16|GOR5A0 +Scenery|Hanging leg (let thru)|62|16|GOR5A0 + +Scenery|Impaled human|25|16|POL1A0 +Scenery|Twitching impaled human|26|16|POL6A0 +Scenery|Skull on a pole|27|16|POL4A0 +Scenery|Skewerd skulls|28|16|POL2A0 +Scenery|Pile of skulls and candles|29|16|POL3A0 + +Teleport|Teleport landing|14|16|TFOGA0 + +Weapon|Chainsaw|2005|20|CSAWA0 +Weapon|Shotgun|2001|20|SHOTA0 +Weapon|Chaingun|2002|20|MGUNA0 +Weapon|Rocket launcher|2003|20|LAUNA0 +Weapon|Plasma gun|2004|20|PLASA0 +Weapon|BFG 9000|2006|20|BFUGA0 + + +# THING_FLAGS section. Each line is "bit number|name|short hand name" +# +# Note there can be no gaps in the bit numbers. If there are bits that +# don't matter they must still defined, eg. +# 0|Bit 0 +# 1|Unused +# 2|Bit 2 +# +%THING_FLAGS +0|Skill 1 and 2|Sk 1/2 +1|Skill 3|Sk 3 +2|Skill 4 and 5|Sk 4/5 +3|Deaf|Deaf +4|Deathmatch only|Deathmatch + + +# LINEDEF_TYPES section. Each line is "class|id|name" +# +# Class is one of the classes from %LINEDEF_CLASSES +# +%LINEDEF_TYPES +Normal|0|Normal + +Special|48|Scrolling wall + +Local door|1|SRm door med 4 - open/close +Local door|26|SR door med 4 - open/close BLUE KEY +Local door|28|SR door med 4 - open/close RED KEY +Local door|27|SR door med 4 - open/close YELLOW KEY +Local door|31|S1 door med - - open +Local door|32|S1 door med - - open BLUE KEY +Local door|33|S1 door med - - open RED KEY +Local door|34|S1 door med - - open YELLOW KEY +Local door|46|GR door med - - open +Local door|117|SR blaze turbo 4 - open/close +Local door|118|S1 blaze turbo - - open + +Remote door|4|W1 door med 4 - open,close +Remote door|29|S1 door med 4 - open,close +Remote door|90|WR door med 4 - open,close +Remote door|63|SR door med 4 - open,close +Remote door|2|W1 door med - - open +Remote door|103|S1 door med - - open +Remote door|86|WR door med - - open +Remote door|61|SR door med - - open +Remote door|3|W1 door med - - close +Remote door|50|S1 door med - - close +Remote door|75|WR door med - - close +Remote door|42|SR door med - - close +Remote door|16|W1 door med 30 - close, then opens +Remote door|76|WR door med 30 - close, then opens +Remote door|108|W1 blaze turbo 4 - open,close +Remote door|111|WR blaze turbo 4 - open,close +Remote door|105|S1 blaze turbo 4 - open,close +Remote door|114|SR blaze turbo 4 - open,close +Remote door|109|W1 blaze turbo - - open +Remote door|112|S1 blaze turbo - - open +Remote door|106|WR blaze turbo - - open +Remote door|115|SR blaze turbo - - open +Remote door|110|W1 blaze turbo - - close +Remote door|113|S1 blaze turbo - - close +Remote door|107|WR blaze turbo - - close +Remote door|116|SR blaze turbo - - close +Remote door|133|S1 blaze turbo - - open BLUE KEY +Remote door|99|SR blaze turbo - - open BLUE KEY +Remote door|135|S1 blaze turbo - - open RED KEY +Remote door|134|SR blaze turbo - - open RED KEY +Remote door|137|S1 blaze turbo - - open YELLOW KEY +Remote door|136|SR blaze turbo - - open YELLOW KEY + +Ceiling|40|W1 mover slow - - up to HEC +Ceiling|41|S1 mover slow - - down to floor +Ceiling|43|SR mover slow - - down to floor +Ceiling|44|W1 mover slow - - down to floor + 8 +Ceiling|49|S1 mover slow - - down to floor + 8 +Ceiling|72|WR mover slow - - down to floor + 8 + +Lift|10|W1 lift fast 3 - lift +Lift|21|S1 lift fast 3 - lift +Lift|88|WRm lift fast 3 - lift +Lift|62|SR lift fast 3 - lift +Lift|121|W1 lift turbo 3 - lift +Lift|122|S1 lift turbo 3 - lift +Lift|120|WR lift turbo 3 - lift +Lift|123|SR lift turbo 3 - lift + +Floor|119|W1 mover slow - - up to nhEF +Floor|128|WR mover slow - - up to nhEF +Floor|18|S1 mover slow - - up to nhEF +Floor|69|SR mover slow - - up to nhEF +Floor|22|W1& mover slow - TX up to nhEF +Floor|95|WR& mover slow - TX up to nhEF +Floor|20|S1& mover slow - TX up to nhEF +Floor|68|SR& mover slow - TX up to nhEF +Floor|47|G1& mover slow - TX up to nhEF +Floor|5|W1 mover slow - - up to LIC +Floor|91|WR mover slow - - up to LIC +Floor|101|S1 mover slow - - up to LIC +Floor|64|SR mover slow - - up to LIC +Floor|24|G1 mover slow - - up to LIC +Floor|130|W1 mover turbo - - up to nhEF +Floor|131|S1 mover turbo - - up to nhEF +Floor|129|WR mover turbo - - up to nhEF +Floor|132|SR mover turbo - - up to nhEF +Floor|56|W1& mover slow - - up to LIC - 8, CRUSH +Floor|94|WR& mover slow - - up to LIC - 8, CRUSH +Floor|55|S1 mover slow - - up to LIC - 8, CRUSH +Floor|65|SR mover slow - - up to LIC - 8, CRUSH +Floor|58|W1 mover slow - - up 24 +Floor|92|WR mover slow - - up 24 +Floor|15|S1& mover slow - TX up 24 +Floor|66|SR& mover slow - TX up 24 +Floor|59|W1& mover slow - TXP up 24 +Floor|93|WR& mover slow - TXP up 24 +Floor|14|S1& mover slow - TX up 32 +Floor|67|SR& mover slow - TX up 32 +Floor|140|S1 mover med - - up 512 +Floor|30|W1 mover slow - - up ShortestLowerTexture +Floor|96|WR mover slow - - up ShortestLowerTexture +Floor|38|W1 mover slow - - down to LEF +Floor|23|S1 mover slow - - down to LEF +Floor|82|WR mover slow - - down to LEF +Floor|60|SR mover slow - - down to LEF +Floor|37|W1 mover slow - NXP down to LEF +Floor|84|WR mover slow - NXP down to LEF +Floor|19|W1 mover slow - - down to HEF +Floor|102|S1 mover slow - - down to HEF +Floor|83|WR mover slow - - down to HEF +Floor|45|SR mover slow - - down to HEF +Floor|36|W1 mover fast - - down to HEF + 8 +Floor|71|S1 mover fast - - down to HEF + 8 +Floor|98|WR mover fast - - down to HEF + 8 +Floor|70|SR mover fast - - down to HEF + 8 +Floor|9|S1 mover slow - NXP donut (see note 12 above) + +Stair|8|W1 mover slow - - stairs +Stair|7|S1 mover slow - - stairs +Stair|100|W1 mover turbo - - stairs (each up 16 not 8) + crush +Stair|127|S1 mover turbo - - stairs (each up 16 not 8) + crush + +Moving floor|53|W1& lift slow 3 - start moving floor +Moving floor|54|W1& - - - - stop moving floor +Moving floor|87|WR& lift slow 3 - start moving floor +Moving floor|89|WR& - - - - stop moving floor + +Crushing ceiling|6|W1& crush med 0 - start crushing, fast hurt +Crushing ceiling|25|W1& crush med 0 - start crushing, slow hurt +Crushing ceiling|73|WR& crush slow 0 - start crushing, slow hurt +Crushing ceiling|77|WR& crush med 0 - start crushing, fast hurt +Crushing ceiling|57|W1& - - - - stop crush +Crushing ceiling|74|WR& - - - - stop crush +Crushing ceiling|141|W1& none? slow 0 - start crushing, slow hurt "Silent" + +Exit level|11|S- clunk - - - End level, go to next level +Exit level|51|S- clunk - - - End level, go to secret level +Exit level|52|W- clunk - - - End level, go to next level +Exit level|124|W- clunk - - - End level, go to secret level + +Teleport|39|W1m tport - - - Teleport +Teleport|97|WRm tport - - - Teleport +Teleport|125|W1m tport - - - Teleport monsters only +Teleport|126|WRm tport - - - Teleport monsters only + +Light effect|35|W1 - - - - 0 +Light effect|104|W1 - - - - LE (light level) +Light effect|12|W1 - - - - HE (light level) +Light effect|13|W1 - - - - 255 +Light effect|79|WR - - - - 0 +Light effect|80|WR - - - - HE (light level) +Light effect|81|WR - - - - 255 +Light effect|17|W1 - - - - Light blinks (see [4-9-1] type 3) +Light effect|138|SR clunk - - - 255 +Light effect|139|SR clunk - - - 0 + + + +# LINEDEF_FLAGS section. Each line is "bit number|name|short hand char" +# +# Note there can be no gaps in the bit numbers. If there are bits that +# don't matter they must still defined, eg. +# 0|Bit 0|1 +# 1|Unused|- +# 2|Bit 2|1 +# +%LINEDEF_FLAGS +0|Impassible|I +1|Block monsters|M +2|Two-sided|2 +3|Upper unpegged|U +4|Lower unpegged|L +5|Secret|S +6|Blocks sound|B +7|Not on map|N +8|Already on map|A + + +# LINEDEF_FLAGS_EXTRA +# +# Simply defines which of the LINEDEF flag bits are the ones that indicates +# certain eatures. This will probably never change anyhow, but is configurable +# in case. The format is: +# +# || +# | +# +# This section MUST appear before LINEDEF_DEFAULTS +# +%LINEDEF_FLAGS_EXTRA +2|0|3|4 + + +# LINEDEF_DEFAULTS +# +# Defaults to use for linedefs. Should appear after LINEDEF_FLAGS. Format: +# Name|Flags values +# +%LINEDEF_DEFAULTS +Empty|0x00 +Wall|0x01 +2-sided wall|0x47 +2-sided passable|0x04 +2-sided blocks monsters|0x46 + + +# SECTOR_TYPES +# +# Defines values and descriptions for the SECTOR special value +# +# Format: +# Class|Id|Long Name|Short Name +# +# Long name should be no longer than 60 characters, Short no longer than 30 +# Class is one of the classes from %SECTOR_CLASSES +# +%SECTOR_TYPES +Normal|0|Normal|Normal +Lights|1|Light random off|Random off +Lights|2|Blink lights 0.5 second|0.5 blink +Lights|3|Blink lights 1.0 second|1.5 blink +Damage/Lights|4|Lose -10/20% health & blink lights 0.5 sec|-10/20% & 0.5 blink +Damage|5|Lose -5/10% health|-5/10% +Damage|7|Lose -2/5% health|-2/5% +Lights|8|Oscillating light|Oscillating light +Secret|9|Secret|Secret +Door|10|Door closes after 30 seconds|30 sec door +Damage/Exit|11|-10/20% health - end level if < 11%|Damage/end level +Lights|12|Blink lights synchronised 0.5 second|0.5 blink sync +Lights|13|Blink lights synchronised 1.0 second|1.5 blink sync +Door|14|Door opens after 300 seconds|300 sec door +Damage|16|Lose -10/20% health|-10/20% +Lights|17|Light random on/off|Random on/off + + + +# SECTOR_STYLES +# +# Sector textureing styles. Note this section is not additive like the +# other sections (as different DOOMs can have different texture names). +# +# Format : +# +# Mode|Name|Upper|Middle|Lower|Floor|Ceiling +# +# Mode is made up of the following bit fields: +# +# Bit 0 - Paint textures on the sidedefs facing into this sector +# Bit 1 - Paint textures on the sidedefs facing out of this sector +# Bit 2 - Leave current lower/upper settings +# Bit 3 - Set upper unpegged if an upper texture is painted +# Bit 4 - Set lower unpegged if a lower texture is painted +# +# If none of bits 2,3 or 4 are set it is assumed that lower/upper unpegged will +# be cleared on painting those textures. +# +%SECTOR_STYLES +0x19|Quarry|ASHWALL|ASHWALL|ASHWALL|MFLR8_2|F_SKY1 +0x19|Fire Quarry|ROCKRED1|ROCKRED1|ROCKRED1|MFLR8_2|F_SKY1 +0x19|Computer Room|COMPTALL|COMPTALL|COMPTALL|CRATOP1|FLAT2 +0x19|Demon Room|MARBFACE|MARBFACE|MARBFACE|DEM1_6|DEM1_5 + + +# EMPTY_TEXTURE_NAME +# +# The empty texture name. For DOOM this is '-'. +# +%EMPTY_TEXTURE_NAME +- + + +# NORMAL_TYPES +# +# The type values used to represent normal sectors and linedefs +# +# Format: +# Value for sectors|Value for linedefs +# +%NORMAL_TYPES +0|0 + + +# LINEDEF_CHECK_DEFAULT +# +# This controls the linedef F12 checking. Where it finds missing textures +# it will replace them with this one, rather than asking, unless this section +# is not defined or is defined to the same value as EMPTY_TEXTURE_NAME. +# +# Format: +# texture_name +# +%LINEDEF_CHECK_DEFAULT +ASHWALL2 diff --git a/doom2.cfg b/doom2.cfg new file mode 100644 index 0000000..1f58a0a --- /dev/null +++ b/doom2.cfg @@ -0,0 +1,72 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program 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. +# +# This program is distributed in the hope that 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# +# $Id: doom2.cfg,v 1.12 2000/06/12 15:58:54 dosuser Exp dosuser $ +# +# Doom 2 config file. See the heading of doom.cfg for details +# + +%INCLUDE_FILES +doom.cfg + +# THING_TYPES section +# +%THING_TYPES +Dead Things|Pool of blood|79|20|POB1A0 +Dead Things|Pool of blood|80|20|POB2A0 +Dead Things|Pool of brains|81|20|BRS1A0 + +Health Items|Megasphere|83|20|MEGAA0 + +Monster|Wolfenstien SS|84|20|SSWVA1 +Monster|Chaingunner|65|20|CPOSA1 +Monster|Hell Knight|69|24|BOS2A1C1 +Monster|Arachnotron|68|64|BSPIA1D1 +Monster|Pain Elemental|71|31|PAINA1 +Monster|Revenant|66|20|SKELA1D1 +Monster|Mancubus|67|48|FATTA1 +Monster|Arch Vile|64|20|VILEA1D1 +Monster|Boss Brain|88|16|BBRNA0 +Monster|Hellspawn Generator|89|16|BOSFB0 +Monster|Hellspawn Spot|87|16|FIRED0 + +Misc|Commander Keen|72|10|KEENA0 + +Scenery|Tall techno floor lamp|85|16|TLMPA0 +Scenery|Short techno floor lamp|86|16|TLP2A0 +Scenery|Burning barrel|70|16|FCANA0 +Scenery|Hanging victim, guts removed|73|16|HDB1A0 +Scenery|Hanging victim, guts and brain removed|74|16|HDB2A0 +Scenery|Hanging torso, looking down|75|16|HDB3A0 +Scenery|Hanging torso, open skull|76|16|HDB4A0 +Scenery|Hanging torso, looking up|77|16|HDB5A0 +Scenery|Hanging torso, brain removed|78|16|HDB6A0 + +Weapon|Double-barrel shotgun|82|20|SGN2A0 + + +# SECTOR_STYLES +# +%SECTOR_STYLES +0x19|Quarry|SP_ROCK1|SP_ROCK1|SP_ROCK1|RROCK09|F_SKY1 +0x19|Concrete Room|STONE|STONE|STONE|FLAT5_4|GRNLITE1 +0x19|Computer Room|COMPTALL|COMPTALL|COMPTALL|FLAT19|FLAT17 +0x19|Demon Room|MARBFACE|MARBFACE|MARBFACE|DEM1_6|DEM1_5 +0x03|Teleport|SUPPORT3|SUPPORT3|SUPPORT3|GATE3|GATE4 diff --git a/edit.c b/edit.c new file mode 100644 index 0000000..0402287 --- /dev/null +++ b/edit.c @@ -0,0 +1,734 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor main definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include + +#include "edit.h" +#include "editvar.h" + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +void EditSetScreen(int w,int h) +{ + TRACE; + + SCRW=w; + SCRH=h; + + FH=GFX_fh(); + + vertex=MapNew(sizeof(Object)); + linedef=MapNew(sizeof(Object)); + sidedef=MapNew(sizeof(Object)); + thing=MapNew(sizeof(Object)); + sector=MapNew(sizeof(Object)); + selected=ListNew(sizeof(int)); +} + +void EditPreviewWadMap(char *name,WadMap *m) +{ + int min_x,min_y,cx,cy,scale; + int f; + Linedef *l; + Vertex *v1,*v2; + int done; + int redraw; + GFXKey key; + Thing *t; + int vertmode; + int linemode; + int things; + + TRACE; + + scale=25; + cx=0; + cy=0; + + done=FALSE; + redraw=TRUE; + linemode=TRUE; + vertmode=TRUE; + things=TRUE; + + while(!done) + { + if (redraw) + { + min_x=cx-(SCRW/2)*scale; + min_y=cy-(SCRH/2)*scale; + + GFX_clear(BLACK); + + if (things) + for(f=0;fthing);f++) + { + t=MapElem(m->thing,f); + + GFX_fcircle((t->x-min_x)/scale, + (-t->y-min_y)/scale,8/scale,V_RGB(200,0,0)); + } + + if (linemode) + for(f=0;flinedef);f++) + { + l=MapElem(m->linedef,f); + v1=MapElem(m->vertex,l->from); + v2=MapElem(m->vertex,l->to); + + GFX_line((v1->x-min_x)/scale, + (-v1->y-min_y)/scale, + (v2->x-min_x)/scale, + (-v2->y-min_y)/scale,GREY(128)); + } + + if (vertmode) + for(f=0;fvertex);f++) + { + v1=MapElem(m->vertex,f); + + GFX_plot((v1->x-min_x)/scale, + (-v1->y-min_y)/scale,WHITE); + } + + GuiDrawInfoBox("Preview Map",1,1,FALSE, + "Map : %s|" + "Scale : %d|" + "X : %d|" + "Y : %d|" + "Linedefs : %s|" + "Vertexes : %s|" + "Things : %s|" + " |" + "Press F1 for help",name,scale,cx,cy, + YESNO(linemode), + YESNO(vertmode), + YESNO(things)); + + GFX_redraw(); + } + + GFX_waitkey(&key); + + redraw=TRUE; + + switch(key.code) + { + case GFX_ESC: + done=TRUE; + break; + + case GFX_DOWN: + cy+=scale*(key.shift ? 20 : 1); + break; + + case GFX_UP: + cy-=scale*(key.shift ? 20 : 1); + break; + + case GFX_RIGHT: + cx+=scale*(key.shift ? 20 : 1); + break; + + case GFX_LEFT: + cx-=scale*(key.shift ? 20 : 1); + break; + + case GFX_PGUP: + if (++scale>32) + scale=32; + break; + + case GFX_PGDN: + if (--scale==0) + scale=1; + break; + + case GFX_ASCII: + switch(toupper(key.ascii)) + { + case 'L': + linemode=!linemode; + break; + case 'V': + vertmode=!vertmode; + break; + case 'T': + things=!things; + break; + default: + break; + } + break; + + case GFX_F1: + GuiInfoBox("HELP", + "Cursor keys - move map|" + "Cursor keys + shift - move map quickly|" + "Page Down - reduce scale|" + "Page Up - increase scale|" + "L (toggle) - draw linedefs|" + "V (toggle) - draw vertex points|" + "T (toggle) - draw things|" + "ESC - quit"); + break; + + default: + redraw=FALSE; + break; + } + } +} + + +void EditLoad(WadMap *map) +{ + int f; + Vertex *v; + Linedef *l; + Sector *s; + Thing *t; + EditVert *ev; + EditLine *el; + EditSect *es; + EditThing *et; + Object o; + int min_x=0,max_x=0,min_y=0,max_y=0; + int find; + + TRACE; + + scale=MAX(0,MIN(32,default_scale)); + + if (MapSize(map->vertex)) + { + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + find=TRUE; + } + else + { + find=FALSE; + ox=-scale*SCRW/2; + oy=scale*SCRH/2; + } + + vertex=MapEmpty(vertex); + linedef=MapEmpty(linedef); + thing=MapEmpty(thing); + sector=MapEmpty(sector); + sidedef=MapEmpty(sidedef); + selected=ListEmpty(selected); + + switch(default_edit_mode) + { + case EDIT_SECTOR: + SetEditMode(SECTOR_MODE); + break; + case EDIT_VERTEX: + SetEditMode(VERTEX_MODE); + break; + case EDIT_LINEDEF: + SetEditMode(LINEDEF_MODE); + break; + case EDIT_THING: + SetEditMode(THING_MODE); + break; + case EDIT_MULTI: + SetEditMode(MULTI_MODE); + break; + default: + SetEditMode(SECTOR_MODE); + break; + } + + /* Get vertex from WadMap + */ + for(f=0;fvertex);f++) + { + v=MapElem(map->vertex,f); + + min_x=MIN(min_x,v->x); + min_y=MIN(min_y,v->y); + max_x=MAX(max_x,v->x); + max_y=MAX(max_y,v->y); + + ev=Grab(sizeof(EditVert)); + memcpy(&ev->v,v,sizeof(Vertex)); + ev->l=ListNew(sizeof(int)); + + o.select=SELECT_NONE; + o.data=ev; + + MapAdd(vertex,f,&o); + } + + if (find) + { + if (min_x==max_y) + max_x++; + + if (min_y==max_y) + max_y++; + + ox=min_x+(max_x-min_x)/2; + oy=min_y+(max_y-min_y)/2; + + ox-=scale*SCRW/2; + oy+=scale*SCRH/2; + } + + /* Get sidedefs from WadMap + */ + for(f=0;fsidedef);f++) + { + o.select=SELECT_NONE; + o.data=Copy(MapElem(map->sidedef,f),sizeof(Sidedef)); + MapAdd(sidedef,f,&o); + } + + /* Get linedefs from WadMap, associated sidedefs, vertex pointers and calc + bounding box + */ + for(f=0;flinedef);f++) + { + l=MapElem(map->linedef,f); + el=Grab(sizeof(EditLine)); + + memcpy(&el->l,l,sizeof(Linedef)); + + el->no=f; + el->sr=GETSIDE(l->right); + + if (l->left!=-1) + el->sl=GETSIDE(l->left); + else + el->sl=NULL; + + el->v[0]=GETVERT(l->from); + el->v[1]=GETVERT(l->to); + + IntListUniqAdd(el->v[0]->l,f); + IntListUniqAdd(el->v[1]->l,f); + + LineCalcBounding(el); + + o.select=SELECT_NONE; + o.data=el; + + MapAdd(linedef,f,&o); + } + + /* Get sectors from WadMap + */ + for(f=0;fsector);f++) + { + s=MapElem(map->sector,f); + es=Grab(sizeof(EditSect)); + + memcpy(&es->s,s,sizeof(Sector)); + + es->no=f; + es->v=ListNew(sizeof(Short)); + es->sr=ListNew(sizeof(EditLine *)); + es->sl=ListNew(sizeof(EditLine *)); + es->all=ListNew(sizeof(EditLine *)); + + o.select=SELECT_NONE; + o.data=es; + + SectorCalcContaining(f,es); + SectorCalcBounding(es); + + MapAdd(sector,f,&o); + } + + /* Get things from WadMap + */ + for(f=0;fthing);f++) + { + t=MapElem(map->thing,f); + et=Grab(sizeof(EditThing)); + memcpy(&et->t,t,sizeof(Thing)); + o.select=SELECT_NONE; + o.data=et; + MapAdd(thing,f,&o); + } + + /* Set up multi map if default mode is MULTI mode + */ + if (default_edit_mode==EDIT_MULTI) + GenerateMultiMap(); +} + + +void EditSave(WadMap *map) +{ + int f; + Object *o; + EditVert *v; + EditThing *t; + EditSect *s; + EditLine *l; + + TRACE; + + MapEmpty(map->linedef); + MapEmpty(map->sidedef); + MapEmpty(map->thing); + MapEmpty(map->vertex); + MapEmpty(map->sector); + + for(f=0;fvertex,f,&(v->v)); + } + + /* Sidedefs are the only edit object stored fully in DOOM format + */ + for(f=0;fsidedef,f,o->data); + } + + for(f=0;flinedef,f,&(l->l)); + } + + for(f=0;fthing,f,&(t->t)); + } + + for(f=0;fsector,f,&(s->s)); + } +} + + +void EditLoop(void) +{ + GFXEvent ev; + + TRACE; + + GFX_bounce(); + FullRedraw(); + quit=FALSE; + + while(!quit) + { + GFX_redraw(); + GFX_await_input_full(&ev); + + new_selection=FALSE; + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleKey(ev.key); + break; + + case GFX_MOUSE_EVENT: + HandleMouse(ev.mouse); + break; + + default: + break; + } + } +} + + +void EditCompact(void) +{ + Map new_t,new_v,new_l,new_s,new_si; + int f; + int r; + int i; + Object o; + Object *oo; + EditLine *l; + EditSect *s; + EditVert *v; + Sidedef *side; + + TRACE; + + ClearSelection(); + + new_t=MapNew(sizeof(Object)); + new_v=MapNew(sizeof(Object)); + new_l=MapNew(sizeof(Object)); + new_s=MapNew(sizeof(Object)); + new_si=MapNew(sizeof(Object)); + + /* Compress linedef + */ + i=0; + for(f=0;f=0;f--) + { + memcpy(&o,MapElem(sidedef,f),sizeof(Object)); + + if (o.data) + { + i--; + MapAdd(new_si,i,&o); + } + else + for(r=0;rdata; + + if (l->l.left>=f) + l->l.left--; + + if (l->l.right>=f) + l->l.right--; + } + } + + /* Compress sectors + */ + i=0; + for(f=0;fall))) + i++; + } + + for(f=MapSize(sector)-1;f>=0;f--) + { + memcpy(&o,MapElem(sector,f),sizeof(Object)); + + s=o.data; + + if ((o.data)&&(ListSize(s->all))) + { + i--; + MapAdd(new_s,i,&o); + } + else + { + if (o.data) + Release(o.data); + + for(r=0;rsector>=f) + side->sector--; + } + } + } + + /* Compress vertexes (deleting unused ones first) + */ + for(f=0;fdata) + { + v=oo->data; + + if (ListSize(v->l)==0) + { + ListClear(v->l); + Release(oo->data); + oo->data=NULL; + } + } + } + + i=0; + for(f=0;f=0;f--) + { + memcpy(&o,MapElem(vertex,f),sizeof(Object)); + + if (o.data) + { + i--; + MapAdd(new_v,i,&o); + } + else + for(r=0;rdata; + + if (l->l.from>=f) + l->l.from--; + + if (l->l.to>=f) + l->l.to--; + } + } + + for(r=0;rdata; + + l->v[0]=VERTFROM(new_v,l->l.from); + l->v[1]=VERTFROM(new_v,l->l.to); + } + + /* Renumber items that remember their own number + */ + for(f=0;fdata; + s->no=f; + } + + for(f=0;fdata; + l->no=f; + } + + /* Save new maps + */ + MapClear(vertex); + MapClear(linedef); + MapClear(sector); + MapClear(thing); + MapClear(sidedef); + + vertex=new_v; + linedef=new_l; + sector=new_s; + thing=new_t; + sidedef=new_si; + + /* Reset current edit set + */ + switch(edit_mode) + { + case SECTOR_MODE: + map=sector; + break; + case LINEDEF_MODE: + map=linedef; + break; + case THING_MODE: + map=thing; + break; + case VERTEX_MODE: + map=vertex; + break; + } + + /* Recalc sidedef pointers in linedefs + */ + for(f=0;fl.left!=-1) + l->sl=GETSIDE(l->l.left); + else + l->sl=NULL; + + if (l->l.right!=-1) + l->sr=GETSIDE(l->l.right); + else + l->sr=NULL; + } + + /* Recalc vertex containing lists + */ + for(f=0;fl); + + for(f=0;fv[0]->l,f); + IntListUniqAdd(l->v[1]->l,f); + } + + /* Recalc sector containing values + */ + SectorCalcContainingAll(); +} + + +/* END OF FILE */ diff --git a/edit.h b/edit.h new file mode 100644 index 0000000..56c11df --- /dev/null +++ b/edit.h @@ -0,0 +1,70 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor definitions + + Note that the lindefs, vertices, etc here are copied from the WadMap + loaded prior to editting. They are then reconverted back to the WadMap + for saving. + + $Id$ + +*/ + +#ifndef _EDIT_H +#define _EDIT_H + +#include "wad.h" + +/* Inform the editor of the screen size +*/ +void EditSetScreen(int w,int h); + + +/* Preview a rough map from a passed WadMap +*/ +void EditPreviewWadMap(char *name,WadMap *map); + + +/* Load in the editor data from a WadMap. Clears the current editor state. +*/ +void EditLoad(WadMap *map); + + +/* Save the editor data back into the WadMap +*/ +void EditSave(WadMap *map); + + +/* Editor loop +*/ +void EditLoop(void); + + +/* Compact the various objects, updating references as required. +*/ +void EditCompact(void); + +#endif + + +/* END OF FILE */ diff --git a/editcord.c b/editcord.c new file mode 100644 index 0000000..da3097f --- /dev/null +++ b/editcord.c @@ -0,0 +1,225 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor co-ordinate utilities + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include + +#include "texture.h" +#include "editvar.h" + +/* ---------------------------------------- MAP DRAWING AND POSITION FUNCTIONS +*/ +int SnapX(int x) +{ + TRACE; + + if (!grid_lock) + return(x); + + if (x>=0) + return (((x+grid_size/2)/grid_size)*grid_size); + else + return (((x-grid_size/2)/grid_size)*grid_size); +} + +int SnapY(int y) +{ + TRACE; + + if (!grid_lock) + return(y); + + if (y>=0) + return (((y+grid_size/2)/grid_size)*grid_size); + else + return (((y-grid_size/2)/grid_size)*grid_size); +} + + +int Len(int x1,int y1,int x2,int y2) +{ + double a,b,c; + + TRACE; + + x2-=x1; + y2-=y1; + x2=ABS(x2); + y2=ABS(y2); + + if (!x2) + return(y2); + else if (!y2) + return(x2); + + a=x2*x2; + b=y2*y2; + c=sqrt(a+b); + return((int)c); +} + + +/* Many thanks to Mathew Wilson (www.mjwilson.demon.co.uk) for this routine +*/ +int LinesCross(int x1_1,int y1_1,int x1_2,int y1_2, + int x2_1,int y2_1,int x2_2,int y2_2) +{ + double x0,y0,x1,y1,u0,v0,u1,v1; + double t; + double m,l; + + x0=(double)x1_1; + y0=(double)y1_1; + u0=(double)x1_2-x1_1; + v0=(double)y1_2-y1_1; + + x1=(double)x2_1; + y1=(double)y2_1; + u1=(double)x2_2-x2_1; + v1=(double)y2_2-y2_1; + + /* Find 1st divisor (to check for zero) + */ + t=(u1*v0)-(v1*u0); + + if (t==0.0) + return(FALSE); + + m=(v0*(x0-x1)-u0*(y0-y1))/t; + + l=(v1*(x0-x1)-u1*(y0-y1))/t; + + if ((l>=0.0)&&(l<=1.0)&&(m>=0.0)&&(m<=1.0)) + return(TRUE); + + return(FALSE); +} + + +int CalcTextureWidth(DirName u,DirName m,DirName l) +{ + int a,b,c; + int w=99999; + + TRACE; + + TextureSize(u,&a,NULL); + TextureSize(m,&b,NULL); + TextureSize(l,&c,NULL); + + if ((a)&&(amin_x=MIN(l->v[0]->v.x,l->v[1]->v.x); + l->max_x=MAX(l->v[0]->v.x,l->v[1]->v.x); + l->min_y=MIN(l->v[0]->v.y,l->v[1]->v.y); + l->max_y=MAX(l->v[0]->v.y,l->v[1]->v.y); +} + + +void SectorCalcBounding(EditSect *s) +{ + Iterator i; + Short *f; + EditVert *v; + + TRACE; + + s->min_x=32000; + s->min_y=32000; + s->max_x=-32000; + s->max_y=-32000; + i=ListIterator(s->v); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + s->min_x=MIN(s->min_x,v->v.x); + s->max_x=MAX(s->max_x,v->v.x); + s->min_y=MIN(s->min_y,v->v.y); + s->max_y=MAX(s->max_y,v->v.y); + + i=IteratorNext(i); + } +} + + +int LineOnDisplay(EditLine *l) +{ + TRACE; + + /* Remember: DOOM Y positions are the reverse of the order on screen + */ + return ((MapToX(l->min_x)max_x)>=0)&& + (MapToY(l->max_y)min_y)>=0)); +} + + +int SectorOnDisplay(EditSect *s) +{ + TRACE; + + /* Remember: DOOM Y positions are the reverse of the order on screen + */ + return ((MapToX(s->min_x)max_x)>=0)&& + (MapToY(s->max_y)min_y)>=0)); +} + + +int PointOnDisplay(int x,int y,int r) +{ + TRACE; + + /* Remember: DOOM Y positions are the reverse of the order on screen + */ + return ((MapToX(x+r)>=0)&&(MapToX(x-r)=0)&&(MapToY(y+r) + + +/* ---------------------------------------- SECTOR CREATION PRIVATE ROUTINES +*/ +static void SwapTexture(DirName a, DirName b) +{ + DirName t; + + strcpy(t,a); + strcpy(a,b); + strcpy(b,t); +} + + +static List ReverseList(List l) +{ + Iterator i; + List new; + + new=ListNew(sizeof(int)); + + i=ListIterator(l); + + while(i) + { + ListInsert(new,IteratorData(i)); + i=IteratorNext(i); + } + + return(new); +} + + +static List CopyList(List l) +{ + Iterator i; + List new; + + new=ListNew(sizeof(int)); + + i=ListIterator(l); + + while(i) + { + ListAppend(new,IteratorData(i)); + i=IteratorNext(i); + } + + return(new); +} + + +/* ---------------------------------------- SECTOR CREATION ROUTINES +*/ +int CreateUnboundSector(int special,int floor,int ceiling,int light,int tag, + DirName floor_t,DirName ceiling_t) +{ + Object o; + EditSect *s; + int sn; + + TRACE; + + sn=MapSize(sector); + + s=Grab(sizeof(EditSect)); + + s->no=sn; + s->s.special=special; + s->s.floor=floor; + s->s.ceiling=ceiling; + s->s.light=light; + strcpy(s->s.floor_t,floor_t); + strcpy(s->s.ceiling_t,ceiling_t); + s->v=ListNew(sizeof(Short)); + s->sr=ListNew(sizeof(EditLine *)); + s->sl=ListNew(sizeof(EditLine *)); + s->all=ListNew(sizeof(EditLine *)); + s->min_x=s->min_y=s->max_x=s->max_y=0; + + o.select=SELECT_NONE; + o.data=s; + MapAdd(sector,sn,&o); + + return(sn); +} + +int CreateSector(List in_v) +{ + List v; + Iterator i; + int *f; + int from; + int to; + int type; + int flag; + int two; + int first; + int sect; + int wr,wl; + int oxr,oxl; + DirName sr_upper,sr_middle,sr_lower; + DirName sl_upper,sl_middle,sl_lower; + EditSect *s; + EditVert *v1,*v2; + int special,floor,ceiling,light; + int in_floor,in_ceiling,in_light; + DirName floor_t,ceiling_t; + int in_sector,new_sec; + int swap; + int nl; + int style_flag; + List left_offset; + + TRACE; + + /* Check enough vertexes + */ + if (ListSize(in_v)<3) + { + GuiInfoBox("ERROR","Need 3 or more vertices|" + "to create a sector"); + FullRedraw(); + return(FALSE); + } + + /* Check all points lie either inside the same sector or outside a sector + */ + in_sector=-1; + + i=ListIterator(in_v); + + f=IteratorData(i); + v1=GETVERT(*f); + in_sector=SectorHoldingPoint(v1->v.x,v1->v.y); + i=IteratorNext(i); + + /* Check to see if the vertices are all inside the same sector. If some or + all of the vertices lie outside the same sector then the sector is + assumed to not be in another one + */ + while(i) + { + f=IteratorData(i); + v1=GETVERT(*f); + + new_sec=SectorHoldingPoint(v1->v.x,v1->v.y); + + if ((in_sector!=-1)&&(new_sec!=in_sector)) + in_sector=-1; + + i=IteratorNext(i); + } + + if (in_sector!=-1) + { + s=GETSECT(in_sector); + light=in_light=s->s.light; + floor=in_floor=s->s.floor; + ceiling=in_ceiling=s->s.ceiling; + } + else + { + s=NULL; + light=in_light=default_light_level; + floor=in_floor=default_floor_height; + ceiling=in_ceiling=default_ceiling_height; + } + + special=0; + + /* Now get the linedef and sector values + */ + if (!GetSectorValues(&type,&flag,&two, + &floor,&ceiling,&light, + in_floor,in_ceiling, + &style_flag, + floor_t,ceiling_t, + sr_upper,sr_middle,sr_lower, + sl_upper,sl_middle,sl_lower)) + return(FALSE); + + /* See if the sector is inside another sector and see if the user wants + the new sectors right sidedefs pointing out into the containing sector + */ + if (in_sector!=-1) + swap=YesNo("Sector in another sector. Make RIGHT SIDEDEF point out?"); + else + swap=FALSE; + + + /* Past here the user cannot cancel the create operation, so now create + a copy of the vertex list (reversed if necessary) and reverse the + textures as necessary + */ + if (swap) + { + if (two) + { + SwapTexture(sr_upper,sl_upper); + SwapTexture(sr_middle,sl_middle); + SwapTexture(sr_lower,sl_lower); + } + + v=ReverseList(in_v); + } + else + v=CopyList(in_v); + + /* Add either lower/upper unpegged according to the sector style flags + */ + if (style_flag&SSTYLE_UPPER_PEG) + flag|=upper_peg_mask; + + if (style_flag&SSTYLE_LOWER_PEG) + flag|=lower_peg_mask; + + /* Create list for left offsets if needed + */ + if (two) + left_offset=ListNew(sizeof(int)); + else + left_offset=NULL; + + /* Calc texture widths and get a new sector number + */ + oxr=0; + oxl=0; + + wr=CalcTextureWidth(sr_upper,sr_middle,sr_lower); + + if (two) + wl=CalcTextureWidth + (sl_upper,sl_middle,sl_lower); + else + wl=0; + + if (swap) + { + sect=in_sector; + in_sector=CreateUnboundSector + (special,floor,ceiling,light,0, + floor_t,ceiling_t); + } + else + sect=CreateUnboundSector + (special,floor,ceiling,light,0, + floor_t,ceiling_t); + + i=ListIterator(v); + + memcpy(&to,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + first=to; + + while(i) + { + from=to; + memcpy(&to,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + + nl=CreateNewLinedef + (from,to, + flag,type,0,two, + oxr,0,sect, + sr_upper,sr_middle,sr_lower, + oxl,0,in_sector, + sl_upper,sl_middle,sl_lower); + + v1=GETVERT(from); + v2=GETVERT(to); + + IntListUniqAdd(v1->l,nl); + IntListUniqAdd(v2->l,nl); + + if (wr) + oxr=(oxr+Len(v1->v.x,v1->v.y, + v2->v.x,v2->v.y))%wr; + + /* The left sidedef has the offsets coming from the opposite direction + so have to be applied in reverse once all the lines have been + created. Damn, wish I'd realised that earlier + */ + if (two) + ListInsert(left_offset,&nl); + } + + /* Create the line to close the polygon + */ + nl=CreateNewLinedef(to,first, + flag,type,0,two, + oxr,0,sect, + sr_upper,sr_middle,sr_lower, + oxl,0,in_sector, + sl_upper,sl_middle,sl_lower); + + v1=GETVERT(to); + v2=GETVERT(first); + + IntListUniqAdd(v1->l,nl); + IntListUniqAdd(v2->l,nl); + + if (two) + ListInsert(left_offset,&nl); + + /* Apply the left offsets + */ + if (two) + { + EditLine *l; + + i=ListIterator(left_offset); + + while(i) + { + f=IteratorData(i); + + l=GETLINE(*f); + + if (wl) + oxl=(oxl+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%wl; + + l->sl->x=oxl; + + i=IteratorNext(i); + } + + ListClear(left_offset); + } + + /* Calc sector bounds + */ + if (swap) + s=GETSECT(in_sector); + else + s=GETSECT(sect); + + SectorCalcContainingAll(); + SectorCalcBounding(s); + + ListClear(v); + + /* Check for mergeable LINEDEFS + */ + i=ListIterator(s->v); + + while(i) + { + Short *s; + + s=IteratorData(i); + CheckMergeLinedef(GETVERT(*s)); + i=IteratorNext(i); + } + + /* Recalc containing in case LINEDEFS where merged + */ + SectorCalcContainingAll(); + + return(TRUE); +} + + +/* END OF FILE */ diff --git a/editdraw.c b/editdraw.c new file mode 100644 index 0000000..0ec30a7 --- /dev/null +++ b/editdraw.c @@ -0,0 +1,346 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + General editor drawing routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include + +#include "editvar.h" + + +/* ---------------------------------------- DRAWING FUNCTIONS +*/ +void DrawArrow(int x1,int y1,int x2,int y2,int c) +{ + int dx,dy; + double ang; + int x,y; + + TRACE; + + dx=x1-x2; + dy=y1-y2; + + /* Calc angle that the line is at + */ + if (dx==0) + if (dy<0) + ang=RAD(0); + else + ang=RAD(180); + else if (dy==0) + if (dx<0) + ang=RAD(90); + else + ang=RAD(270); + else + { + ang=atan((double)dx/(double)dy); + + if (dy>0) + ang-=RAD(180); + } + + MapLine(x1,y1,x2,y2,c); + + x=(int)(x2-sin(ang-RAD(25))*12.0); + y=(int)(y2-cos(ang-RAD(25))*12.0); + MapLine(x2,y2,x,y,c); + + x=(int)(x2-sin(ang+RAD(25))*12.0); + y=(int)(y2-cos(ang+RAD(25))*12.0); + MapLine(x2,y2,x,y,c); +} + + +void DrawGrid(void) +{ + int c; + + TRACE; + + if (!grid_onoff) + return; + + agrid=grid_size; + + while((agrid/scale)<8) + agrid*=2; + + c=YToMap(0); + + while(c%agrid) + c++; + + while(c>YToMap(SCRH-1)) + { + GFX_line(0,MapToY(c),SCRW-1,MapToY(c),GRIDCOL); + c-=agrid; + } + + c=ox; + while(c%agrid) + c--; + + while(cdata; + + if (l) + { + /* LINEDEFS can move if we're in certain edit modes + */ + if (edit_mode!=THING_MODE) + LineCalcBounding(l); + + if (edit_mode!=SECTOR_MODE) + if (LineOnDisplay(l)) + switch(edit_mode) + { + case VERTEX_MODE: + case MULTI_MODE: + DrawArrow(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y,LINECOL); + break; + + case LINEDEF_MODE: + DrawObject_LINEDEF(l,o->select); + break; + + case THING_MODE: + MapLineD(l,LINECOL); + break; + } + } + } + + if ((edit_mode==VERTEX_MODE)||(edit_mode==MULTI_MODE)) + for(f=0;fdata; + + if (v) + if (PointOnDisplay(v->v.x,v->v.y,vertex_rad)) + DrawObject_VERTEX(v,o->select); + } + + /* Sectors are drawn in a number of passes as selected sectors can quite + easily be overdrtawn by unselected ones + */ + if (edit_mode==SECTOR_MODE) + { + for(f=0;fdata; + if (s) + { + SectorCalcBounding(s); + + if (SectorOnDisplay(s)) + DrawObject_SECTOR(s,o->select); + } + } + + i=ListIterator(selected); + + while(i) + { + sv=IteratorData(i); + + o=MapElem(sector,*sv); + s=o->data; + if (s) + { + SectorCalcBounding(s); + + if (SectorOnDisplay(s)) + DrawObject_SECTOR(s,o->select); + } + + i=IteratorNext(i); + } + + /* This slightly dodgy check is because sectors (as explained) do not + order themselves very well. This check wil put the currently + hovered-over object back on top of the display. + */ + if (current!=-1) + { + o=MapElem(sector,current); + s=o->data; + + if (s) + { + SectorCalcBounding(s); + + if (SectorOnDisplay(s)) + DrawObject_SECTOR(s,o->select); + } + } + } + + for(f=0;fdata; + + if (t) + if ((edit_mode==THING_MODE)||(edit_mode==MULTI_MODE)) + { + if (PointOnDisplay(t->t.x,t->t.y,ThingRadius(t->t.type,NULL))) + DrawObject_THING(t,o->select); + } + else + if (PointOnDisplay(t->t.x,t->t.y,8)) + { + MapLine(t->t.x-8,t->t.y,t->t.x+8,t->t.y,THINGCOL); + MapLine(t->t.x,t->t.y-8,t->t.x,t->t.y+8,THINGCOL); + } + } +} + + +void DrawHeader(void) +{ +#ifdef DEBUG + static int chk=TRUE; + static int db=FALSE; +#endif + + TRACE; + + GFX_frect(0,0,SCRW,FH*2,BLUE); + + GFX_print(0,0,WHITE,"Mode: %-8s Pos: %d,%d", + edit_str[edit_mode],XToMap(ms.x),YToMap(ms.y)); + + if (grid_onoff) + GFX_print(SCRW/2,0,WHITE,"Scale: %-2d Lock: %-3s Grid : %d/%d", + scale,YESNO(grid_lock),grid_size,agrid); + else + GFX_print(SCRW/2,0,WHITE,"Scale: %-2d Lock: %-3s Grid : %d", + scale,YESNO(grid_lock),grid_size); + + DrawObjectHeader(); + +#ifdef DEBUG + + /* Debug + */ + if (chk) + { + if ((getenv("VIDOOM_VDEBUG"))&&(!strcmp(getenv("VIDOOM_VDEBUG"),"Y"))) + db=TRUE; + else + db=FALSE; + + chk=FALSE; + } + + if (db) + { + static char ds[128]; + int y; + Iterator i; + int *f; + + GFX_frect(0,FH*2,SCRW,FH*2,RED); + GFX_print(0,FH*2,WHITE,"ox=%d oy=%d " + "SectorHoldingPoint(%d,%d)=%d " + "ListSize(selected)=%d", + ox,oy, + XToMap(ms.x),YToMap(ms.y), + SectorHoldingPoint(XToMap(ms.x),YToMap(ms.y)), + ListSize(selected)); + + i=ListIterator(selected); + ds[0]=0; + y=FH*3; + + while(i) + { + f=IteratorData(i); + + if (strlen(ds)>70) + { + GFX_print(0,y,WHITE,ds); + ds[0]=0; + y+=FH; + } + + sprintf(ds+strlen(ds),"%d, ",*f); + + i=IteratorNext(i); + } + + strcat(ds,""); + GFX_print(0,y,WHITE,"%s",ds); + } +#endif +} + + +void FullRedraw(void) +{ + TRACE; + + GFX_mouse(&ms.x,&ms.y); + GFX_clear(BLACK); + + DrawGrid(); + DrawMap(); + DrawObjectInfo(); + DrawHeader(); +} + + +/* END OF FILE */ diff --git a/editevnt.c b/editevnt.c new file mode 100644 index 0000000..d87deeb --- /dev/null +++ b/editevnt.c @@ -0,0 +1,991 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor generic event handler definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include + +#include "editvar.h" + + +/* ---------------------------------------- PREDICATE FUNCTIONS +*/ +static int PredSelected(void *a,void *b) +{ + int *i1,*i2; + + i1=a; + i2=b; + return(*i1==*i2); +} + + +/* ---------------------------------------- OBJECT LOCATORS +*/ +void GenericCheckMouse(void) +{ + static PLAT_MENU gen_menu[]={{"Insert",TM_INSERT},{NULL,0}}; + Object *o; + int f; + Iterator i; + int temp_select=FALSE; + int map_x,map_y; + + TRACE; + + map_x=XToMap(ms.x); + map_y=YToMap(ms.y); + + /* If an object is already selected then see if it is still over it + */ + if (current!=-1) + { + o=MapElem(map,current); + + if (!(PositionOnObject(map_x,map_y,o->data))) + { + if (o->select!=SELECT_SELECTED) + SetSelect(current,SELECT_NONE); + + current=-1; + + DrawObject(o->data,o->select); + DrawObjectInfo(); + } + } + + if (current==-1) + for(f=0;(fdata) + { + if (PositionOnObject(map_x,map_y,o->data)) + { + current=f; + if (o->select!=SELECT_SELECTED) + SetSelect(current,SELECT_OVER); + + DrawObject(o->data,o->select); + DrawObjectInfo(); + } + } + } + + /* Do selection box if shift pressed + */ + if ((ms.b&GFX_BUTLEFT)&&(ms.shift)) + { + GFXEvent e; + int x1,y1,x2,y2; + + GFX_set_XOR_mode(); + + do + { + int w,h; + + do + { + GFX_await_input_full(&e); + } while(e.type!=GFX_MOUSE_EVENT); + + w=e.mouse.x-ms.x; + h=e.mouse.y-ms.y; + + GFX_rect(ms.x,ms.y,w,h,WHITE); + GFX_redraw(); + GFX_rect(ms.x,ms.y,w,h,WHITE); + + } while(e.mouse.b&GFX_BUTLEFT); + + GFX_clear_XOR_mode(); + GFX_redraw(); + + x1=MIN(XToMap(ms.x),XToMap(e.mouse.x)); + y1=MIN(YToMap(ms.y),YToMap(e.mouse.y)); + x2=MAX(XToMap(ms.x),XToMap(e.mouse.x)); + y2=MAX(YToMap(ms.y),YToMap(e.mouse.y)); + + if (!(e.mouse.ctrl|ms.ctrl)) + ClearSelection(); + + SelectBox(x1,y1,x2,y2); + + memcpy(&ms,&e.mouse,sizeof(e.mouse)); + FullRedraw(); + } + else + /* Handle left (select) and right (menu) buttons + */ + { + if (ms.b&GFX_BUTLEFT) + if (current==-1) + { + if (!ms.ctrl) + { + ClearSelection(); + FullRedraw(); + } + } + else + { + if (ms.ctrl) + { + o=MapElem(map,current); + + if (o->select==SELECT_SELECTED) + { + if ((i=ListFindElem(selected,PredSelected,¤t))) + { + i=IteratorDelete(i); + i=IteratorClear(i); + } + + SetSelect(current,SELECT_NONE); + DrawObject(o->data,SELECT_NONE); + } + else + { + SetSelect(current,SELECT_SELECTED); + ListAppend(selected,¤t); + DrawObject(o->data,SELECT_SELECTED); + } + } + else + { + ClearSelectionLeaveCurrent(); + SetSelect(current,SELECT_SELECTED); + ListAppend(selected,¤t); + FullRedraw(); + } + } + + /* If the middle or right button is pressed over an object, check + adding the object to the selected list + */ + if ((ms.b&(GFX_BUTRIGHT|GFX_BUTMIDDLE))&&(current!=-1)) + { + /* If there is currently nothing selected then this object is + selected for the duration of the move or menu operation + */ + if (ListSize(selected)==0) + { + temp_select=TRUE; + ListAppend(selected,¤t); + o=MapElem(map,current); + SetSelect(current,SELECT_SELECTED); + DrawObject(o->data,o->select); + } + else if (hover_select!=HOVER_NONE) + { + o=MapElem(map,current); + + if (o->select!=SELECT_SELECTED) + { + if (hover_select==HOVER_SINGLE) + ClearSelectionLeaveCurrent(); + + o=MapElem(map,current); + SetSelect(current,SELECT_SELECTED); + ListAppend(selected,¤t); + FullRedraw(); + } + } + } + + + /* If the middle button is pressed move the object. This is provided as + a shortcut to the menu move option + */ + if ((ms.b&GFX_BUTMIDDLE)&&(ListSize(selected))) + MoveObject(); + + /* If the right button is pressed selected the editting options + */ + if (ms.b&GFX_BUTRIGHT) + if (ListSize(selected)) + ObjectMenu(); + else + switch(GUI_menu(typename,ms.x,ms.y,gen_menu,GUI_CANCEL)) + { + case TM_INSERT: + ObjectInsert(); + break; + + default: + break; + } + + if ((temp_select)&&(!new_selection)) + { + ClearSelection(); + FullRedraw(); + } + } +} + + +/* ---------------------------------------- INPUT HANDLERS +*/ +void SetEditMode(int mode) +{ + TRACE; + + ClearSelection(); + current=-1; + + edit_mode=mode; + + switch(mode) + { + case SECTOR_MODE: + typename="Sector"; + map=sector; + PositionOnObject=PositionOnObject_SECTOR; + SelectBox=SelectBox_SECTOR; + SelectByType=SelectByType_SECTOR; + DrawObject=DrawObject_SECTOR; + DrawObjectInfo=DrawObjectInfo_SECTOR; + DrawObjectHeader=DrawObjectHeader_SECTOR; + MoveObject=MoveObject_SECTOR; + RotateObject=RotateObject_SECTOR; + ScaleObject=ScaleObject_SECTOR; + SetTagObject=SetTagObject_SECTOR; + LocateObject=LocateObject_SECTOR; + ObjectMenu=ObjectMenu_SECTOR; + ObjectInsert=ObjectInsert_SECTOR; + ObjectDelete=ObjectDelete_SECTOR; + ObjectKey=ObjectKey_SECTOR; + ObjectHasTag=ObjectHasTag_SECTOR; + SetSelect=SetSelect_GENERIC; + break; + + case LINEDEF_MODE: + typename="Linedef"; + map=linedef; + PositionOnObject=PositionOnObject_LINEDEF; + SelectBox=SelectBox_LINEDEF; + SelectByType=SelectByType_LINEDEF; + DrawObject=DrawObject_LINEDEF; + DrawObjectInfo=DrawObjectInfo_LINEDEF; + DrawObjectHeader=DrawObjectHeader_LINEDEF; + MoveObject=MoveObject_LINEDEF; + RotateObject=RotateObject_LINEDEF; + ScaleObject=ScaleObject_LINEDEF; + SetTagObject=SetTagObject_LINEDEF; + LocateObject=LocateObject_LINEDEF; + ObjectMenu=ObjectMenu_LINEDEF; + ObjectInsert=ObjectInsert_LINEDEF; + ObjectDelete=ObjectDelete_LINEDEF; + ObjectKey=ObjectKey_LINEDEF; + ObjectHasTag=ObjectHasTag_LINEDEF; + SetSelect=SetSelect_GENERIC; + break; + + case VERTEX_MODE: + typename="Vertex"; + map=vertex; + PositionOnObject=PositionOnObject_VERTEX; + SelectBox=SelectBox_VERTEX; + SelectByType=SelectByType_VERTEX; + DrawObject=DrawObject_VERTEX; + DrawObjectInfo=DrawObjectInfo_VERTEX; + DrawObjectHeader=DrawObjectHeader_VERTEX; + MoveObject=MoveObject_VERTEX; + RotateObject=RotateObject_VERTEX; + ScaleObject=ScaleObject_VERTEX; + SetTagObject=SetTagObject_VERTEX; + LocateObject=LocateObject_VERTEX; + ObjectMenu=ObjectMenu_VERTEX; + ObjectInsert=ObjectInsert_VERTEX; + ObjectDelete=ObjectDelete_VERTEX; + ObjectKey=ObjectKey_VERTEX; + ObjectHasTag=ObjectHasTag_VERTEX; + SetSelect=SetSelect_GENERIC; + break; + + case THING_MODE: + typename="Thing"; + map=thing; + PositionOnObject=PositionOnObject_THING; + SelectBox=SelectBox_THING; + SelectByType=SelectByType_THING; + DrawObject=DrawObject_THING; + DrawObjectInfo=DrawObjectInfo_THING; + DrawObjectHeader=DrawObjectHeader_THING; + MoveObject=MoveObject_THING; + RotateObject=RotateObject_THING; + ScaleObject=ScaleObject_THING; + SetTagObject=SetTagObject_THING; + LocateObject=LocateObject_THING; + ObjectMenu=ObjectMenu_THING; + ObjectInsert=ObjectInsert_THING; + ObjectDelete=ObjectDelete_THING; + ObjectKey=ObjectKey_THING; + ObjectHasTag=ObjectHasTag_THING; + SetSelect=SetSelect_GENERIC; + break; + + case MULTI_MODE: + GenerateMultiMap(); + typename="Multimode"; + map=multimap; + PositionOnObject=PositionOnObject_MULTI; + SelectBox=SelectBox_MULTI; + SelectByType=SelectByType_MULTI; + DrawObject=DrawObject_MULTI; + DrawObjectInfo=DrawObjectInfo_MULTI; + DrawObjectHeader=DrawObjectHeader_MULTI; + MoveObject=MoveObject_MULTI; + RotateObject=RotateObject_MULTI; + ScaleObject=ScaleObject_MULTI; + SetTagObject=SetTagObject_MULTI; + LocateObject=LocateObject_MULTI; + ObjectMenu=ObjectMenu_MULTI; + ObjectInsert=ObjectInsert_MULTI; + ObjectDelete=ObjectDelete_MULTI; + ObjectKey=ObjectKey_MULTI; + ObjectHasTag=ObjectHasTag_MULTI; + SetSelect=SetSelect_MULTI; + break; + } + + GenericCheckMouse(); + FullRedraw(); +} + + +/* This handles the keys that should usable in all modes (movement, scale, + grid, etc) +*/ +void HandleMoveKey(GFXKey k, int check_mouse) +{ + int cx,cy; + + TRACE; + + if (k.code!=GFX_ASCII) + switch(k.code) + { + case GFX_DOWN: + oy-=scale*(k.shift ? 60 : 20); + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + case GFX_UP: + oy+=scale*(k.shift ? 60 : 20); + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + case GFX_RIGHT: + ox+=scale*(k.shift ? 60 : 20); + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + case GFX_LEFT: + ox-=scale*(k.shift ? 60 : 20); + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + case GFX_PGDN: + if ((--scale)<1) + scale=1; + else + { + cx=ox+(scale+1)*SCRW/2; + cy=oy-(scale+1)*SCRH/2; + ox=cx-(scale)*SCRW/2; + oy=cy+(scale)*SCRH/2; + } + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + case GFX_PGUP: + if ((++scale)>32) + scale=32; + else + { + cx=ox+(scale-1)*SCRW/2; + cy=oy-(scale-1)*SCRH/2; + ox=cx-(scale)*SCRW/2; + oy=cy+(scale)*SCRH/2; + } + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + default: + break; + } + else + switch(toupper(k.ascii)) + { + case 'G': + grid_onoff=!grid_onoff; + FullRedraw(); + break; + + case 'X': + grid_lock=!grid_lock; + DrawHeader(); + break; + + case 'Q': + grid_size/=2; + if (grid_size<2) + grid_size=2; + FullRedraw(); + break; + + case 'W': + grid_size*=2; + if (grid_size>512) + grid_size=512; + FullRedraw(); + break; + +#ifdef DEBUG + case 'D': + case 'd': + { + static PLAT_MENU debug_menu[]= + { + {"Dump current selection list",1}, + {"Save screen",2}, + {NULL,-1} + }; + + switch(GUI_menu("DEBUG",0,0,debug_menu,-1)) + { + case 1: + { + static char ds[128]; + Iterator i; + int *f; + + Debug(("No selections : %d\n",ListSize(selected))); + + i=ListIterator(selected); + ds[0]=0; + + while(i) + { + f=IteratorData(i); + + if (strlen(ds)>60) + { + Debug(("%s\n",ds)); + ds[0]=0; + } + + sprintf(ds+strlen(ds),"%d, ",*f); + + i=IteratorNext(i); + } + + strcat(ds,""); + Debug(("%s\n",ds)); + } + + break; + + case 2: + { + static int i=0; + char p[10]; + + sprintf(p,"pic%d.bmp",i++); + GFX_save_screen(p); + + } + + break; + + default: + break; + } + + break; + } +#endif + + default: + break; + } +} + + +void HandleKey(GFXKey k) +{ + Object *o; + int f; + + TRACE; + + HandleMoveKey(k,TRUE); + ObjectKey(k); + + if (k.code!=GFX_ASCII) + switch(k.code) + { + case GFX_F1: + GuiInfoBox("HELP (Keys)","%s",general_help_keys); + GuiInfoBox("HELP (Mouse)","%s",general_help_mouse); + FullRedraw(); + break; + + case GFX_F2: + { + char s[128]; + + sprintf(s,"%s Mode Keys",typename); + GuiInfoBox(s,"%s",mode_help[edit_mode]); + FullRedraw(); + break; + } + + case GFX_TAB: + if (k.shift) + SetEditMode(PREV_MODE(edit_mode)); + else + SetEditMode(NEXT_MODE(edit_mode)); + break; + + case GFX_INSERT: + ObjectInsert(); + break; + + case GFX_DELETE: + ObjectDelete(); + break; + + case GFX_F9: + if (k.shift) + { + ListEmpty(selected); + + for(f=0;fdata) + if (o->select==SELECT_SELECTED) + SetSelect(f,SELECT_NONE); + else + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } + else + ClearSelection(); + + FullRedraw(); + break; + + case GFX_F10: + if (k.shift) + { + SelectByType(); + FullRedraw(); + } + else + { + ClearSelection(); + + for(f=0;fdata) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + + FullRedraw(); + } + + break; + + case GFX_F11: + { + static int last_sel=0; + Iterator i; + int *n; + Object *o; + + if (ListSize(selected)) + { + if (k.shift) + last_sel--; + else + last_sel++; + + if (last_sel<0) + last_sel=ListSize(selected)-1; + + if (last_sel>=ListSize(selected)) + last_sel=0; + + i=ListIterator(selected); + + for(f=0;fdata); + } + + IteratorClear(i); + FullRedraw(); + } + break; + } + + case GFX_F3: + MergeWad(); + + /* In Multi mode we must notify the MultiMap that new vertexes + and things have been added. This should always be safe as + new objects are added at the end of the current objects (ie. + holes in the maps are not filled in), so the current + selection is safe. + */ + if (edit_mode==MULTI_MODE) + GenerateMultiMap(); + + break; + + case GFX_F4: + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + MoveObject(); + + if (tmp) + ListEmpty(selected); + } + break; + } + + case GFX_F5: + { + static double last_rot=0.0; + int tmp; + + tmp=TmpAddCurrent(); + + rotate_dialog[D_ROTATE].data.d=last_rot; + + if (ListSize(selected)) + { + if (GUI_dialog("Rotate",D_ROTATE_NO,rotate_dialog)) + { + last_rot=rotate_dialog[D_ROTATE].data.d; + RotateObject(-last_rot); + FullRedraw(); + } + + if (tmp) + ListEmpty(selected); + } + break; + } + + case GFX_F6: + { + static double last_scale=1.0; + int tmp; + + tmp=TmpAddCurrent(); + + scale_dialog[D_SCALE].data.d=last_scale; + + if (ListSize(selected)) + { + if (GUI_dialog("Scale",D_SCALE_NO,scale_dialog)) + { + ScaleObject(last_scale=scale_dialog[D_SCALE].data.d); + FullRedraw(); + } + + if (tmp) + ListEmpty(selected); + } + break; + } + + case GFX_F7: + if (k.shift) + { + static int last_tag=0; + int f; + Object *o; + + tag_dialog[D_TAG].data.i=last_tag; + + if (GUI_dialog("Tag number to select",D_TAG_NO,tag_dialog)) + { + last_tag=tag_dialog[D_TAG].data.i; + + for(f=0;fdata)&&(ObjectHasTag(o->data,last_tag))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + + FullRedraw(); + } + } + else + { + static int last_tag=0; + int tmp; + + tmp=TmpAddCurrent(); + + tag_dialog[D_TAG].data.i=last_tag; + + if (ListSize(selected)) + { + if (GUI_dialog("Tag number",D_TAG_NO,tag_dialog)) + { + SetTagObject(last_tag=tag_dialog[D_TAG].data.i); + DrawObjectInfo(); + } + + if (tmp) + ListEmpty(selected); + } + } + break; + + case GFX_F8: + if (edit_mode!=MULTI_MODE) + { + static int last_no=0; + + objno_dialog[D_OBJNO].data.i=last_no; + + if (GUI_dialog("Object number",D_OBJNO_NO,objno_dialog)) + { + Object *o; + int f; + + f=objno_dialog[D_OBJNO].data.i; + o=MapElem(map,f); + + if ((o)&&(o->data)) + { + last_no=objno_dialog[D_OBJNO].data.i; + + if (k.shift) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + + LocateObject(o->data); + GenericCheckMouse(); + FullRedraw(); + } + else + { + GuiInfoBox("ERROR","Object does not exist"); + FullRedraw(); + } + } + } + break; + + case GFX_ESC: + quit=TRUE; + break; + + default: + break; + } + else + switch(toupper(k.ascii)) + { + case 'R': + FullRedraw(); + break; + + case 'S': + SetEditMode(SECTOR_MODE); + break; + + case 'L': + SetEditMode(LINEDEF_MODE); + break; + + case 'V': + SetEditMode(VERTEX_MODE); + break; + + case 'T': + SetEditMode(THING_MODE); + break; + + case 'C': + SetEditMode(MULTI_MODE); + break; + + case '[': + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + RotateObject(5.0); + + if (tmp) + ListEmpty(selected); + + FullRedraw(); + } + + break; + } + + case ']': + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + RotateObject(-5.0); + + if (tmp) + ListEmpty(selected); + + FullRedraw(); + } + + break; + } + + case '{': + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + ScaleObject(0.90); + + if (tmp) + ListEmpty(selected); + + FullRedraw(); + } + + break; + } + + case '}': + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + ScaleObject(1.10); + + if (tmp) + ListEmpty(selected); + + FullRedraw(); + } + + break; + } + + default: + break; + } +} + + +void HandleMouse(GFXMouse m) +{ + TRACE; + + memcpy(&ms,&m,sizeof(m)); + GenericCheckMouse(); + DrawHeader(); +} + + +/* END OF FILE */ diff --git a/editgui.c b/editgui.c new file mode 100644 index 0000000..afb922d --- /dev/null +++ b/editgui.c @@ -0,0 +1,470 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + General editor GUI routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "editvar.h" +#include "texture.h" +#include "sectors.h" + +#include + +#define TXTPMT(lr,ulm) "Pick " ulm " texture for " lr " sidedef" + + +/* ---------------------------------------- GUI FUNCTIONS +*/ +int GetTexture(char *t,DirName d) +{ + int f; + + TRACE; + + if ((f=GUI_image_picklist(t,texture_picklist,TXT_PICKDEFVAL)) + !=TXT_PICKDEFVAL) + { + strcpy(d,texture_picklist[f].text); + return(TRUE); + } + else + return(FALSE); +} + + +int GetFlat(char *t,DirName d) +{ + int f; + + TRACE; + + if ((f=GUI_image_picklist(t,flat_picklist,TXT_PICKDEFVAL)) + !=TXT_PICKDEFVAL) + { + strcpy(d,flat_picklist[f].text); + return(TRUE); + } + else + return(FALSE); +} + + + +int GetLinedefValues(int set_class, + int r_floor, int l_floor, int r_ceiling, int l_ceiling, + int *type,int *flag,int *two, + DirName sr_upper,DirName sr_middle,DirName sr_lower, + DirName sl_upper,DirName sl_middle,DirName sl_lower) + +{ + TRACE; + + if (set_class) + { + if ((*type=SelectLinedef())==LINEDEF_NULLID) + return(FALSE); + } + else + *type=0; + + if (ChooseLinedefType(flag,two)) + { + if (*two) + { + if (r_floorl_ceiling) + { + if (!GetTexture(TXTPMT("RIGHT","UPPER"),sr_upper)) + return(FALSE); + } + else + strcpy(sr_upper,empty_texture); + + if (ask_middle_on_2sided) + { + if (!GetTexture(TXTPMT("RIGHT","MIDDLE"),sr_middle)) + return(FALSE); + } + else + strcpy(sr_middle,empty_texture); + + if (l_floorr_ceiling) + { + if (!GetTexture(TXTPMT("LEFT","UPPER"),sl_upper)) + return(FALSE); + } + else + strcpy(sl_upper,empty_texture); + + if (ask_middle_on_2sided) + { + if (!GetTexture(TXTPMT("LEFT","MIDDLE"),sl_middle)) + return(FALSE); + } + else + strcpy(sl_middle,empty_texture); + } + else + { + strcpy(sr_upper,empty_texture); + strcpy(sr_lower,empty_texture); + + if (!GetTexture("Pick MIDDLE texture for RIGHT sidedef",sr_middle)) + return(FALSE); + } + + return(TRUE); + } + + return(FALSE); +} + + +int GetSectorValues(int *line_type, int *line_flag, int *two_sided, + int *floor, int *ceiling, int *light, + int in_floor, int in_ceiling, + int *style_flags, + DirName floor_t, DirName ceiling_t, + DirName sr_upper, DirName sr_middle, DirName sr_lower, + DirName sl_upper, DirName sl_middle, DirName sl_lower) +{ + TRACE; + + if ((*line_type=SelectLinedef())==LINEDEF_NULLID) + return(FALSE); + + sector_val_dialog[D_SVAL_LIGHT].data.i=*light; + sector_val_dialog[D_SVAL_FLOOR].data.i=*floor; + sector_val_dialog[D_SVAL_CEILING].data.i=*ceiling; + + if (!GUI_dialog("Values for sector",D_SECTOR_VAL_NO,sector_val_dialog)) + return(FALSE); + + *floor=sector_val_dialog[D_SVAL_FLOOR].data.i; + *ceiling=sector_val_dialog[D_SVAL_CEILING].data.i; + *light=sector_val_dialog[D_SVAL_LIGHT].data.i; + + if (!ChooseLinedefType(line_flag,two_sided)) + return(FALSE); + + if (NoSectorStyles()) + { + if (!ChooseSectorStyle(style_flags,sr_upper,sr_middle,sr_lower, + floor_t,ceiling_t)) + return(FALSE); + + if (*two_sided) + { + strcpy(sl_upper,sr_upper); + strcpy(sl_middle,sr_middle); + strcpy(sl_lower,sr_lower); + + if (*floor>=in_floor) + strcpy(sr_lower,empty_texture); + + if (*ceiling<=in_ceiling) + strcpy(sr_upper,empty_texture); + + if (!ask_middle_on_2sided) + strcpy(sr_middle,empty_texture); + + if (in_floor>=*floor) + strcpy(sl_lower,empty_texture); + + if (in_ceiling<=*ceiling) + strcpy(sl_upper,empty_texture); + + if (!ask_middle_on_2sided) + strcpy(sl_middle,empty_texture); + } + else + { + strcpy(sr_upper,empty_texture); + strcpy(sr_lower,empty_texture); + } + } + else + { + *style_flags=0; + + if (!GetFlat("Choose floor texture",floor_t)) + return(FALSE); + + if (!GetFlat("Choose ceiling texture",ceiling_t)) + return(FALSE); + + if (*two_sided) + { + if (*floorin_ceiling) + { + if (!GetTexture(TXTPMT("RIGHT","UPPER"),sr_upper)) + return(FALSE); + } + else + strcpy(sr_upper,empty_texture); + + if (ask_middle_on_2sided) + { + if (!GetTexture(TXTPMT("RIGHT","MIDDLE"),sr_middle)) + return(FALSE); + } + else + strcpy(sr_middle,empty_texture); + + if (in_floor<*floor) + { + if (!GetTexture(TXTPMT("LEFT","LOWER"),sl_lower)) + return(FALSE); + } + else + strcpy(sl_lower,empty_texture); + + if (in_ceiling>*ceiling) + { + if (!GetTexture(TXTPMT("LEFT","UPPER"),sl_upper)) + return(FALSE); + } + else + strcpy(sl_upper,empty_texture); + + if (ask_middle_on_2sided) + { + if (!GetTexture(TXTPMT("LEFT","MIDDLE"),sl_middle)) + return(FALSE); + } + else + strcpy(sl_middle,empty_texture); + } + else + { + strcpy(sr_upper,empty_texture); + strcpy(sr_lower,empty_texture); + + if (!GetTexture("Pick MIDDLE texture for RIGHT sidedef",sr_middle)) + return(FALSE); + } + } + + return(TRUE); +} + + +int PickPoint(char *p, int *x, int *y, void (*draw)(int *x,int *y), + void (*key)(GFXKey k), + void (*infobox)(char *p)) +{ + GFXEvent e; + int cx,cy; + int done; + int cancel; + + TRACE; + + draw_current_info=FALSE; + FullRedraw(); + + done=FALSE; + cancel=FALSE; + + cx=XToMap(ms.x); + cy=YToMap(ms.y); + + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + cx=SnapX(cx); + cy=SnapY(cy); + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + if (infobox) + infobox(p); + else + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,TRUE, + "Press button to select point|Press ESC to cancel"); + + GFX_redraw(); + + while(!done) + { + GFX_await_input_full(&e); + + switch(e.type) + { + case GFX_MOUSE_EVENT: + + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + memcpy(&ms,&e.mouse,sizeof(e.mouse)); + + if (ms.b) + done=TRUE; + + DrawHeader(); + cx=XToMap(ms.x); + cy=YToMap(ms.y); + + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + cx=SnapX(cx); + cy=SnapY(cy); + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + if (infobox) + infobox(p); + else + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,TRUE, + "Press button to select point|Press ESC to cancel"); + + GFX_redraw(); + + break; + + case GFX_KEY_EVENT: + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + HandleMoveKey(e.key,FALSE); + cx=SnapX(XToMap(ms.x)); + cy=SnapY(YToMap(ms.y)); + + if (key) + key(e.key); + + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + if (infobox) + infobox(p); + else + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,TRUE, + "Press button to select point|Press ESC to cancel"); + + GFX_redraw(); + + if (e.key.code==GFX_ESC) + { + done=TRUE; + cancel=TRUE; + } + + break; + + default: + break; + } + } + + draw_current_info=TRUE; + FullRedraw(); + + *x=cx; + *y=cy; + + return(!cancel); +} + + +int YesNo(char *fmt,...) +{ + static char s[512]; + va_list va; + + va_start(va,fmt); + vsprintf(s,fmt,va); + va_end(va); + + return(GUI_yesno(s)); +} + + +/* END OF FILE */ diff --git a/editilst.c b/editilst.c new file mode 100644 index 0000000..f7a6763 --- /dev/null +++ b/editilst.c @@ -0,0 +1,106 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor integer list routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" + + +/* ---------------------------------------- PRIVATE ROUTINES +*/ + + +/* ---------------------------------------- EXPORTED ROUTINES +*/ +int InIntList(List l, int i) +{ + Iterator li; + int *f; + + li=ListIterator(l); + + while(li) + { + f=IteratorData(li); + + if (*f==i) + { + IteratorClear(li); + return(TRUE); + } + + li=IteratorNext(li); + } + + return(FALSE); +} + + +void IntListUniqAdd(List l, int i) +{ + Iterator li; + int *f; + + li=ListIterator(l); + + while(li) + { + f=IteratorData(li); + + if (*f==i) + { + IteratorClear(li); + return; + } + + li=IteratorNext(li); + } + + ListAppend(l,&i); +} + + +void IntListRm(List l, int i) +{ + Iterator li; + int *f; + + li=ListIterator(l); + + while(li) + { + f=IteratorData(li); + + if (*f==i) + li=IteratorDelete(li); + else + li=IteratorNext(li); + } +} + + +/* END OF FILE */ diff --git a/editline.c b/editline.c new file mode 100644 index 0000000..1efcb7f --- /dev/null +++ b/editline.c @@ -0,0 +1,3322 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor LINEDEF definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include +#include + +#include "editvar.h" +#include "sectors.h" +#include "texture.h" + + +/* ---------------------------------------- MACROS +*/ +#define LinesCrossV(v1,v2,v3,v4) \ + LinesCross ((v1)->v.x,(v1)->v.y,(v2)->v.x,(v2)->v.y, \ + (v3)->v.x,(v3)->v.y,(v4)->v.x,(v4)->v.y) + +#define SetPoint(pt,vt) do {(pt).x=(vt)->v.x;(pt).y=(vt)->v.y;} while(0) + +#define SPLINE_THRESH 1 + +/* This following define relies on the naming of parameters in DoCalcSpline() + and DoCalcLine() +*/ +#define CHECKSTEP(X,Y) do { \ + (*len)++; \ + \ + if (p) \ + if (((*len)%step)==0) \ + { \ + if ((*idx)v[0]->v.x)-(l->v[1]->v.x))/2; + dy=((l->v[0]->v.y)-(l->v[1]->v.y))/2; + + MapLineD(l,col); + + MapLine((int)(l->v[0]->v.x-dx),(int)(l->v[0]->v.y-dy), + (int)(l->v[0]->v.x-dx-dy/6),(int)(l->v[0]->v.y-dy+dx/6),col); +} + + +static int SelColour(int selmode) +{ + switch(selmode) + { + case SELECT_OVER: + return(OVERCOL); + break; + case SELECT_SELECTED: + return(SELCOL); + break; + default: + if (edit_mode==SECTOR_MODE) + return(SECTCOL); + else + return(LINECOL); + break; + } +} + + +static void RemoveHighlights(List l) +{ + Iterator i; + Object *o; + int *n; + + i=ListIterator(l); + + while(i) + { + n=IteratorData(i); + + if ((o=MapElem(linedef,*n))) + DrawLinedef(o->data,SelColour(o->select)); + + i=IteratorNext(i); + } +} + + +static void LineSelectionCentre(int *x,int *y) +{ + int *f; + EditLine *l; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + min_x=MIN(l->min_x,min_x); + min_y=MIN(l->min_y,min_y); + max_x=MAX(l->max_x,max_x); + max_y=MAX(l->max_y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +static void DeleteLeftSidedef(EditLine *l) +{ + Object *o; + int n; + int del; + int side; + EditLine *cl; + + TRACE; + + if (l->l.left==-1) + return; + + l->sl=NULL; + side=l->l.left; + l->l.left=-1; + + /* Free up the sidedef if there is no other linedef + bound to it + */ + del=TRUE; + + for(n=0;(nl.left==side)||(cl->l.right==side))) + del=FALSE; + } + + if (del) + { + o=MapElem(sidedef,side); + Release(o->data); + o->data=NULL; + } +} + + +static void DeleteRightSidedef(EditLine *l) +{ + Object *o; + int n; + int del; + int side; + EditLine *cl; + + TRACE; + + if (l->l.right==-1) + return; + + l->sr=NULL; + side=l->l.right; + l->l.right=-1; + + /* Free up the sidedef if there is no other linedef + bound to it + */ + del=TRUE; + + for(n=0;(nl.left==side)||(cl->l.right==side))) + del=FALSE; + } + + if (del) + { + o=MapElem(sidedef,side); + Release(o->data); + o->data=NULL; + } +} + + +static void DeleteLinedef(int f) +{ + Object *o; + EditLine *l; + + TRACE; + + o=MapElem(linedef,f); + l=o->data; + DeleteLeftSidedef(l); + DeleteRightSidedef(l); + + IntListRm(l->v[0]->l,f); + IntListRm(l->v[1]->l,f); + + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; +} + + +static int SplitLinedef(int f) +{ + Object o; + EditLine *l,*nl; + Sidedef *nsl,*nsr; + EditVert *nv; + int n_nl,dx,dy,tw; + + TRACE; + + l=GETLINE(f); + + o.select=SELECT_NONE; + + /* Create copies of the original linedefs and sidedefs + */ + nl=Grab(sizeof(EditLine)); + memcpy(nl,l,sizeof(EditLine)); + o.data=nl; + n_nl=MapSize(linedef); + nl->no=n_nl; + MapAdd(linedef,n_nl,&o); + + nsr=Grab(sizeof(Sidedef)); + memcpy(nsr,l->sr,sizeof(Sidedef)); + o.data=nsr; + nl->l.right=MapSize(sidedef); + MapAdd(sidedef,nl->l.right,&o); + nl->sr=GETSIDE(nl->l.right); + + if (l->l.left!=-1) + { + nsl=Grab(sizeof(Sidedef)); + memcpy(nsl,l->sl,sizeof(Sidedef)); + o.data=nsl; + nl->l.left=MapSize(sidedef); + MapAdd(sidedef,nl->l.left,&o); + nl->sl=GETSIDE(nl->l.left); + } + else + nsl=NULL; + + /* Work out the middle of the current line and create the vertex there + */ + nv=Grab(sizeof(EditVert)); + nv->l=ListNew(sizeof(int)); + + dx=((l->v[1]->v.x)-(l->v[0]->v.x))/2; + dy=((l->v[1]->v.y)-(l->v[0]->v.y))/2; + + nv->v.x=l->v[0]->v.x+dx; + nv->v.y=l->v[0]->v.y+dy; + o.data=nv; + + /* Update the vertex map, and the from/to in the old/new linedefs + */ + nl->l.from=MapSize(vertex); + MapAdd(vertex,nl->l.from,&o); + + l->l.to=nl->l.from; + + l->v[1]=GETVERT(l->l.to); + nl->v[0]=GETVERT(nl->l.from); + + /* Update the vertex lists + */ + IntListRm(nl->v[1]->l,f); + IntListUniqAdd(nl->v[0]->l,f); + IntListUniqAdd(nl->v[0]->l,n_nl); + + /* Align textures + */ + tw=CalcTextureWidth(nsr->upper,nsr->middle,nsr->lower); + + if (tw) + nsr->x=(l->sr->x+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + else + nsr->x=0; + + if (nsl) + { + tw=CalcTextureWidth(nsl->upper,nsl->middle,nsl->lower); + if (tw) + nsl->x=(l->sl->x+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + else + nsl->x=0; + } + + /* New linedef no + */ + return(n_nl); +} + + +/* ---------------------------------------- STEP CREATION CODE CALCULATIONS +*/ +static void DoCalcLine (int x0,int y0,int x1,int y1, + Point p[],int step,int *idx,int *len) +{ + int dx,dy,ix,iy,incre,incrne,d,x,y,ymode; + int p1x,p1y,p2x,p2y; + + TRACE; + + p1x=x0; + p1y=y0; + p2x=x1; + p2y=y1; + + dx=p2x-p1x; + dy=p2y-p1y; + + ix=SGN(dx); + iy=SGN(dy); + + dx=ABS(dx); + dy=ABS(dy); + + if (dy>dx) + { + ymode=TRUE; + d=dx*2-dy; + incre=dx*2; + incrne=(dx-dy)*2; + } + else + { + ymode=FALSE; + d=dy*2-dx; + incre=dy*2; + incrne=(dy-dx)*2; + } + + x=p1x; + y=p1y; + + CHECKSTEP(x,y); + + if (ymode) + while(y!=p2y) + { + if (d<=0) + { + d+=incre; + y+=iy; + } + else + { + d+=incrne; + y+=iy; + x+=ix; + } + + CHECKSTEP(x,y); + } + else + while(x!=p2x) + { + if (d<=0) + { + d+=incre; + x+=ix; + } + else + { + d+=incrne; + y+=iy; + x+=ix; + } + + CHECKSTEP(x,y); + } +} + + +static void DoCalcSpline (int x0,int y0,int x1,int y1,int x2,int y2, + Point p[],int step,int *idx,int *len) +{ + int xa, ya, xb, yb, xc, yc, xp, yp; + + TRACE; + + if ((x0==x1==x2)&&(y0==y1==y2)) + { + CHECKSTEP(x0,y0); + return; + } + + if ((x0==x1)&&(y0==y1)) + { + if (p) + DoCalcLine(x1,y1,x2,y2,p,step,idx,len); + else + *len+=Len(x1,y1,x2,y2); + return; + } + + if ((x0==x2)&&(y0==y2)) + { + if (p) + DoCalcLine(x0,y0,x1,y1,p,step,idx,len); + else + *len+=Len(x0,y0,x1,y1); + return; + } + + if ((x1==x2)&&(y1==y2)) + { + if (p) + DoCalcLine(x0,y0,x2,y2,p,step,idx,len); + else + *len+=Len(x0,y0,x2,y2); + return; + } + + xa = ( x0 + x1 ) / 2; + ya = ( y0 + y1 ) / 2; + xc = ( x1 + x2 ) / 2; + yc = ( y1 + y2 ) / 2; + xb = ( xa + xc ) / 2; + yb = ( ya + yc ) / 2; + + xp = ( x0 + xb ) / 2; + yp = ( y0 + yb ) / 2; + + if ( ABS( xa - xp ) + ABS( ya - yp ) > SPLINE_THRESH ) + DoCalcSpline(x0,y0,xa,ya,xb,yb,p,step,idx,len); + else + if (p) + DoCalcLine(x0,y0,xb,yb,p,step,idx,len); + else + *len+=Len(x0,y0,xb,yb); + + xp = ( x2 + xb ) / 2; + yp = ( y2 + yb ) / 2; + if ( ABS( xc - xp ) + ABS( yc - yp ) > SPLINE_THRESH ) + DoCalcSpline(xb,yb,xc,yc,x2,y2,p,step,idx,len); + else + if (p) + DoCalcLine(xb,yb,x2,y2,p,step,idx,len); + else + *len+=Len(xb,yb,x2,y2); +} + + +static void Spline(int x0,int y0, int x1, int y1, int x2, int y2, + Point p[],int step) +{ + int len; + int idx; + + TRACE; + + len=0; + idx=0; + DoCalcSpline(x0,y0,x1,y1,x2,y2,p,step,&idx,&len); +} + + +static int SplineLen(int x0,int y0, int x1, int y1, int x2, int y2) +{ + int len; + + TRACE; + + len=0; + DoCalcSpline(x0,y0,x1,y1,x2,y2,NULL,0,NULL,&len); + return (len); +} + + +static void CalcSteps(void) +{ + double dx,dy; + int f,r; + int len; + + TRACE; + + step.step_f=((double)step.to_f-step.from_f)/(step.no+2); + step.step_c=((double)step.to_c-step.from_c)/(step.no+2); + + if (step.circular) + { + f=step.side; + + len=SplineLen(step.vf[f].x,step.vf[f].y,step.x,step.y, + step.vt[f].x,step.vt[f].y); + + len=(int)((double)len/((double)step.no+1.0)+1.0); + + if (len<1) + len=1; + + Spline(step.vf[f].x,step.vf[f].y,step.x,step.y, + step.vt[f].x,step.vt[f].y,&step.p[f][1],len); + + step.p[f][0].x=step.vf[f].x; + step.p[f][0].y=step.vf[f].y; + + step.p[f][step.no+1].x=step.vt[f].x; + step.p[f][step.no+1].y=step.vt[f].y; + } + else + for(f=0;f<2;f++) + { + dx=(double)(step.vt[f].x-step.vf[f].x)/(step.no+1); + dy=(double)(step.vt[f].y-step.vf[f].y)/(step.no+1); + + for(r=1;r<=step.no;r++) + { + step.p[f][r].x=(int)(step.vf[f].x+(dx*r)); + step.p[f][r].y=(int)(step.vf[f].y+(dy*r)); + } + + step.p[f][0].x=step.vf[f].x; + step.p[f][0].y=step.vf[f].y; + + step.p[f][step.no+1].x=step.vt[f].x; + step.p[f][step.no+1].y=step.vt[f].y; + } +} + + +int SectorInBox(Point tl, Point br) +{ + int x,y; + + x=tl.x+(br.x-tl.x)/2; + y=tl.y+(br.y-tl.y)/2; + + return (SectorHoldingPoint(x,y)); +} + + +/* ---------------------------------------- STEP CREATION CALLBACKS +*/ +static void PickDraw(int *x, int *y) +{ + int f; + + TRACE; + + step.x=*x; + step.y=*y; + + if (step.circular) + CalcSteps(); + + for(f=0;f<2;f++) + MapLine(step.p[f][0].x,step.p[f][0].y, + step.p[f][1].x,step.p[f][1].y,LINECOL); + + for(f=1;f<=step.no;f++) + { + MapLine(step.p[0][f].x,step.p[0][f].y, + step.p[1][f].x,step.p[1][f].y,LINECOL); + + MapLine(step.p[0][f].x,step.p[0][f].y, + step.p[0][f+1].x,step.p[0][f+1].y,LINECOL); + + MapLine(step.p[1][f].x,step.p[1][f].y, + step.p[1][f+1].x,step.p[1][f+1].y,LINECOL); + } +} + + +static void PickKey(GFXKey k) +{ + TRACE; + + if (k.code==GFX_ASCII) + switch(toupper(k.ascii)) + { + case 'C': + step.circular=!step.circular; + CalcSteps(); + break; + + case 'S': + step.side^=1; + CalcSteps(); + break; + + case 'R': + step.swap=!step.swap; + + if (!step.swap) + { + SetPoint(step.vf[0],step.from->v[0]); + SetPoint(step.vf[1],step.from->v[1]); + SetPoint(step.vt[0],step.to->v[0]); + SetPoint(step.vt[1],step.to->v[1]); + } + else + { + SetPoint(step.vf[0],step.from->v[0]); + SetPoint(step.vf[1],step.from->v[1]); + SetPoint(step.vt[0],step.to->v[1]); + SetPoint(step.vt[1],step.to->v[0]); + } + + CalcSteps(); + + if (step.circular) + { + step.side^=1; + CalcSteps(); + step.side^=1; + } + + break; + + case '+': + if (step.noMIN_STEPS) + { + step.no--; + CalcSteps(); + + if (step.circular) + { + step.side^=1; + CalcSteps(); + step.side^=1; + } + } + break; + } +} + + +static void PickInfo(char *p) +{ + TRACE; + + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "No : %d|" + "Step (F) : %d|" + "Step (C) : %d|" + "Mode : %-s|" + "Side : %d", + step.no,ABS((int)step.step_f),ABS((int)step.step_c), + step.circular ? "Curve " : "Straight", + step.side); + + GuiDrawInfoBox(p,GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "+ - increase number of steps|" + "- - decrease number of steps|" + "C - change between straight/curve|" + "S - change wall being moved in curve mode|" + "R - swap vertex matching|" + " |" + "Press left button to complete. ESC to cancel"); +} + + +/* ---------------------------------------- STEP CREATION CODE +*/ +typedef struct + { + int line; + int apply; + } TextureMatch; + +static void ApplyTextureOffset(List li,int tw,int right) +{ + int off; + Iterator i; + TextureMatch *tm; + EditLine *l; + Sidedef *s; + + TRACE; + + i=ListIterator(li); + off=0; + + while(i) + { + tm=IteratorData(i); + + l=GETLINE(tm->line); + + if (tm->apply) + { + if (right) + s=l->sr; + else + s=l->sl; + + s->x=off; + } + + off=(off+Len(l->v[0]->v.x,l->v[0]->v.y,l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } +} + + +static int CreateSteps(int i_from, int i_to) +{ + EditSect *s; + EditLine *from,*to; + DirName upper,lower,middle,floor,ceiling; + int s_flag; + int type; + + TRACE; + + from=GETLINE(i_from); + to=GETLINE(i_to); + + if ((Len(from->v[0]->v.x,from->v[0]->v.y, + from->v[1]->v.x,from->v[1]->v.y)==0)|| + (Len(to->v[0]->v.x,to->v[0]->v.y,to->v[1]->v.x,to->v[1]->v.y)==0)) + { + GuiInfoBox("ERROR","Lines must be non-zero length"); + return(FALSE); + } + + if (((from->l.from==to->l.from)&&(to->l.to==to->l.to))|| + ((from->l.from==to->l.to)&&(to->l.to==to->l.from))) + { + GuiInfoBox("ERROR","Lines cannot share a vertex"); + return(FALSE); + } + + if (!(LinesCrossV(from->v[0],to->v[0],from->v[1],to->v[1]))) + { + step.swap=FALSE; + SetPoint(step.vf[0],from->v[0]); + SetPoint(step.vf[1],from->v[1]); + SetPoint(step.vt[0],to->v[0]); + SetPoint(step.vt[1],to->v[1]); + } + else + { + step.swap=TRUE; + SetPoint(step.vf[0],from->v[0]); + SetPoint(step.vf[1],from->v[1]); + SetPoint(step.vt[0],to->v[1]); + SetPoint(step.vt[1],to->v[0]); + } + + step.x=ms.x; + step.y=ms.y; + step.from=from; + step.to=to; + step.no=1; + step.circular=FALSE; + step.side=0; + + s=GETSECT(from->sr->sector); + step.from_c=s->s.ceiling; + step.from_f=s->s.floor; + + s=GETSECT(to->sr->sector); + step.to_c=s->s.ceiling; + step.to_f=s->s.floor; + + CalcSteps(); + + if ((PickPoint("Create steps",&step.x,&step.y,PickDraw,PickKey,PickInfo))&& + (ChooseSectorStyle(&s_flag,upper,middle,lower,floor,ceiling))&& + ((type=SelectSector())!=SECTOR_NULLID)) + { + Object o; + EditLine *el; + EditVert *ev[2][MAX_STEPS+2]; + EditSect *s; + Sidedef *ns; + TextureMatch tm; + List side_sl[2],side_sr[2]; + int n; + int v[2][MAX_STEPS+2]; + int do_ceiling; + double fh,ch; + int prev_fh,prev_ch; + int in_sect,sect,prev_sect; + int nl,flags; + int offy_c,offy_f,tw,th; + int f,r; + + /* Create lists for mainting lines for afterward texture alignment + */ + for(f=0;f<2;f++) + { + side_sl[f]=ListNew(sizeof(TextureMatch)); + side_sr[f]=ListNew(sizeof(TextureMatch)); + } + + if ((do_ceiling=GUI_yesno("Move ceiling with steps?"))) + ch=step.from_c+step.step_c; + else + ch=MAX(step.to_c,step.from_c); + + fh=step.from_f+step.step_f; + + tw=CalcTextureWidth(upper,middle,lower); + + TextureSize(middle,NULL,&th); + + /* Create/get all the vertexes needed + */ + for(f=0;f<=step.no+1;f++) + if (f==0) + { + v[0][f]=step.from->l.from; + v[1][f]=step.from->l.to; + ev[0][f]=step.from->v[0]; + ev[1][f]=step.from->v[1]; + } + else if (f==step.no+1) + { + if (step.swap) + { + v[1][f]=step.to->l.from; + v[0][f]=step.to->l.to; + ev[1][f]=step.to->v[0]; + ev[0][f]=step.to->v[1]; + } + else + { + v[0][f]=step.to->l.from; + v[1][f]=step.to->l.to; + ev[0][f]=step.to->v[0]; + ev[1][f]=step.to->v[1]; + } + } + else + for(r=0;r<2;r++) + { + ev[r][f]=Grab(sizeof(EditVert)); + ev[r][f]->v.x=step.p[r][f].x; + ev[r][f]->v.y=step.p[r][f].y; + ev[r][f]->l=ListNew(sizeof(int)); + + o.data=ev[r][f]; + o.select=SELECT_NONE; + v[r][f]=MapSize(vertex); + MapAdd(vertex,-1,&o); + } + + /* Delete current left sidedefs on the anchor lines + */ + if (step.from->l.left!=-1) + DeleteLeftSidedef(step.from); + + if (step.to->l.left!=-1) + DeleteLeftSidedef(step.to); + + /* Set up the flags for the 1st line and all the previous sector and + height vars + */ + prev_fh=step.from_f; + prev_ch=step.from_c; + prev_sect=step.from->sr->sector; + offy_c=0; + offy_f=0; + + /* Create the steps up to the last one + */ + for(f=0;f<=step.no;f++) + { + in_sect=SectorInBox(step.p[0][f],step.p[1][f+1]); + + if (in_sect!=-1) + s=GETSECT(in_sect); + else + s=NULL; + + sect=CreateUnboundSector + (type,(int)fh,(int)ch,default_light_level,0,floor,ceiling); + + /* Create the linedef at the start of the step. For the 1st step + we adjust the original linedef. Otherwise create a new one + */ + if (!f) + { + el=step.from; + el->l.flags|=side2_mask; + el->l.flags&=~block_mask; + + ns=Grab(sizeof(Sidedef)); + ns->x=0; + ns->y=0; + + el->l.flags|=upper_peg_mask; + el->l.flags&=~lower_peg_mask; + + if (prev_ch>(int)ch) + { + strcpy(el->sr->upper,upper); + strcpy(ns->upper,empty_texture); + } + else if (prev_ch<(int)ch) + { + strcpy(el->sr->upper,empty_texture); + strcpy(ns->upper,upper); + } + else + { + strcpy(el->sr->upper,empty_texture); + strcpy(ns->upper,empty_texture); + } + + if (prev_fh<(int)fh) + { + strcpy(el->sr->lower,lower); + strcpy(ns->lower,empty_texture); + } + else if (prev_fh>(int)fh) + { + strcpy(el->sr->lower,empty_texture); + strcpy(ns->lower,lower); + } + else + { + strcpy(el->sr->lower,empty_texture); + strcpy(ns->lower,empty_texture); + } + + strcpy(el->sr->middle,empty_texture); + strcpy(ns->middle,empty_texture); + + ns->sector=sect; + + o.data=ns; + o.select=SELECT_NONE; + + n=MapSize(sidedef); + MapAdd(sidedef,n,&o); + el->sl=ns; + el->l.left=n; + } + else + { + flags=side2_mask|upper_peg_mask; + + nl=CreateNewLinedef + (v[0][f],v[1][f],flags,normal_linedef,0,TRUE, + 0,0,prev_sect, + (prev_ch > (int)ch) ? upper : empty_texture, + empty_texture, + (prev_fh < (int)fh) ? lower : empty_texture, + 0,0,sect, + (prev_ch < (int)ch) ? upper : empty_texture, + empty_texture, + (prev_fh > (int)fh) ? lower : empty_texture); + + /* Add the new linedef to the vertex lists + */ + IntListUniqAdd(ev[0][f]->l,nl); + IntListUniqAdd(ev[1][f]->l,nl); + } + + /* Create the linedefs for the walls + */ + if (th) + { + offy_f-=(int)fh-prev_fh; + + while (offy_f<0) + offy_f+=th; + + offy_f%=th; + } + + if (do_ceiling) + if (th) + { + offy_c-=(int)ch-prev_ch; + + while (offy_c<0) + offy_c+=th; + + offy_c%=th; + } + + for(r=0;r<2;r++) + { + if (in_sect==-1) + { + int offy; + + flags=block_mask; + + if (!do_ceiling) + { + flags|=upper_peg_mask; + offy=0; + } + else + offy=offy_c; + + nl=CreateNewLinedef(v[r][f+r],v[r][f+(r^1)], + flags,normal_linedef,0,FALSE, + 0,offy,sect, + empty_texture, + middle, + empty_texture, + 0,0,-1, + empty_texture, + empty_texture, + empty_texture); + + tm.line=nl; + + if (r==0) + { + tm.apply=TRUE; + ListAppend(side_sr[r],&tm); + tm.apply=FALSE; + ListInsert(side_sl[r],&tm); + } + else + { + tm.apply=TRUE; + ListInsert(side_sr[r],&tm); + tm.apply=FALSE; + ListAppend(side_sl[r],&tm); + } + } + else + { + int offy_l,offy_r; + + flags=side2_mask; + flags=side2_mask|lower_peg_mask|upper_peg_mask; + + if ((int)ch>s->s.ceiling) + offy_r=offy_c; + else if ((int)fhs.floor) + offy_r=offy_c; + else + offy_r=0; + + offy_l=0; + + nl=CreateNewLinedef(v[r][f+r],v[r][f+(r^1)], + flags,normal_linedef,0,TRUE, + 0,offy_r,sect, + ((int)ch > s->s.ceiling) ? + upper : empty_texture, + empty_texture, + ((int)fh < s->s.floor) ? + lower : empty_texture, + 0,offy_l,in_sect, + ((int)ch < s->s.ceiling) ? + upper : empty_texture, + empty_texture, + ((int)fh > s->s.floor) ? + lower : empty_texture); + + tm.line=nl; + + if (r==0) + { + tm.apply=TRUE; + ListAppend(side_sr[r],&tm); + tm.apply=TRUE; + ListInsert(side_sl[r],&tm); + } + else + { + tm.apply=TRUE; + ListInsert(side_sr[r],&tm); + tm.apply=TRUE; + ListAppend(side_sl[r],&tm); + } + } + + /* Add the new linedef to the vertex lists + */ + IntListUniqAdd(ev[r][f]->l,nl); + IntListUniqAdd(ev[r][f+1]->l,nl); + } + + prev_fh=(int)fh; + prev_ch=(int)ch; + + fh+=step.step_f; + + if (do_ceiling) + ch+=step.step_c; + + prev_sect=sect; + } + + /* Adjust the end linedef anchor + */ + el=step.to; + el->l.flags|=side2_mask; + el->l.flags&=~block_mask; + + ns=Grab(sizeof(Sidedef)); + ns->x=0; + ns->y=0; + + if ((prev_ch!=step.to_c)&&(s_flag&SSTYLE_UPPER_PEG)) + el->l.flags|=upper_peg_mask; + else if (!(s_flag&SSTYLE_LEAVE_PEG)) + el->l.flags&=~upper_peg_mask; + + if ((prev_fh!=step.to_f)&&(s_flag&SSTYLE_LOWER_PEG)) + el->l.flags|=lower_peg_mask; + else if (!(s_flag&SSTYLE_LEAVE_PEG)) + el->l.flags&=~lower_peg_mask; + + if (prev_chsr->upper,upper); + strcpy(ns->upper,empty_texture); + } + else if (prev_ch>step.to_c) + { + strcpy(el->sr->upper,empty_texture); + strcpy(ns->upper,upper); + } + else + { + strcpy(el->sr->upper,empty_texture); + strcpy(ns->upper,empty_texture); + } + + if (prev_fh>step.to_f) + { + strcpy(el->sr->lower,lower); + strcpy(ns->lower,empty_texture); + } + else if (prev_fhsr->lower,empty_texture); + strcpy(ns->lower,lower); + } + else + { + strcpy(el->sr->lower,empty_texture); + strcpy(ns->lower,empty_texture); + } + + strcpy(el->sr->middle,empty_texture); + strcpy(ns->middle,empty_texture); + + ns->sector=prev_sect; + + o.data=ns; + o.select=SELECT_NONE; + + n=MapSize(sidedef); + MapAdd(sidedef,n,&o); + el->sl=ns; + el->l.left=n; + + /* Calculate the texture offsets for the walls + */ + for(f=0;f<2;f++) + { + ApplyTextureOffset(side_sl[f],tw,FALSE); + ApplyTextureOffset(side_sr[f],tw,TRUE); + + ListClear(side_sl[f]); + ListClear(side_sr[f]); + } + + SectorCalcContainingAll(); + + return(TRUE); + } + else + return(FALSE); +} + + +/* ---------------------------------------- LINEDEF VECTOR MAP UTILS +*/ + +/* Note this is repeated, rather than shared with the sector vector map to save + any unexpected later interactions +*/ +static int vno=0; +static char *vmap=NULL; + +static void InitVMAP(void) +{ + TRACE; + + if (vnosr->sector; + + if (!(s=GETSECT(sec_no))) + return(ll); + + vert_no=l->l.to; + + /* If the start LINEDEF is 2-sided and wholy within the sector, we only + track along connected 2-sided lines in the same sector. + + If the start line is 1-sided then we allow both 1 and 2 sided LINEDEFs + in the resulting list, but only 2 sided LINEDEFs that just have this + sector on one side of the line. + + To make this easier we mark the LMAP entries for those lines we wish to + ignore before starting. + */ + if ((l->sl)&&(l->sl->sector==sec_no)) + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if (!l->sl) + lmap[l->no]=TRUE; + else + if (!((l->sl->sector==sec_no)&&(l->sr->sector==sec_no))) + lmap[l->no]=TRUE; + + i=IteratorNext(i); + } + } + else + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if ((l->sl)&&(l->sl->sector==sec_no)&&(l->sr->sector==sec_no)) + lmap[l->no]=TRUE; + + i=IteratorNext(i); + } + } + + done=FALSE; + + while(!done) + { + done=TRUE; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + f=l->no; + + if (!lmap[f]) + { + /* We need two seperate checks, as obviously left sidedefs + pointing into the sector will need TO, rather than FROM, + checking + */ + if ((l->sr->sector==sec_no)&&(l->l.from==vert_no)) + { + lmap[f]=TRUE; + ListAppend(ll,&f); + done=FALSE; + vert_no=l->l.to; + } + else if ((l->sl)&&(l->sl->sector==sec_no)&&(l->l.to==vert_no)) + { + lmap[f]=TRUE; + ListAppend(ll,&f); + done=FALSE; + vert_no=l->l.from; + } + } + + i=IteratorNext(i); + } + } + + return(ll); +} + + +/* ---------------------------------------- LINEDEF MERGING +*/ +void CheckMergeLinedef(EditVert *v) +{ + Iterator i; + int *f; + int r; + EditLine *ol,*cl; + int same_dir; + int merge; + + TRACE; + + i=ListIterator(v->l); + + while(i) + { + f=IteratorData(i); + + ol=GETLINE(*f); + + for(r=0;rl.from==ol->l.from)&&(cl->l.to==ol->l.to))|| + ((cl->l.from==ol->l.to)&&(cl->l.to==ol->l.from))) + { + if ((cl->l.from==ol->l.from)&&(cl->l.to==ol->l.to)) + same_dir=TRUE; + else + same_dir=FALSE; + + if(merge_linedef==MERGE_ASK) + merge=YesNo("Linedefs %d and %d overlap. Merge?",*f,r); + else + merge=TRUE; + + if (merge) + { + if (same_dir) + { + if (cl->l.left!=-1) + { + DeleteLeftSidedef(ol); + ol->l.left=cl->l.left; + ol->sl=GETSIDE(ol->l.left); + ol->l.flags|=side2_mask; + + if (auto_block_linedefs) + ol->l.flags&=~block_mask; + } + } + else + { + DeleteLeftSidedef(ol); + ol->l.left=cl->l.right; + ol->sl=GETSIDE(ol->l.left); + ol->l.flags|=side2_mask; + + if (auto_block_linedefs) + ol->l.flags&=~block_mask; + } + + DeleteLinedef(r); + } + } + } + + i=IteratorNext(i); + } +} + + +/* ---------------------------------------- LINEDEF CREATION +*/ +int CreateNewLinedef(int from, int to, + int flags, int type, int tag, int two_sided, + int sr_ox, int sr_oy, int sr_sector, + DirName sr_upper, DirName sr_middle, DirName sr_lower, + int sl_ox, int sl_oy, int sl_sector, + DirName sl_upper, DirName sl_middle, DirName sl_lower) +{ + Object o; + EditLine *l; + Sidedef *s; + int ln,srn,sln; + + TRACE; + + ln=MapSize(linedef); + + srn=MapSize(sidedef); + + if (two_sided) + sln=srn+1; + else + sln=-1; + + o.select=SELECT_NONE; + + s=Grab(sizeof(Sidedef)); + s->x=sr_ox; + s->y=sr_oy; + s->sector=sr_sector; + strcpy(s->upper,sr_upper); + strcpy(s->middle,sr_middle); + strcpy(s->lower,sr_lower); + o.data=s; + MapAdd(sidedef,srn,&o); + + if (sln!=-1) + { + s=Grab(sizeof(Sidedef)); + s->x=sl_ox; + s->y=sl_oy; + s->sector=sl_sector; + strcpy(s->upper,sl_upper); + strcpy(s->middle,sl_middle); + strcpy(s->lower,sl_lower); + o.data=s; + MapAdd(sidedef,sln,&o); + } + + l=Grab(sizeof(EditLine)); + + l->no=ln; + + l->l.from=from; + l->l.to=to; + + l->l.flags=flags; + l->l.type=type; + l->l.tag=tag; + + l->v[0]=GETVERT(l->l.from); + l->v[1]=GETVERT(l->l.to); + + l->l.right=srn; + l->l.left=sln; + + l->sr=GETSIDE(srn); + + if (sln!=-1) + l->sl=GETSIDE(sln); + else + l->sl=NULL; + + if (edit_mode==LINEDEF_MODE) + switch(insert_select) + { + case HOVER_NONE: + o.select=SELECT_NONE; + break; + case HOVER_ADD: + case HOVER_SINGLE: + o.select=SELECT_SELECTED; + break; + } + else + o.select=SELECT_NONE; + + LineCalcBounding(l); + o.data=l; + MapAdd(linedef,ln,&o); + + if (edit_mode==LINEDEF_MODE) + switch(insert_select) + { + case HOVER_NONE: + break; + case HOVER_ADD: + ListAppend(selected,&ln); + break; + case HOVER_SINGLE: + ClearSelection(); + o.select=SELECT_SELECTED; + ListAppend(selected,&ln); + FullRedraw(); + break; + } + + return(ln); +} + + +/* ---------------------------------------- GENERIC LINEDEF FUNCS +*/ +int PositionOnObject_LINEDEF(int x,int y,void *data) +{ + EditLine *l; + + TRACE; + + l=data; + + /* + if (scale<4) + box=BOXBOUND_FUZZY(x,y,l->min_x,l->min_y,l->max_x,l->max_y,2); + else + box=BOXBOUND_FUZZY(x,y,l->min_x,l->min_y,l->max_x,l->max_y,scale/2); + + if (!box) + return(FALSE); + */ + + if(LinesCross(x-(scale*linedef_select),y,x+(scale*linedef_select),y, + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)) + return(TRUE); + + return(LinesCross(x,y-(scale*linedef_select),x,y+(scale*linedef_select), + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)); +} + + +void SelectBox_LINEDEF(int x1,int y1,int x2,int y2) +{ + Object *o; + EditLine *l; + int f; + + TRACE; + + for(f=0;fdata)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(l->v[0]->v.x,l->v[0]->v.y,x1,y1,x2,y2))&& + (BOXBOUND(l->v[1]->v.x,l->v[1]->v.y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_LINEDEF(void) +{ + Object *o; + EditLine *l; + int id; + int f; + + if ((id=SelectLinedef())!=LINEDEF_NULLID) + { + ClearSelection(); + + for(f=0;fdata)&&(l->l.type==id)) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } +} + + +void DrawObject_LINEDEF(void *data, int selmode) +{ + static List hilite=NULL; + static int drawn=FALSE; + Iterator i; + EditLine *l; + EditLine *sl=NULL; + EditSect *s; + Object *o; + int f; + + TRACE; + + if (!hilite) + hilite=ListNew(sizeof(int)); + + l=data; + + /* If the current object has changed, remove the highlighted tag objects + */ + if ((current==-1)&&(drawn)) + { + drawn=FALSE; + RemoveHighlights(hilite); + ListEmpty(hilite); + } + + /* Draw tagged sectors + */ + if ((tag_highlight)&&(current==l->no)) + { + RemoveHighlights(hilite); + ListEmpty(hilite); + + if (l->l.tag) + { + drawn=TRUE; + + for(f=0;fs.tag==l->l.tag)&&(SectorOnDisplay(s))) + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&sl,IteratorData(i),sizeof(sl)); + o=MapElem(linedef,sl->no); + + if (o->select==SELECT_NONE) + { + ListAppend(hilite,&(sl->no)); + DrawLinedef(sl,TAGCOL); + } + + i=IteratorNext(i); + } + } + } + + } + + /* Only draw the line if it's not been drawn tagged or is selected. + */ + if ((!tag_highlight)||(selmode==SELECT_SELECTED)|| + (!InIntList(hilite,l->no))) + DrawLinedef(data,SelColour(selmode)); +} + + +void DrawObjectInfo_LINEDEF(void) +{ + EditLine *l; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((l=GETLINE(current)))) + { + if (show_full_linedef_info) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Type [%4.4x]: %-35.35s|" + "Tag : %-5d", + current, + LinedefFlagText(l->l.flags), + l->l.type,LinedefName(l->l.type),l->l.tag); + else + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Type [%4.4x]: %-20.20s|" + "Tag : %-5d", + current, + LinedefFlagText(l->l.flags), + l->l.type,LinedefClass(l->l.type),l->l.tag); + + GuiDrawInfoBox("RIGHT SIDEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Offset : %d,%d|" + "Upper : %-10s|" + "Middle : %-10s|" + "Lower : %-10s|" + "Sector : %d", + l->sr->x,l->sr->y, + l->sr->upper,l->sr->middle,l->sr->lower, + l->sr->sector); + + if (l->sl) + GuiDrawInfoBox("LEFT SIDEDEF",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Offset : %d,%d|" + "Upper : %-10s|" + "Middle : %-10s|" + "Lower : %-10s|" + "Sector : %d", + l->sl->x,l->sl->y, + l->sl->upper,l->sl->middle,l->sl->lower, + l->sl->sector); + else + GuiDrawInfoBox("NO LEFT SIDEDEF",GUI_FLUSH_LEFT, + GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + } + else + { + if (show_full_linedef_info) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Type : %35s|" + "Tag : -",""); + else + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Type : %20s|" + "Tag : -",""); + + GuiDrawInfoBox("RIGHT SIDEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + + GuiDrawInfoBox("LEFT SIDEDEF",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + } +} + + +void DrawObjectHeader_LINEDEF(void) +{ + if (tag_highlight) + GFX_print(0,FH,WHITE,"Tag highlight: ON"); + else + GFX_print(0,FH,WHITE,"Tag highlight: OFF"); +} + + +void MoveObject_LINEDEF(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditLine *l; + List orig; + int *f,r; + Point p; + unsigned char *vmap; + int cancel; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + + vmap=Grab(MapSize(vertex)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + p.x=l->v[0]->v.x; + p.y=l->v[0]->v.y; + ListAppend(orig,&p); + p.x=l->v[1]->v.x; + p.y=l->v[1]->v.y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move LINEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + + l=GETLINE(*f); + + memcpy(&p,IteratorData(i2),sizeof(Point)); + l->v[0]->v.x=p.x; + l->v[0]->v.y=p.y; + i2=IteratorNext(i2); + + memcpy(&p,IteratorData(i2),sizeof(Point)); + l->v[1]->v.x=p.x; + l->v[1]->v.y=p.y; + i2=IteratorNext(i2); + + i=IteratorNext(i); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + for(r=0;rl.from]) + { + l->v[0]->v.x+=dmx; + l->v[0]->v.y+=dmy; + vmap[l->l.from]=TRUE; + } + + if (!vmap[l->l.to]) + { + l->v[1]->v.x+=dmx; + l->v[1]->v.y+=dmy; + vmap[l->l.to]=TRUE; + } + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + Release(vmap); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_LINEDEF(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditLine *l; + + TRACE; + + InitVMAP(); + + LineSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + if (!vmap[l->l.from]) + { + vmap[l->l.from]=TRUE; + x=l->v[0]->v.x; + y=l->v[0]->v.y; + + Rotate(cx,cy,&x,&y,angle); + + l->v[0]->v.x=x; + l->v[0]->v.y=y; + } + + if (!vmap[l->l.to]) + { + vmap[l->l.to]=TRUE; + x=l->v[1]->v.x; + y=l->v[1]->v.y; + + Rotate(cx,cy,&x,&y,angle); + + l->v[1]->v.x=x; + l->v[1]->v.y=y; + } + + i=IteratorNext(i); + } +} + + +void ScaleObject_LINEDEF(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditLine *l; + + TRACE; + + LineSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + x=l->v[0]->v.x; + y=l->v[0]->v.y; + + Scale(cx,cy,&x,&y,scale); + + l->v[0]->v.x=x; + l->v[0]->v.y=y; + + x=l->v[1]->v.x; + y=l->v[1]->v.y; + + Scale(cx,cy,&x,&y,scale); + + l->v[1]->v.x=x; + l->v[1]->v.y=y; + + i=IteratorNext(i); + } +} + + +void SetTagObject_LINEDEF(int tag) +{ + int *f; + Iterator i; + EditLine *l; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + l->l.tag=tag; + i=IteratorNext(i); + } +} + + +void LocateObject_LINEDEF(void *obj) +{ + int cx,cy; + EditLine *l; + + TRACE; + + l=obj; + cx=l->min_x+(l->max_x-l->min_x)/2; + cy=l->min_y+(l->max_y-l->min_y)/2; + ox=cx-scale*SCRW/2; + oy=cy+scale*SCRH/2; +} + + +void ObjectInsert_LINEDEF(void) +{ + int type; + int fl,two; + DirName sr_upper,sr_lower,sr_middle; + DirName sl_upper,sl_lower,sl_middle; + int ok; + int from,to; + int nl; + EditVert *v; + + TRACE; + + if (MapSize(vertex)<2) + { + GuiInfoBox("ERROR","Need more that 2 vertices|to make a line"); + FullRedraw(); + } + else + { + vertex_dialog[D_VERTEX_FROM].data.i=MapSize(vertex)-2; + vertex_dialog[D_VERTEX_TO].data.i=MapSize(vertex)-1; + + ok=GUI_dialog("Create LINEDEF",D_VERTEX_NO,vertex_dialog); + + if (ok) + { + from=vertex_dialog[D_VERTEX_FROM].data.i; + to=vertex_dialog[D_VERTEX_TO].data.i; + + if ((from>=MapSize(vertex))||(from<0)||(!GETVERT(from))) + { + GuiInfoBox("ERROR","%d (from) is an invalid vertex",from); + FullRedraw(); + ok=FALSE; + } + else if ((to>=MapSize(vertex))||(to<0)||(!GETVERT(to))) + { + GuiInfoBox("ERROR","%d (to) is an invalid vertex",to); + FullRedraw(); + ok=FALSE; + } + } + + if (ok) + if (GetLinedefValues(TRUE,0,0,0,0, + &type,&fl,&two, + sr_upper,sr_middle,sr_lower, + sl_upper,sl_middle,sl_lower)) + { + nl=CreateNewLinedef(from,to, + fl,type,0,two, + 0,0,0, + sr_upper,sr_middle,sr_lower, + 0,0,0, + sl_upper,sl_middle,sl_lower); + + v=GETVERT(from); + IntListUniqAdd(v->l,from); + v=GETVERT(to); + IntListUniqAdd(v->l,from); + + FullRedraw(); + } + } +} + + +void ObjectDelete_LINEDEF(void) +{ + Iterator i; + int *f; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + DeleteLinedef(*f); + i=IteratorNext(i); + } + + SectorCalcContainingAll(); + ClearSelection(); + FullRedraw(); +} + + +void ObjectMenu_LINEDEF(void) +{ + static int ax=0; + static int ay=0; + EditLine *l; + int f,*s; + Iterator i; + int cancel; + int opt; + + TRACE; + + s=NULL; + cancel=FALSE; + GFX_redraw(); + + opt=GUI_menu("Linedef/sidedef",ms.x,ms.y,linedef_popup,GUI_CANCEL); + + switch(opt) + { + case TM_RIGHT_SIDE: + opt=GUI_menu("Right sidedef",ms.x,ms.y,right_popup,GUI_CANCEL); + break; + + case TM_LEFT_SIDE: + opt=GUI_menu("Left sidedef",ms.x,ms.y,left_popup,GUI_CANCEL); + break; + + default: + break; + } + + switch(opt) + { + case TM_TYPE: + { + f=SelectLinedef(); + + if (f!=LINEDEF_NULLID) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + l->l.type=f; + i=IteratorNext(i); + } + + FullRedraw(); + } + break; + } + + case TM_FLAGS: + l=SelHead(); + f=l->l.flags; + + if (GUI_multi_box("Flags",LinedefFlagArray(),&f)) + { + int new_side; + List new; + + new=ListNew(sizeof(int)); + new_side=FALSE; + + i=ListIterator(selected); + + while(i) + { + int new_f; + + new_f=f; + s=IteratorData(i); + l=GETLINE(*s); + + /* If the line was 2 sided, and is now one - removed the + left sidedef + */ + if ((l->l.flags&side2_mask)&&(!(new_f&side2_mask))) + { + DeleteLeftSidedef(l); + + if (auto_block_linedefs) + new_f|=block_mask; + } + + /* If the line was 1 sided, and is now two - add the + left sidedef + */ + if ((!(l->l.flags&side2_mask))&&(new_f&side2_mask)) + { + Object o; + Sidedef *ns; + int n; + + ns=Grab(sizeof(Sidedef)); + ns->x=0; + ns->y=0; + strcpy(ns->upper,empty_texture); + strcpy(ns->middle,empty_texture); + strcpy(ns->lower,empty_texture); + ns->sector=-1; + + o.data=ns; + o.select=SELECT_NONE; + + n=MapSize(sidedef); + MapAdd(sidedef,n,&o); + l->sl=ns; + l->l.left=n; + + new_side=TRUE; + + ListAppend(new,s); + + if (auto_block_linedefs) + new_f&=~block_mask; + } + + l->l.flags=new_f; + i=IteratorNext(i); + } + + if (new_side) + switch(new_2sided_select) + { + case NEWSELECT_NEVER: + GuiInfoBox("NOTICE","Left SIDEDEFS have been added|" + "to some or all LINEDEFS"); + break; + + /* WARNING: This case cascades into the following + one + */ + case NEWSELECT_ASK: + if (!YesNo("New left SIDEDEFS created. " + "Select those LINEDEFS?")) + break; + case NEWSELECT_SELECT: + { + Object *o; + + new_selection=TRUE; + ClearSelection(); + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + ListAppend(selected,s); + i=IteratorNext(i); + } + break; + } + } + + ListClear(new); + + FullRedraw(); + } + + break; + + case TM_SWAP_SIDES: + { + int tmp; + Sidedef *tmp_s; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (l->l.left!=-1) + { + tmp=l->l.left; + tmp_s=l->sl; + + l->sl=l->sr; + l->l.left=l->l.right; + + l->sr=tmp_s; + l->l.right=tmp; + + tmp=l->l.from; + l->l.from=l->l.to; + l->l.to=tmp; + + l->v[0]=GETVERT(l->l.from); + l->v[1]=GETVERT(l->l.to); + } + + i=IteratorNext(i); + } + + SectorCalcContainingAll(); + FullRedraw(); + + break; + } + + case TM_SPLIT_LINE: + { + List new; + int no; + Object *o; + + new=ListNew(sizeof(int)); + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + no=SplitLinedef(*s); + ListAppend(new,&no); + i=IteratorNext(i); + } + + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + + ListAppend(selected,s); + i=IteratorNext(i); + } + + ListClear(new); + SectorCalcContainingAll(); + FullRedraw(); + + break; + } + + case TM_TRACK_LINE: + { + List new; + Object *o; + + i=ListIterator(selected); + + *s=MapSize(linedef)+1; + + while(i) + { + s=IteratorData(i); + i=IteratorNext(i); + } + + if ((new=TrackLinedef(*s))) + { + ClearSelection(); + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + ListAppend(selected,s); + + i=IteratorNext(i); + } + + ListClear(new); + new_selection=TRUE; + FullRedraw(); + } + + break; + } + + case TM_STEPS: + if (ListSize(selected)!=2) + GuiInfoBox("ERROR","Just select 2 linedefs|for this function"); + else + { + int *l1,*l2; + + i=ListIterator(selected); + l1=IteratorData(i); + i=IteratorNext(i); + l2=IteratorData(i); + IteratorClear(i); + + cancel=CreateSteps(*l1,*l2); + } + + FullRedraw(); + break; + + + case TM_OFFSET_R: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=l->sr->x; + offset_dialog[D_OFFSET_OFFY].data.i=l->sr->y; + + if (GUI_dialog("Right offset",D_OFFSET_NO,offset_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + { + l->sr->x=offset_dialog[D_OFFSET_OFFX].data.i; + l->sr->y=offset_dialog[D_OFFSET_OFFY].data.i; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_ADJUST_R: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=ax; + offset_dialog[D_OFFSET_OFFY].data.i=ay; + + if (GUI_dialog("Right offset adjustment",D_OFFSET_NO,offset_dialog)) + { + ax=offset_dialog[D_OFFSET_OFFX].data.i; + ay=offset_dialog[D_OFFSET_OFFY].data.i; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + { + l->sr->x+=ax; + l->sr->y+=ay; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_SECTOR_R: + l=SelHead(); + + sectorn_dialog[D_SECTORN_SECNO].data.i=l->sr->sector; + + if (GUI_dialog("Right sector",D_SECTORN_NO,sectorn_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + l->sr->sector=sectorn_dialog[D_SECTORN_SECNO].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + SectorCalcContainingAll(); + FullRedraw(); + } + + break; + + case TM_UPPER_T_R: + { + DirName d; + + if ((GetTexture("Upper Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->upper,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_MIDDLE_T_R: + { + DirName d; + + if ((GetTexture("Middle Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->middle,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_LOWER_T_R: + { + DirName d; + + if ((GetTexture("Lower Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->lower,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_ALIGN_R: + { + int tw; + int ox; + + l=SelHead(); + + tw=CalcTextureWidth(l->sr->upper,l->sr->middle,l->sr->lower); + + if (tw==0) + { + GuiInfoBox("ERROR","First selected linedef has no texture"); + FullRedraw(); + } + else + { + ox=l->sr->x; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + + l=GETLINE(*s); + + l->sr->x=ox; + + ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } + + FullRedraw(); + } + + } + break; + + + case TM_OFFSET_L: + l=SelHead(); + + if (l->sl) + { + offset_dialog[D_OFFSET_OFFX].data.i=l->sl->x; + offset_dialog[D_OFFSET_OFFY].data.i=l->sl->y; + } + + if (GUI_dialog("Left offset",D_OFFSET_NO,offset_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + { + l->sl->x=offset_dialog[D_OFFSET_OFFX].data.i; + l->sl->y=offset_dialog[D_OFFSET_OFFY].data.i; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_ADJUST_L: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=ax; + offset_dialog[D_OFFSET_OFFY].data.i=ay; + + if (GUI_dialog("Left offset adjustment",D_OFFSET_NO,offset_dialog)) + { + ax=offset_dialog[D_OFFSET_OFFX].data.i; + ay=offset_dialog[D_OFFSET_OFFY].data.i; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + { + l->sl->x+=ax; + l->sl->y+=ay; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_SECTOR_L: + l=SelHead(); + + if (l->sl) + sectorn_dialog[D_SECTORN_SECNO].data.i=l->sl->sector; + + if (GUI_dialog("Left sector",D_SECTORN_NO,sectorn_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + l->sl->sector=sectorn_dialog[D_SECTORN_SECNO].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + SectorCalcContainingAll(); + FullRedraw(); + } + + break; + + case TM_UPPER_T_L: + { + DirName d; + + if ((GetTexture("Upper Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->upper,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_MIDDLE_T_L: + { + DirName d; + + if ((GetTexture("Middle Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->middle,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_LOWER_T_L: + { + DirName d; + + if ((GetTexture("Lower Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->lower,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_ALIGN_L: + { + int tw; + int ox; + int ok; + + ok=TRUE; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (!(l->sl)) + ok=FALSE; + + i=IteratorNext(i); + } + + if (!ok) + { + GuiInfoBox("ERROR","Some linedefs with no left sidedef"); + FullRedraw(); + } + else + { + l=SelHead(); + + tw=CalcTextureWidth(l->sl->upper,l->sl->middle,l->sl->lower); + + if (tw==0) + { + GuiInfoBox("ERROR","First selected linedef has no texture"); + FullRedraw(); + } + else + { + ox=l->sl->x; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + + l=GETLINE(*s); + + l->sl->x=ox; + + ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } + + FullRedraw(); + } + } + + } + break; + + + case TM_TAG: + l=SelHead(); + tag_dialog[D_TAG].data.i=l->l.tag; + + if (GUI_dialog("Tag",D_TAG_NO,tag_dialog)) + { + SetTagObject_LINEDEF(tag_dialog[D_TAG].data.i); + FullRedraw(); + } + + break; + + case TM_DELETE: + ObjectDelete_LINEDEF(); + break; + + case TM_MOVE: + MoveObject_LINEDEF(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(!new_selection)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } +} + + +void ObjectKey_LINEDEF(GFXKey k) +{ + char s[128]; + EditLine *l; + int f; + int change; + List li; + Iterator i; + EditSect *sr,*sl; + DirName d; + Object *o; + int apply; + + TRACE; + + switch(k.code) + { + case GFX_F12: + li=ListNew(sizeof(int)); + + change=FALSE; + + if (ListSize(selected)==0) + { + GuiInfoBox("ERROR","No linedefs selected"); + FullRedraw(); + return; + } + + i=ListIterator(selected); + + while(i) + { + memcpy(&f,IteratorData(i),sizeof(f)); + + if ((l=GETLINE(f))) + { + TRACE; + if (check_1side_lower) + if ((!l->sl)&&(strcmp(l->sr->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with a " + "lower texture. Remove?",f))) + { + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + + TRACE; + if (check_1side_middle) + if ((!l->sl)&&(!strcmp(l->sr->middle,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with no " + "middle texture. Add?",f))) + { + sprintf(s,"Pick MIDDLE texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->middle,d); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if (check_1side_upper) + if ((!l->sl)&&(strcmp(l->sr->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with a " + "upper texture. Remove?",f))) + { + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + + TRACE; + if ((check_2side_lower)&&(l->sl)&&(l->sl->sector!=-1)&& + (l->sr->sector!=-1)) + { + sr=GETSECT(l->sr->sector); + sl=GETSECT(l->sl->sector); + + if ((sr->s.floors.floor)&& + (!strcmp(l->sr->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "lower texture. Add?",f))) + { + sprintf(s,"Pick LOWER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->lower,d); + strcpy(l->sl->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.floor>sl->s.floor)&& + (!strcmp(l->sl->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "lower texture. Add?",f))) + { + sprintf(s,"Pick LOWER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sl->lower,d); + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.floor==sl->s.floor)&& + ((strcmp(l->sl->lower,empty_texture))|| + (strcmp(l->sr->lower,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with pointless " + "lower texture. Remove?",f))) + { + strcpy(l->sl->lower,empty_texture); + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_middle)&&(l->sl)&&(l->sl->sector!=-1)) + { + if (((strcmp(l->sr->middle,empty_texture))|| + (strcmp(l->sl->middle,empty_texture)))&& + (l->sl->sector!=l->sr->sector)) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with a " + "middle texture. Remove?",f))) + { + strcpy(l->sr->middle,empty_texture); + strcpy(l->sl->middle,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_upper)&&(l->sl)&&(l->sl->sector!=-1)&& + (l->sr->sector!=-1)) + { + sr=GETSECT(l->sr->sector); + sl=GETSECT(l->sl->sector); + + if ((sr->s.ceiling>sl->s.ceiling)&& + (!strcmp(l->sr->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "upper texture. Add?",f))) + { + sprintf(s,"Pick UPPER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->upper,d); + strcpy(l->sl->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.ceilings.ceiling)&& + (!strcmp(l->sl->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "upper texture. Add?",f))) + { + sprintf(s,"Pick UPPER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sl->upper,d); + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.ceiling==sl->s.ceiling)&& + ((strcmp(l->sl->upper,empty_texture))|| + (strcmp(l->sr->upper,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with pointless " + "upper texture. Remove?",f))) + { + strcpy(l->sl->upper,empty_texture); + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_same_sector)&&(l->sl)&&(l->sl->sector!=-1)) + { + if ((l->sl->sector==l->sr->sector)&& + ((strcmp(l->sr->lower,empty_texture))|| + (strcmp(l->sr->middle,empty_texture))|| + (strcmp(l->sr->upper,empty_texture))|| + (strcmp(l->sl->lower,empty_texture))|| + (strcmp(l->sl->middle,empty_texture))|| + (strcmp(l->sl->upper,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided within a " + "sector and is textured. Remove all?",f))) + { + strcpy(l->sr->lower,empty_texture); + strcpy(l->sl->lower,empty_texture); + strcpy(l->sr->middle,empty_texture); + strcpy(l->sl->middle,empty_texture); + strcpy(l->sr->upper,empty_texture); + strcpy(l->sl->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + } + + i=IteratorNext(i); + } + + if (change) + { + if (YesNo("Select altered LINEDEFs?")) + { + ClearSelection(); + i=ListIterator(li); + + while(i) + { + memcpy(&f,IteratorData(i),sizeof(int)); + o=MapElem(linedef,f); + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + i=IteratorNext(i); + } + + FullRedraw(); + } + } + else + { + GuiInfoBox("NOTICE","No problems found"); + FullRedraw(); + } + + ListClear(li); + break; + + default: + + case GFX_ASCII: + switch(toupper(k.ascii)) + { + case 'H': + tag_highlight=!tag_highlight; + FullRedraw(); + break; + + default: + break; + } + break; + } +} + + +int ObjectHasTag_LINEDEF(void *obj, int tag) +{ + EditLine *l; + + return ((l=obj)&&(l->l.tag==tag)); +} + + +/* END OF FILE */ diff --git a/editmrg.c b/editmrg.c new file mode 100644 index 0000000..7aaa10b --- /dev/null +++ b/editmrg.c @@ -0,0 +1,567 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Merging of WAD maps + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" +#include "gui.h" +#include "wad.h" + + +/* ---------------------------------------- LOCAL DATA +*/ +static WadMap *wad; +static int min_x; +static int min_y; +static int max_x; +static int max_y; +static int cx; +static int cy; +static int ang; + + +/* ---------------------------------------- CO-ORD FUNCS +*/ +static void MergeCoord(int *x, int *y) +{ + if (ang) + { + Rotate(min_x,min_y,x,y,(double)ang); + + *x=cx-min_x+(*x); + *y=cy-min_y+(*y); + } + else + { + *x=cx-min_x+(*x); + *y=cy-min_y+(*y); + } +} + +/* ---------------------------------------- PickPoint() CALLBACKS +*/ +static void PickDraw(int *x,int *y) +{ + Map lm,vm; + Linedef *l; + Vertex *v1,*v2; + int x1,y1,x2,y2; + int f; + + cx=*x=SnapX(*x); + cy=*y=SnapY(*y); + + lm=wad->linedef; + vm=wad->vertex; + + for(f=0;ffrom); + v2=MapElem(vm,l->to); + + x1=v1->x; + y1=v1->y; + MergeCoord(&x1,&y1); + x1=MapToX(x1); + y1=MapToY(y1); + + x2=v2->x; + y2=v2->y; + MergeCoord(&x2,&y2); + x2=MapToX(x2); + y2=MapToY(y2); + + GFX_line(x1,y1,x2,y2,WHITE); + } +} + + +static void PickKey(GFXKey k) +{ + TRACE; + + if (k.code==GFX_ASCII) + switch(k.ascii) + { + case '.': + if (--ang<0) + ang=359; + break; + + case ',': + ang=(ang+1)%360; + break; + + case '>': + if ((ang-=10)<0) + ang+=360; + break; + + case '<': + ang=(ang+10)%360; + break; + + default: + break; + } +} + + +static void PickInfo(char *p) +{ + TRACE; + + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE,"Angle : %3d|",ang); + + GuiDrawInfoBox(p,GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + ", - rotate left 1 deg |" + ". - rotate right 1 deg |" + "< - rotate left 10 deg |" + "> - rotate right 10 deg|" + " |" + "Press left button to complete. ESC to cancel"); +} + + +/* ---------------------------------------- WAD MERGEING +*/ +void MergeWad(void) +{ + Object o; + Linedef *l; + Sector *s=NULL; + Thing *t; + Vertex *v; + Sidedef *si; + EditVert *ev; + EditLine *el; + EditSect *es; + EditThing *et; + char *name; + int f; + int unbound; + int n_thing; + int n_line; + int n_side; + int n_vert; + int n_sect; + int n_tag; + int tmp_wad; + char *tmp_n; + char *wadf; + int *secmap; + int x,y; + + if (level_style==DOOM_2_LEVELS) + tmp_n="MAP01"; + else + tmp_n="E1M1"; + + if ((tmp_wad=YesNo("Load a new PWAD and read %s from it?",tmp_n))) + { + if (!(wadf=GUI_fsel("Pick PWAD to merge map from",PWAD_dir,".WAD"))) + return; + + if (AddPWAD(wadf)!=WAD_OK) + { + GuiInfoBox("ERROR","AddPWAD(%s): %s",wadf,WadErrorString()); + FullRedraw(); + Release(wadf); + return; + } + + name=tmp_n; + } + else + { + wadf=NULL; + + if (!(name=GuiPickLevel("Pick map to merge"))) + return; + } + + GuiDrawInfoBox("Loading...",GUI_CENTRE,GUI_CENTRE,TRUE, + "Loading level %s",name); + if (!(wad=LoadMap(name))) + { + GuiInfoBox("ERROR","LoadMap(%s): %s",name,WadErrorString()); + FullRedraw(); + + if (tmp_wad) + { + if (CloseWad(wadf)!=WAD_OK) + GuiInfoBox("ERROR","CloseWad(%s)|%s",wadf,WadErrorString()); + + Release(wadf); + } + + return; + } + + if (MapSize(wad->linedef)==0) + { + GuiInfoBox("ERROR","No LINEDEFS in %s",name); + ClearMap(wad); + FullRedraw(); + + if (tmp_wad) + { + if (CloseWad(wadf)!=WAD_OK) + GuiInfoBox("ERROR","CloseWad(%s)|%s",wadf,WadErrorString()); + + Release(wadf); + } + + return; + } + + FullRedraw(); + + /* Get top left hand corner of map and see if there are unbound left + sidedefs + */ + ang=0; + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + for(f=0;fvertex);f++) + { + v=MapElem(wad->vertex,f); + + min_x=MIN(min_x,v->x); + min_y=MIN(min_y,v->y); + + max_x=MAX(max_x,v->x); + max_y=MAX(max_y,v->y); + } + + min_x=min_x+(max_x-min_x)/2; + min_y=min_y+(max_y-min_y)/2; + + unbound=FALSE; + + for(f=0;(flinedef))&&(!unbound);f++) + { + l=MapElem(wad->linedef,f); + + if (l->left!=-1) + { + si=MapElem(wad->sidedef,l->left); + + if (si->sector==-1) + unbound=TRUE; + } + } + + /* Position + */ + if (!PickPoint("Position MAP",&cx,&cy,PickDraw,PickKey,PickInfo)) + { + ClearMap(wad); + + if (tmp_wad) + { + if (CloseWad(wadf)!=WAD_OK) + GuiInfoBox("ERROR","CloseWad(%s)|%s",wadf,WadErrorString()); + + Release(wadf); + } + + return; + } + + /* Adjust co-ords + */ + for(f=0;fvertex);f++) + { + v=MapElem(wad->vertex,f); + x=v->x; + y=v->y; + MergeCoord(&x,&y); + v->x=x; + v->y=y; + } + + for(f=0;fthing);f++) + { + t=MapElem(wad->thing,f); + x=t->x; + y=t->y; + MergeCoord(&x,&y); + t->x=x; + t->y=y; + } + + /* If the map is a structure with some unbound left sidedefs, calculate + which sectors the new linedefs appear in (taken from the line's + midpoint) + */ + if (unbound) + { + Vertex *v1,*v2; + int lcx,lcy; + + secmap=Grab(sizeof(int)*MapSize(wad->linedef)); + + for(f=0;flinedef);f++) + { + l=MapElem(wad->linedef,f); + + v1=MapElem(wad->vertex,l->from); + v2=MapElem(wad->vertex,l->to); + + lcx=v1->x+((v2->x-v1->x)/2); + lcy=v1->y+((v2->y-v1->y)/2); + + secmap[f]=SectorHoldingPoint(lcx,lcy); + } + + /* See if floor and ceilings shold be adjusted + */ + if (YesNo("Adjust structure floor heights?")) + { + int t,min,diff; + + if ((t=SectorHoldingPoint(cx,cy))!=-1) + es=GETSECT(t); + else + es=NULL; + + if (es) + { + min=99999; + + for(f=0;fsector);f++) + { + s=MapElem(wad->sector,f); + + if (min>s->floor) + min=s->floor; + } + + diff=min-es->s.floor; + + for(f=0;fsector);f++) + { + s=MapElem(wad->sector,f); + s->floor-=diff; + s->ceiling-=diff; + } + } + } + + if (YesNo("Adjust structure ceiling heights?")) + { + int t; + + if ((t=SectorHoldingPoint(cx,cy))!=-1) + es=GETSECT(t); + else + es=NULL; + + if (es) + for(f=0;fsector);f++) + { + s=MapElem(wad->sector,f); + + if ((s->ceiling!=es->s.ceiling)&&(s->floors.ceiling)) + s->ceiling=es->s.ceiling; + } + } + } + else + secmap=NULL; + + /* Renumber tags? + */ + n_tag=0; + + if (YesNo("Renumber tags?")) + { + for(f=0;fl.tag); + + for(f=0;fs.tag); + } + + n_thing=MapSize(thing); + n_line=MapSize(linedef); + n_side=MapSize(sidedef); + n_sect=MapSize(sector); + n_vert=MapSize(vertex); + + /* Insert vertexes + */ + for(f=0;fvertex);f++) + { + v=MapElem(wad->vertex,f); + + ev=Grab(sizeof(EditVert)); + memcpy(&ev->v,v,sizeof(Vertex)); + ev->l=ListNew(sizeof(int)); + + o.select=SELECT_NONE; + o.data=ev; + + MapAdd(vertex,f+n_vert,&o); + } + + /* Insert sidedefs + */ + for(f=0;fsidedef);f++) + { + o.select=SELECT_NONE; + si=o.data=Copy(MapElem(wad->sidedef,f),sizeof(Sidedef)); + + if (si->sector!=-1) + si->sector+=n_sect; + + MapAdd(sidedef,f+n_side,&o); + } + + /* Insert linedefs and get associated sidedefs, vertex pointers and calc + bounding box + */ + for(f=0;flinedef);f++) + { + l=MapElem(wad->linedef,f); + el=Grab(sizeof(EditLine)); + + memcpy(&el->l,l,sizeof(Linedef)); + + if (el->l.tag) + el->l.tag+=n_tag; + + el->l.from+=n_vert; + el->l.to+=n_vert; + + el->l.right+=n_side; + + if (el->l.left!=-1) + el->l.left+=n_side; + + el->no=f+n_line; + el->sr=GETSIDE(el->l.right); + + if (l->left!=-1) + { + el->sl=GETSIDE(el->l.left); + + if ((unbound)&&(el->sl->sector==-1)) + el->sl->sector=secmap[f]; + } + else + el->sl=NULL; + + el->v[0]=GETVERT(el->l.from); + el->v[1]=GETVERT(el->l.to); + + IntListUniqAdd(el->v[0]->l,f+n_line); + IntListUniqAdd(el->v[1]->l,f+n_line); + + LineCalcBounding(el); + + o.select=SELECT_NONE; + o.data=el; + + MapAdd(linedef,f+n_line,&o); + } + + /* Insert sectors + */ + for(f=0;fsector);f++) + { + s=MapElem(wad->sector,f); + es=Grab(sizeof(EditSect)); + + memcpy(&es->s,s,sizeof(Sector)); + + es->no=f+n_sect; + + if (es->s.tag) + es->s.tag+=n_tag; + + es->v=ListNew(sizeof(Short)); + es->sr=ListNew(sizeof(EditLine *)); + es->sl=ListNew(sizeof(EditLine *)); + es->all=ListNew(sizeof(EditLine *)); + + o.select=SELECT_NONE; + o.data=es; + + MapAdd(sector,f+n_sect,&o); + } + + /* Insert things + */ + for(f=0;fthing);f++) + { + t=MapElem(wad->thing,f); + et=Grab(sizeof(EditThing)); + memcpy(&et->t,t,sizeof(Thing)); + o.select=SELECT_NONE; + o.data=et; + MapAdd(thing,f+n_thing,&o); + } + + SectorCalcContainingAll(); + + GuiInfoBox("NOTICE","Vertexes adjusted by %d|" + "Linedefs adjusted by %d|" + "Sidedefs adjusted by %d|" + "Sectors adjusted by %d|" + "Things adjusted by %d|" + "Tags adjusted by %d", + n_vert,n_line,n_side,n_sect,n_thing,n_tag); + + FullRedraw(); + + /* Tidy up + */ + ClearMap(wad); + + if (unbound) + Release(secmap); + + if (tmp_wad) + { + if (CloseWad(wadf)!=WAD_OK) + GuiInfoBox("ERROR","CloseWad(%s)|%s",wadf,WadErrorString()); + + Release(wadf); + } +} + + +/* END OF FILE */ diff --git a/editmult.c b/editmult.c new file mode 100644 index 0000000..3e78da0 --- /dev/null +++ b/editmult.c @@ -0,0 +1,582 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor MULTIMODE definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "editvar.h" + +#define VERTEX 1 +#define THING 2 + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static int GetIterType(Iterator *i,MultiObj **mr,EditVert **v,EditThing **t) +{ + int *f; + MultiObj *m; + + TRACE; + + f=IteratorData(*i); + m=GETMULTI(*f); + + switch(m->type) + { + case VERTEX: + *v=GETVERT(m->i); + break; + case THING: + *t=GETTHING(m->i); + break; + } + + *i=IteratorNext(*i); + + if (mr) + *mr=m; + + return(m->type); +} + + +static int GetType(MultiObj *m,EditVert **v,EditThing **t) +{ + TRACE; + + switch(m->type) + { + case VERTEX: + *v=GETVERT(m->i); + break; + case THING: + *t=GETTHING(m->i); + break; + } + + return(m->type); +} + + +static void SelectionCentre(int *x,int *y) +{ + int *f; + MultiObj *m; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + m=GETMULTI(*f); + + min_x=MIN(m->x,min_x); + min_y=MIN(m->y,min_y); + max_x=MAX(m->x,max_x); + max_y=MAX(m->y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +static void ApplySelectionCoords(void) +{ + MultiObj *m; + Iterator i; + EditVert *v; + EditThing *t; + + TRACE; + + i=ListIterator(selected); + + while(i) + switch(GetIterType(&i,&m,&v,&t)) + { + case THING: + t->t.x=m->x; + t->t.y=m->y; + break; + + case VERTEX: + v->v.x=m->x; + v->v.y=m->y; + break; + } +} + + +/* ---------------------------------------- EXPORTED UTILS +*/ +void GenerateMultiMap(void) +{ + MultiObj *m; + EditVert *v; + EditThing *t; + Object o; + int f; + + TRACE; + + if (!multimap) + multimap=MapNew(sizeof(MultiObj)); + else + { + for(f=0;ftype=VERTEX; + m->i=f; + m->x=v->v.x; + m->y=v->v.y; + o.data=m; + o.select=SELECT_NONE; + MapAdd(multimap,-1,&o); + } + + for(f=0;ftype=THING; + m->i=f; + m->x=t->t.x; + m->y=t->t.y; + o.data=m; + o.select=SELECT_NONE; + MapAdd(multimap,-1,&o); + } +} + +/* ---------------------------------------- GENERIC THING FUNCS +*/ +int PositionOnObject_MULTI(int x,int y,void *data) +{ + EditVert *v; + EditThing *t; + + TRACE; + + switch(GetType(data,&v,&t)) + { + case VERTEX: + return (PositionOnObject_VERTEX(x,y,v)); + break; + case THING: + return (PositionOnObject_THING(x,y,t)); + break; + } + + return (FALSE); +} + + +void SelectBox_MULTI(int x1,int y1,int x2,int y2) +{ + Object *o; + MultiObj *m; + int f; + + TRACE; + + for(f=0;fdata)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(m->x,m->y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_MULTI(void) +{ + TRACE; + return; +} + + +void DrawObject_MULTI(void *data, int selmode) +{ + MultiObj *m; + + TRACE; + m=data; + + switch(m->type) + { + case VERTEX: + DrawObject_VERTEX(GETVERT(m->i),selmode); + break; + case THING: + DrawObject_THING(GETTHING(m->i),selmode); + break; + default: + break; + } +} + + +void DrawObjectInfo_MULTI(void) +{ + MultiObj *m; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((m=GETMULTI(current)))) + GuiDrawInfoBox("MULTI MODE",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Object type : %s|" + "Number : %d", + (m->type == VERTEX ? "VERTEX" : "THING "), + m->i); + else + GuiDrawInfoBox("MULTI MODE",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Object type : |" + "Number : -"); +} + + +void DrawObjectHeader_MULTI(void) +{ + TRACE; +} + + +void MoveObject_MULTI(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + MultiObj *m; + List orig; + int *f; + Point p; + int cancel=FALSE; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + m=GETMULTI(*f); + p.x=m->x; + p.y=m->y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move Multiple Objects", + GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + memcpy(&p,IteratorData(i2),sizeof(Point)); + m=GETMULTI(*f); + m->x=p.x; + m->y=p.y; + + i=IteratorNext(i); + i2=IteratorNext(i2); + } + + ApplySelectionCoords(); + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + i=ListIterator(selected); + while(i) + { + f=IteratorData(i); + + m=GETMULTI(*f); + + m->x+=dmx; + m->y+=dmy; + + i=IteratorNext(i); + } + + ApplySelectionCoords(); + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_MULTI(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + MultiObj *m; + + TRACE; + + SelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + m=GETMULTI(*f); + + x=m->x; + y=m->y; + + Rotate(cx,cy,&x,&y,angle); + + m->x=x; + m->y=y; + + i=IteratorNext(i); + } + + ApplySelectionCoords(); +} + + +void ScaleObject_MULTI(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + MultiObj *m; + + TRACE; + + SelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + m=GETMULTI(*f); + + x=m->x; + y=m->y; + + Scale(cx,cy,&x,&y,scale); + + m->x=x; + m->y=y; + + i=IteratorNext(i); + } + + ApplySelectionCoords(); +} + + +void SetTagObject_MULTI(int tag) +{ + TRACE; +} + + +void LocateObject_MULTI(void *obj) +{ + MultiObj *m; + + TRACE; + + m=obj; + + ox=m->x-scale*SCRW/2; + oy=m->y+scale*SCRH/2; + +} + + +void ObjectInsert_MULTI(void) +{ + TRACE; +} + + +void ObjectDelete_MULTI(void) +{ + TRACE; +} + + +void ObjectMenu_MULTI(void) +{ + TRACE; +} + + +void ObjectKey_MULTI(GFXKey k) +{ + TRACE; +} + + +int ObjectHasTag_MULTI(void *obj, int tag) +{ + TRACE; + return(FALSE); +} + + +void SetSelect_MULTI(int i, int mode) +{ + Object *o; + MultiObj *m; + Map om; + + TRACE; + o=MapElem(multimap,i); + + if ((m=o->data)) + { + o->select=mode; + + if (m->type==VERTEX) + om=vertex; + else + om=thing; + + o=MapElem(om,m->i); + o->select=mode; + } +} + + +/* END OF FILE */ diff --git a/editsect.c b/editsect.c new file mode 100644 index 0000000..4c1cb8f --- /dev/null +++ b/editsect.c @@ -0,0 +1,1577 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor SECTOR definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "sectors.h" +#include "editvar.h" + +#include +#include + + +/* This is the data shared between the PickPoint() callback functions and the + Create function +*/ +typedef struct + { + int cx; + int cy; + Point p[64]; + int dx; + int dy; + int r; + double ai; + int sides; + } PickData; + +static PickData pick; + +/* This shows which LINEDEFs are drawn tagged +*/ +static List hilite=NULL; + + +/* ---------------------------------------- PickPoint() CALLBACKS +*/ +static void DrawVertSet(int *x, int *y) +{ + double ang; + int dx,dy; + int f; + + TRACE; + + pick.dx=*x; + pick.dy=*y; + + dx=pick.cx-pick.dx; + dy=pick.cy-pick.dy; + + /* Calc angle that the line is at + */ + if (dx==0) + if (dy<0) + ang=RAD(0); + else + ang=RAD(180); + else if (dy==0) + if (dx<0) + ang=RAD(90); + else + ang=RAD(270); + else + { + ang=atan((double)dx/(double)dy); + + if (dy>0) + ang-=RAD(180); + } + + /* Calc line len + */ + pick.r=Len(pick.cx,pick.cy,pick.dx,pick.dy); + + for(f=0;fv.x=pick.p[f].x; + v->v.y=pick.p[f].y; + v->l=ListNew(sizeof(int)); + + n=MapSize(vertex); + + o.select=SELECT_NONE; + o.data=v; + + MapAdd(vertex,n,&o); + ListAppend(l,&n); + } + + return(l); +} + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static int SelectColour(int selmode) +{ + TRACE; + + switch(selmode) + { + case SELECT_OVER: + return(OVERCOL); + break; + case SELECT_SELECTED: + return(SELCOL); + break; + default: + return(SECTCOL); + break; + } +} + + +void DrawSector(EditSect *s, int col, int check_tag) +{ + Iterator i; + EditLine *l; + + TRACE; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if (!(check_tag)||(!tag_highlight)||(!InIntList(hilite,l->no))) + MapLineD(l,col); + + i=IteratorNext(i); + } +} + + +static void RemoveHighlights(void) +{ + Iterator i; + Object *o; + EditLine *l; + int *n; + + i=ListIterator(hilite); + + while(i) + { + n=IteratorData(i); + + if ((l=GETLINE(*n))) + { + if (l->sr->sector>=0) + if ((o=MapElem(sector,l->sr->sector))) + DrawSector(o->data,SelectColour(o->select),FALSE); + + if ((l->sl)&&(l->sl->sector>=0)) + if ((o=MapElem(sector,l->sl->sector))) + DrawSector(o->data,SelectColour(o->select),FALSE); + } + + i=IteratorNext(i); + } +} + + +static void SectorSelectionCentre(int *x,int *y) +{ + int *f; + EditSect *s; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + min_x=MIN(s->min_x,min_x); + min_y=MIN(s->min_y,min_y); + max_x=MAX(s->max_x,max_x); + max_y=MAX(s->max_y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +/* ---------------------------------------- SECTOR VECTOR MAP UTILS +*/ +static int vno=0; +static char *vmap=NULL; + +static void InitVMAP(void) +{ + if (vnodata)&&(PositionOnObject_SECTOR(x,y,o->data))) + return(f); + } + + return(-1); +} + + +void SectorCalcContaining(int no,EditSect *s) +{ + int f; + EditLine *l; + int match; + + TRACE; + + ListEmpty(s->v); + ListEmpty(s->sr); + ListEmpty(s->sl); + ListEmpty(s->all); + InitVMAP(); + + for(f=0;fsr)&&(l->sr->sector==no)) + { + ListAppend(s->sr,&l); + ListAppend(s->all,&l); + match=TRUE; + } + + if ((l->sl)&&(l->sl->sector==no)) + { + if (!match) + ListAppend(s->all,&l); + + ListAppend(s->sl,&l); + match=TRUE; + } + + if (match) + { + if (!vmap[l->l.from]) + { + ListAppend(s->v,&(l->l.from)); + vmap[l->l.from]=TRUE; + } + + if (!vmap[l->l.to]) + { + ListAppend(s->v,&(l->l.to)); + vmap[l->l.to]=TRUE; + } + } + } + } +} + + +void SectorCalcContainingAll(void) +{ + int f; + EditSect *s; + + TRACE; + + for(f=0;fall); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if ((l->sl)&&(l->sl->sector==s->no)&&(l->sr->sector==s->no)) + lmap[l->no]=TRUE; + + i=IteratorNext(i); + } + + /* Set the floor and ceiling + */ + strcpy(s->s.floor_t,floor); + strcpy(s->s.ceiling_t,ceiling); + + /* Now draw a trail through the linedefs, aligning textures as we go along + */ + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if (!lmap[l->no]) + { + track=TrackLinedef(l->no); + ox=0; + ti=ListIterator(track); + + while(ti) + { + n=IteratorData(ti); + + l=GETLINE(*n); + + if (((l->sr->sector==s->no)&&(flag&SSTYLE_FACING_IN))|| + ((l->sr->sector!=s->no)&&(flag&SSTYLE_FACING_OUT))) + { + if (strcmp(l->sr->upper,empty_texture)) + { + strcpy(l->sr->upper,upper); + + if (flag&SSTYLE_UPPER_PEG) + l->l.flags|=upper_peg_mask; + else if (!(flag&SSTYLE_LEAVE_PEG)) + l->l.flags&=~upper_peg_mask; + } + + if (strcmp(l->sr->middle,empty_texture)) + strcpy(l->sr->middle,middle); + + if (strcmp(l->sr->lower,empty_texture)) + { + strcpy(l->sr->lower,lower); + + if (flag&SSTYLE_LOWER_PEG) + l->l.flags|=lower_peg_mask; + else if (!(flag&SSTYLE_LEAVE_PEG)) + l->l.flags&=~lower_peg_mask; + } + + l->sr->x=ox; + lmap[l->no]=TRUE; + } + + if ((l->sl)&& + (((l->sl->sector==s->no)&&(flag&SSTYLE_FACING_IN))|| + ((l->sl->sector!=s->no)&&(flag&SSTYLE_FACING_OUT)))) + { + if (strcmp(l->sl->upper,empty_texture)) + { + strcpy(l->sl->upper,upper); + + if (flag&SSTYLE_UPPER_PEG) + l->l.flags|=upper_peg_mask; + else if (!(flag&SSTYLE_LEAVE_PEG)) + l->l.flags&=~upper_peg_mask; + } + + if (strcmp(l->sl->middle,empty_texture)) + strcpy(l->sl->middle,middle); + + if (strcmp(l->sl->lower,empty_texture)) + { + strcpy(l->sl->lower,lower); + + if (flag&SSTYLE_LOWER_PEG) + l->l.flags|=lower_peg_mask; + else if (!(flag&SSTYLE_LEAVE_PEG)) + l->l.flags&=~lower_peg_mask; + } + + l->sl->x=ox; + lmap[l->no]=TRUE; + } + + ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + + ti=IteratorNext(ti); + } + + ListClear(track); + } + + i=IteratorNext(i); + } +} + + +/* ---------------------------------------- GENERIC SECTOR FUNCS +*/ +int PositionOnObject_SECTOR(int x,int y,void *data) +{ + int cross; + EditSect *s; + EditLine *l; + Vertex *vi,*vj; + Iterator i; + + TRACE; + + s=data; + + if (BOXBOUND(x,y,s->min_x,s->min_y,s->max_x,s->max_y)) + { + cross=FALSE; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + /* Linedefs that have a right and left sidedef pointing at the + same sector are not counted + */ + if (!((l->sr)&&(l->sl)&&(l->sl->sector==l->sr->sector))) + { + vi=&(l->v[0]->v); + vj=&(l->v[1]->v); + + /* This code is taken from comp.graphics.algorithms FAQ 2.03 + */ + if ((((vi->y<=y) && (yy)) || + ((vj->y<=y) && (yy))) && + (x < (vj->x - vi->x) * (y - vi->y) / + (vj->y - vi->y) + vi->x)) + cross=!cross; + } + + i=IteratorNext(i); + } + + return(cross); + } + else + return(FALSE); +} + + +/* This code is kept as a semi-working base if the routine based on the + comp.graphics.algorithm FAQ fails (this could be as I don't do it on a list + of ordered vertexes as the original does - doing on a line basis should be + the same though). +*/ +int OLD_PositionOnObject_SECTOR(int x,int y,void *data) +{ + int x_no; + int y_no; + EditSect *s; + EditLine *l; + Iterator i; + + TRACE; + + s=data; + + if (BOXBOUND(x,y,s->min_x,s->min_y,s->max_x,s->max_y)) + { + x_no=0; + y_no=0; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + /* Linedefs that have a right and left sidedef pointing at the + same sector are not counted + */ + if (!((l->sr)&&(l->sl)&&(l->sl->sector==l->sr->sector))) + { + /* This is a bit (understatement) kludgy, but we do 2 line + crossing checks, one in X and one in the Y direction. This + way we can omit a lot of extra checking for lines bisecting + shared vertexes and the like. + */ + if (LinesCross(s->min_x,y,x,y, + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)) + x_no++; + + if (LinesCross(x,s->min_y,x,y, + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)) + y_no++; + } + + i=IteratorNext(i); + } + + /* Odd number of crossed lines means we're in the sector + */ + return((x_no%2)||(y_no%2)); + } + else + return(FALSE); +} + + +void SelectBox_SECTOR(int x1,int y1,int x2,int y2) +{ + Object *o; + EditSect *s; + int f; + + TRACE; + + for(f=0;fdata)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(s->min_x,s->min_y,x1,y1,x2,y2))&& + (BOXBOUND(s->max_x,s->max_y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_SECTOR(void) +{ + Object *o; + EditSect *s; + int id; + int f; + + if ((id=SelectSector())!=SECTOR_NULLID) + { + ClearSelection(); + + for(f=0;fdata)&&(s->s.special==id)) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } +} + + +void DrawObject_SECTOR(void *data, int selmode) +{ + static int drawn=FALSE; + Object *o; + EditSect *s; + EditLine *l; + int sel; + int f; + + TRACE; + + if (!hilite) + hilite=ListNew(sizeof(int)); + + s=data; + + /* If the current object has changed, remove the highlighted tag objects + */ + if ((current==-1)&&(drawn)) + { + drawn=FALSE; + RemoveHighlights(); + ListEmpty(hilite); + } + + /* Draw tagged linedefs + */ + if ((tag_highlight)&&(current==s->no)) + { + RemoveHighlights(); + ListEmpty(hilite); + + if (s->s.tag) + { + drawn=TRUE; + + for(f=0;fl.tag==s->s.tag)&&(LineOnDisplay(l))) + { + sel=FALSE; + + if (l->sr->sector>=0) + if ((o=MapElem(sector,l->sr->sector))) + sel=(o->select!=SELECT_NONE); + + if ((l->sl)&&(l->sl->sector>=0)) + if ((o=MapElem(sector,l->sl->sector))) + sel|=(o->select!=SELECT_NONE); + + if (!sel) + { + IntListUniqAdd(hilite,f); + MapLineD(l,TAGCOL); + } + } + } + + } + + DrawSector(s,SelectColour(selmode),TRUE); +} + + +void DrawObjectInfo_SECTOR(void) +{ + EditSect *s; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((s=GETSECT(current)))) + GuiDrawInfoBox("SECTOR",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Sector Number : %-5d|" + "Floor : %-5d|" + "Ceiling : %-5d|" + "Height : %-5d|" + "Light : %-5d|" + "Floor texture : %-10s|" + "Ceiling texture : %-10s|" + "Sector Type : %-30s|" + "Tag : %-5d", + current, + s->s.floor, + s->s.ceiling, + s->s.ceiling-s->s.floor, + s->s.light, + s->s.floor_t, + s->s.ceiling_t, + SectorName(s->s.special), + s->s.tag); + else + GuiDrawInfoBox("SECTOR",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Sector Number : -|" + "Floor : -|" + "Ceiling : -|" + "Height : -|" + "Light : -|" + "Floor texture : -|" + "Ceiling texture : -|" + "Sector Type : %-30s|" + "Tag : -","-"); +} + + +void DrawObjectHeader_SECTOR(void) +{ + if (tag_highlight) + GFX_print(0,FH,WHITE,"Tag highlight: ON"); + else + GFX_print(0,FH,WHITE,"Tag highlight: OFF"); + + switch(sector_move) + { + case MOVE_ALL: + GFX_print(SCRW/2,FH,WHITE,"Move mode: ALL"); + break; + case MOVE_LEFT: + GFX_print(SCRW/2,FH,WHITE,"Move mode: LEFT"); + break; + case MOVE_RIGHT: + GFX_print(SCRW/2,FH,WHITE,"Move mode: RIGHT"); + break; + } +} + + +void MoveObject_SECTOR(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditSect *s; + EditLine *l; + EditVert *v; + List orig; + int *f; + Point p; + List vert; + int cancel; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + vert=ListNew(sizeof(EditVert *)); + + InitVMAP(); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + switch(sector_move) + { + case MOVE_ALL: + i2=ListIterator(s->all); + break; + + case MOVE_LEFT: + i2=ListIterator(s->sl); + break; + + case MOVE_RIGHT: + default: + i2=ListIterator(s->sr); + break; + } + + while(i2) + { + memcpy(&l,IteratorData(i2),sizeof(l)); + + if (!vmap[l->l.from]) + { + v=GETVERT(l->l.from); + ListAppend(vert,&v); + p.x=l->v[0]->v.x; + p.y=l->v[0]->v.y; + ListAppend(orig,&p); + vmap[l->l.from]=TRUE; + } + + if (!vmap[l->l.to]) + { + v=GETVERT(l->l.to); + ListAppend(vert,&v); + p.x=l->v[1]->v.x; + p.y=l->v[1]->v.y; + ListAppend(orig,&p); + vmap[l->l.to]=TRUE; + } + + i2=IteratorNext(i2); + } + + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move SECTOR",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(vert); + i2=ListIterator(orig); + + while(i2) + { + memcpy(&v,IteratorData(i),sizeof(v)); + + memcpy(&p,IteratorData(i2),sizeof(Point)); + v->v.x=p.x; + v->v.y=p.y; + + i2=IteratorNext(i2); + i=IteratorNext(i); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + i=ListIterator(vert); + while(i) + { + memcpy(&v,IteratorData(i),sizeof(v)); + + v->v.x+=dmx; + v->v.y+=dmy; + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + ListClear(vert); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_SECTOR(double angle) +{ + int cx,cy; + int x,y; + int *f; + Short *r; + Iterator i,i2; + EditSect *s; + EditVert *v; + + TRACE; + + InitVMAP(); + + SectorSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + i2=ListIterator(s->v); + + while(i2) + { + r=IteratorData(i2); + v=GETVERT(*r); + + if (!vmap[*r]) + { + vmap[*r]=TRUE; + + x=v->v.x; + y=v->v.y; + + Rotate(cx,cy,&x,&y,angle); + + v->v.x=x; + v->v.y=y; + } + + i2=IteratorNext(i2); + } + + i=IteratorNext(i); + } +} + + +void ScaleObject_SECTOR(double scale) +{ + int cx,cy; + int x,y; + int *f; + Short *r; + Iterator i,i2; + EditSect *s; + EditVert *v; + + TRACE; + + InitVMAP(); + + SectorSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + i2=ListIterator(s->v); + + while(i2) + { + r=IteratorData(i2); + v=GETVERT(*r); + + if (!vmap[*r]) + { + vmap[*r]=TRUE; + + x=v->v.x; + y=v->v.y; + + Scale(cx,cy,&x,&y,scale); + + v->v.x=x; + v->v.y=y; + } + + i2=IteratorNext(i2); + } + + i=IteratorNext(i); + } +} + + +void SetTagObject_SECTOR(int tag) +{ + int *f; + Iterator i; + EditSect *s; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.tag=tag; + i=IteratorNext(i); + } +} + + +void LocateObject_SECTOR(void *obj) +{ + int cx,cy; + EditSect *s; + + TRACE; + + s=obj; + cx=s->min_x+(s->max_x-s->min_x)/2; + cy=s->min_y+(s->max_y-s->min_y)/2; + ox=cx-scale*SCRW/2; + oy=cy+scale*SCRH/2; +} + + +void ObjectInsert_SECTOR(void) +{ +# define SM_UNBOUND 1 +# define SM_POLY 2 + + static PLAT_MENU sector_insert_menu[]= + { + {"Create unbound sector",SM_UNBOUND}, + {"Create polygon",SM_POLY}, + {NULL,GUI_CANCEL} + }; + + TRACE; + + switch(GUI_menu("Sector",ms.x,ms.y,sector_insert_menu,GUI_CANCEL)) + { + case SM_UNBOUND: + { + int sec; + + sec=CreateUnboundSector(normal_sector,default_floor_height, + default_ceiling_height,default_light_level, + 0,empty_texture,empty_texture); + + GuiInfoBox("NOTICE","A sector number %d has been created.|" + "SIDEDEFS will have to bound to the sector " + "before it|becomes visible and edittable.",sec); + + FullRedraw(); + break; + } + + case SM_POLY: + { + static int last_sides=4; + List sel; + + nosides_dialog[D_NOSIDES].data.i=last_sides; + + if (GUI_dialog("Create sector",D_NOSIDES_NO,nosides_dialog)) + { + pick.sides=nosides_dialog[D_NOSIDES].data.i; + + if ((pick.sides<3)||(pick.sides>64)) + { + GuiInfoBox("ERROR","Only enter a value between 3 and 64"); + FullRedraw(); + break; + } + else + if (PickPoint("Select centre of new sector", + &pick.cx,&pick.cy,NULL,NULL,NULL)) + { + pick.ai=RAD(360.0/pick.sides); + + if (PickPoint("Select the width and rotation " + "of the sector",&pick.dx,&pick.dy, + DrawVertSet,NULL,NULL)) + { + /* Merge identical vertices from the list and + check that the vertices will not be dubious + */ + if ((sel=GenVertList())) + { + if (!CreateSector(sel)) + { + Iterator i; + Object *o; + EditVert *v; + int *n; + + i=ListIterator(sel); + + while(i) + { + n=IteratorData(i); + o=MapElem(vertex,*n); + v=o->data; + + ListClear(v->l); + Release(v); + o->data=NULL; + + i=IteratorNext(i); + } + } + else + { + FullRedraw(); + last_sides=pick.sides; + } + + ListClear(sel); + } + else + { + GuiInfoBox("ERROR","Shape makes no sense"); + FullRedraw(); + break; + } + } + } + } + + break; + } + + default: + break; + } +} + + +void ObjectDelete_SECTOR(void) +{ + TRACE; + + GuiInfoBox("NOTICE","Sector not deleted| |" + "Sectors are automatically deleted|" + "when saving the map if no LINEDEFs|" + "are bound to it."); + FullRedraw(); +} + + +void ObjectMenu_SECTOR(void) +{ + Iterator i; + EditSect *s; + int *f; + int cancel; + + TRACE; + + cancel=FALSE; + + switch(GUI_menu("Sector",ms.x,ms.y,sector_popup,GUI_CANCEL)) + { + case TM_FLOOR: + s=SelHead(); + sector_fl_dialog[D_SECTOR_FLOOR].data.i=s->s.floor; + + if (GUI_dialog("Floor height",D_SECTOR_FL_NO,sector_fl_dialog)) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.floor=sector_fl_dialog[D_SECTOR_FLOOR].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + break; + + case TM_CEILING: + s=SelHead(); + sector_ce_dialog[D_SECTOR_CEILING].data.i=s->s.ceiling; + + if (GUI_dialog("Ceiling height",D_SECTOR_CE_NO,sector_ce_dialog)) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.ceiling=sector_ce_dialog[D_SECTOR_CEILING].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + break; + + case TM_LIGHT: + s=SelHead(); + sector_li_dialog[D_SECTOR_LIGHT].data.i=s->s.light; + + if (GUI_dialog("Light level",D_SECTOR_LI_NO,sector_li_dialog)) + { + i=ListIterator(selected); + + sector_li_dialog[D_SECTOR_LIGHT].data.i= + MIN(255,MAX(sector_li_dialog[D_SECTOR_LIGHT].data.i,0)); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.light=sector_li_dialog[D_SECTOR_LIGHT].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + break; + + case TM_TAG: + s=SelHead(); + tag_dialog[D_TAG].data.i=s->s.tag; + + if (GUI_dialog("Tag",D_TAG_NO,tag_dialog)) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.tag=tag_dialog[D_TAG].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + break; + + case TM_FLOOR_T: + { + DirName d; + + if ((GetFlat("Floor texture",d))) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + strcpy(s->s.floor_t,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_CEILING_T: + { + DirName d; + + if ((GetFlat("Ceiling texture",d))) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + strcpy(s->s.ceiling_t,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_TYPE: + { + int id; + + id=SelectSector(); + + if (id!=SECTOR_NULLID) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.special=id; + i=IteratorNext(i); + } + + FullRedraw(); + } + break; + } + + case TM_STYLE: + { + int flag; + DirName upper,middle,lower,floor,ceiling; + + if (ChooseSectorStyle(&flag,upper,middle,lower,floor,ceiling)) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + ApplySectorStyle(s,flag,upper,middle,lower,floor,ceiling); + i=IteratorNext(i); + } + } + + break; + } + + case TM_MOVE: + MoveObject_SECTOR(); + break; + + case TM_DELETE: + ObjectDelete_SECTOR(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } +} + + +void ObjectKey_SECTOR(GFXKey k) +{ + Iterator i; + EditSect *s; + int tmpsel; + int *f; + + /* Check keys that need no objects + */ + if (k.code==GFX_ASCII) + switch(toupper(k.ascii)) + { + case 'H': + tag_highlight=!tag_highlight; + FullRedraw(); + break; + + case 'M': + if (sector_move==MOVE_ALL) + sector_move=MOVE_RIGHT; + else if (sector_move==MOVE_RIGHT) + sector_move=MOVE_LEFT; + else if (sector_move==MOVE_LEFT) + sector_move=MOVE_ALL; + + DrawHeader(); + GFX_redraw(); + break; + + default: + break; + } + + tmpsel=TmpAddCurrent(); + + if (ListSize(selected)==0) + return; + + if (k.code!=GFX_ASCII) + switch(k.code) + { + default: + break; + } + else + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + switch(toupper(k.ascii)) + { + case ',': + s->s.floor-=8; + if (s->s.floor>s->s.ceiling) + s->s.floor+=8; + break; + + case '.': + s->s.floor+=8; + if (s->s.floor>s->s.ceiling) + s->s.floor-=8; + break; + + case '<': + s->s.ceiling-=8; + if (s->s.ceilings.floor) + s->s.ceiling+=8; + break; + + case '>': + s->s.ceiling+=8; + if (s->s.ceilings.floor) + s->s.ceiling-=8; + break; + + case '-': + s->s.light=MAX(0,s->s.light-16); + break; + + case '+': + s->s.light=MIN(255,s->s.light+16); + break; + + default: + break; + } + + i=IteratorNext(i); + } + + FullRedraw(); + } + + if (tmpsel) + ListEmpty(selected); +} + + +int ObjectHasTag_SECTOR(void *obj, int tag) +{ + EditSect *s; + + return ((s=obj)&&(s->s.tag==tag)); +} + + +/* END OF FILE */ diff --git a/editsel.c b/editsel.c new file mode 100644 index 0000000..7c64ece --- /dev/null +++ b/editsel.c @@ -0,0 +1,133 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor selection definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" + + + +/* After all that hard work of making the Object type the only thing that + the top level selection code needs to worry about, the Multi edit mode + goes and throws a spanner in the works.... +*/ +void SetSelect_GENERIC(int i, int mode) +{ + Object *o; + + o=MapElem(map,i); + o->select=mode; +} + + +int TmpAddCurrent(void) +{ + if ((ListSize(selected)==0)&&(current!=-1)) + { + ListAppend(selected,¤t); + return(TRUE); + } + else + return(FALSE); +} + + +void ClearSelection(void) +{ + int *n; + Iterator i; + + TRACE; + + if (map) + { + if (current!=-1) + SetSelect(current,SELECT_NONE); + + i=ListIterator(selected); + + while(i) + { + n=IteratorData(i); + SetSelect(*n,SELECT_NONE); + i=IteratorNext(i); + } + } + + selected=ListEmpty(selected); + current=-1; +} + + +void ClearSelectionLeaveCurrent(void) +{ + int *n; + Iterator i; + + TRACE; + + if (map) + { + i=ListIterator(selected); + + while(i) + { + n=IteratorData(i); + SetSelect(*n,SELECT_NONE); + i=IteratorNext(i); + } + } + + selected=ListEmpty(selected); +} + + +void *SelHead(void) +{ + Iterator i; + int *f; + Object *o; + void *p; + + TRACE; + + i=ListIterator(selected); + p=NULL; + + if ((f=IteratorData(i))) + { + o=MapElem(map,*f); + p=o->data; + } + + IteratorClear(i); + + return(p); +} + + +/* END OF FILE */ diff --git a/editsrot.c b/editsrot.c new file mode 100644 index 0000000..b6764d1 --- /dev/null +++ b/editsrot.c @@ -0,0 +1,76 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor scale and rotation routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" + +#include + + +/* ---------------------------------------- ROTATION ROUTINES +*/ +void Rotate(int cx,int cy,int *x,int *y, double ang) +{ + double r,t; + + TRACE; + + ang=RAD(ang); + + *x-=cx; + *y-=cy; + + r=hypot((double)*x,(double)*y); + t=atan2((double)*y,(double)*x); + + *x=(int)(r*cos(t+ang)+0.5); + *y=(int)(r*sin(t+ang)+0.5); + + *x+=cx; + *y+=cy; +} + + +/* ---------------------------------------- SCALE ROUTINES +*/ +void Scale(int cx,int cy,int *x,int *y, double sc) +{ + TRACE; + + *x-=cx; + *y-=cy; + + *x=(int)((*x)*sc); + *y=(int)((*y)*sc); + + *x+=cx; + *y+=cy; +} + + +/* END OF FILE */ diff --git a/editthng.c b/editthng.c new file mode 100644 index 0000000..ecc9dc6 --- /dev/null +++ b/editthng.c @@ -0,0 +1,636 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor THING definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "editvar.h" + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static void ThingSelectionCentre(int *x,int *y) +{ + int *f; + EditThing *t; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + + min_x=MIN(t->t.x,min_x); + min_y=MIN(t->t.y,min_y); + max_x=MAX(t->t.x,max_x); + max_y=MAX(t->t.y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +/* ---------------------------------------- GENERIC THING FUNCS +*/ +int PositionOnObject_THING(int x,int y,void *data) +{ + EditThing *t; + int r; + + TRACE; + + t=data; + r=ThingRadius(t->t.type,NULL); + + return (RADBOUND(x,y,t->t.x,t->t.y,r)); +} + + +void SelectBox_THING(int x1,int y1,int x2,int y2) +{ + Object *o; + EditThing *t; + int f; + + TRACE; + + for(f=0;fdata)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(t->t.x,t->t.y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_THING(void) +{ + Object *o; + EditThing *t; + int id; + int f; + + if ((id=SelectThing())!=THING_NULLID) + { + ClearSelection(); + + for(f=0;fdata)&&(t->t.type==id)) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } +} + + +void DrawObject_THING(void *data, int selmode) +{ + EditThing *t; + int a; + int lx,ly; + int r; + int col; + + TRACE; + t=data; + + a=((t->t.ang+22)/45%8); + r=ThingRadius(t->t.type,&col); + + switch(selmode) + { + case SELECT_OVER: + col=OVERCOL; + break; + case SELECT_SELECTED: + col=SELCOL; + break; + default: + break; + } + + lx=t->t.x+(t_arrow[a].x*r); + ly=t->t.y+(t_arrow[a].y*r); + + MapCircle(t->t.x,t->t.y,r,col); + DrawArrow(t->t.x,t->t.y,lx,ly,col); +} + + +void DrawObjectInfo_THING(void) +{ + EditThing *ti; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((ti=GETTHING(current)))) + GuiDrawInfoBox("THING",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Thing No : %d|" + "Thing Id : %d|" + "Angle : %s (%d)|" + "Flags : %s (0x%.2x)|" + "Name : %-60s", + current, + ti->t.type, + ANGLESTR(ti->t.ang),ti->t.ang, + ThingFlagText((int)ti->t.opt),ti->t.opt, + ThingName(ti->t.type)); + else + GuiDrawInfoBox("THING",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Thing No : -|" + "Thing Id : -|" + "Angle : -|" + "Flags : - (-)|" + "Name : %-60s",""); +} + + +void DrawObjectHeader_THING(void) +{ +} + + +void MoveObject_THING(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditThing *t; + List orig; + int *f; + Point p; + int cancel=FALSE; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + p.x=t->t.x; + p.y=t->t.y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move THING",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + memcpy(&p,IteratorData(i2),sizeof(Point)); + t=GETTHING(*f); + t->t.x=p.x; + t->t.y=p.y; + + i=IteratorNext(i); + i2=IteratorNext(i2); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + i=ListIterator(selected); + while(i) + { + f=IteratorData(i); + + t=GETTHING(*f); + + t->t.x+=dmx; + t->t.y+=dmy; + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_THING(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditThing *t; + + TRACE; + + ThingSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + + x=t->t.x; + y=t->t.y; + + Rotate(cx,cy,&x,&y,angle); + + t->t.x=x; + t->t.y=y; + + i=IteratorNext(i); + } +} + + +void ScaleObject_THING(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditThing *t; + + TRACE; + + ThingSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + + x=t->t.x; + y=t->t.y; + + Scale(cx,cy,&x,&y,scale); + + t->t.x=x; + t->t.y=y; + + i=IteratorNext(i); + } +} + + +void SetTagObject_THING(int tag) +{ + TRACE; +} + + +void LocateObject_THING(void *obj) +{ + EditThing *t; + + TRACE; + + t=obj; + + ox=t->t.x-scale*SCRW/2; + oy=t->t.y+scale*SCRH/2; +} + + +void ObjectInsert_THING(void) +{ + Object o; + EditThing *t; + int f; + + TRACE; + + t=Grab(sizeof(EditThing)); + memcpy(&t->t,&ed_thing,sizeof(Thing)); + t->t.x=SnapX(XToMap(ms.x)); + t->t.y=SnapY(YToMap(ms.y)); + + f=MapSize(thing); + + switch(insert_select) + { + case HOVER_NONE: + o.select=SELECT_NONE; + break; + case HOVER_ADD: + case HOVER_SINGLE: + o.select=SELECT_SELECTED; + break; + } + + o.data=t; + DrawObject_THING(t,o.select); + MapAdd(thing,f,&o); + + switch(insert_select) + { + case HOVER_NONE: + break; + case HOVER_ADD: + ListAppend(selected,&f); + break; + case HOVER_SINGLE: + ClearSelection(); + ListAppend(selected,&f); + FullRedraw(); + break; + } +} + + +void ObjectDelete_THING(void) +{ + Iterator i; + Object *o; + int *f; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + + o=MapElem(thing,*f); + + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; + + i=IteratorNext(i); + } + + ClearSelection(); + FullRedraw(); +} + + +void ObjectMenu_THING(void) +{ + EditThing *t; + int f,*s; + Iterator i; + int cancel; + int redraw=FALSE; + + TRACE; + + cancel=FALSE; + GFX_redraw(); + + switch(GUI_menu("Thing",ms.x,ms.y,thing_popup,GUI_CANCEL)) + { + case TM_TYPE: + { + Short id; + + id=(Short)SelectThing(); + + if (id!=THING_NULLID) + { + ed_thing.type=id; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.type=id; + i=IteratorNext(i); + } + + redraw=TRUE; + } + } + break; + + case TM_ANGLE: + { + int a; + + t=SelHead(); + a=t->t.ang; + + if ((a=GUI_radio_box + ("Angle",thing_angle,a,GUI_CANCEL))!=GUI_CANCEL) + { + ed_thing.ang=a; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.ang=a; + i=IteratorNext(i); + } + } + + redraw=TRUE; + } + break; + + case TM_FLAGS: + i=ListIterator(selected); + s=IteratorData(i); + t=GETTHING(*s); + f=t->t.opt; + + if (GUI_multi_box("Flags",ThingFlagArray(),&f)) + { + ed_thing.opt=f; + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.opt=ed_thing.opt; + i=IteratorNext(i); + } + + redraw=TRUE; + } + break; + + case TM_SNAP: + { + int orig_lock; + + orig_lock=grid_lock; + grid_lock=TRUE; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.x=SnapX(t->t.x); + t->t.y=SnapX(t->t.y); + i=IteratorNext(i); + } + + grid_lock=orig_lock; + redraw=TRUE; + + break; + } + + case TM_DELETE: + ObjectDelete_THING(); + break; + + case TM_MOVE: + MoveObject_THING(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } + else if (redraw) + FullRedraw(); +} + + +void ObjectKey_THING(GFXKey k) +{ +} + + +int ObjectHasTag_THING(void *obj, int tag) +{ + return(FALSE); +} + + +/* END OF FILE */ diff --git a/editvar.c b/editvar.c new file mode 100644 index 0000000..b28fc9f --- /dev/null +++ b/editvar.c @@ -0,0 +1,383 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor global varaiable definitions + + Note that the lindefs, vertices, etc here are copied from the WadMap + loaded prior to editting. They are then reconverted back to the WadMap + for saving. + + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "editvar.h" + + +/* ---------------------------------------- EDIT TYPES +*/ + +char *edit_str[]={"Sector","Linedef","Vertex","Thing","Multimode"}; + + +/* ---------------------------------------- EDIT VARS +*/ + +void HandleMoveKey(GFXKey k,int check_mouse); + +int edit_mode=SECTOR_MODE; + +Map vertex=NULL; +Map linedef=NULL; +Map sidedef=NULL; +Map sector=NULL; +Map thing=NULL; +Map multimap=NULL; + +int SCRW; +int SCRH; +int FH; + +int scale=5; +int ox; +int oy; + +GFXMouse ms; + +int quit; + +int agrid; + +int current=-1; +List selected=NULL; + +/* This variable should be set to try by any actions in the generic object + routines that have generated a new selection list. +*/ +int new_selection=FALSE; + +Thing ed_thing={0,0,0,1,0x07}; + +/* This variable stops the DrawObjectInfo() routine being called on redraws +*/ +int draw_current_info=TRUE; + +/* ---------------------------------------- USED AS GENERIC FUNCTIONS AND VALUES +*/ + +/* Data in all these functions is the Object.data pointer +*/ +int (*PositionOnObject)(int x, int y, void *data); +void (*SelectBox)(int x1, int y1, int x2, int y2); +void (*SelectByType)(void); +void (*DrawObject)(void *data, int selmode); +void (*DrawObjectInfo)(void); +void (*DrawObjectHeader)(void); +void (*MoveObject)(void); +void (*RotateObject)(double angle); +void (*ScaleObject)(double scale); +void (*SetTagObject)(int tag); +void (*LocateObject)(void *obj); +void (*ObjectMenu)(void); +void (*ObjectInsert)(void); +void (*ObjectDelete)(void); +void (*ObjectKey)(GFXKey k); +int (*ObjectHasTag)(void *obj, int tag); +void (*SetSelect)(int i, int mode); + +char *typename; +Map map; + + +/* ---------------------------------------- MENUS AND DIALOGS +*/ +PLAT_MENU thing_popup[]={ + {"Change type",TM_TYPE}, + {"Change angle",TM_ANGLE}, + {"Change flags",TM_FLAGS}, + {"Snap selected things",TM_SNAP}, + {"Move",TM_MOVE}, + {"Delete",TM_DELETE}, + {NULL,GUI_CANCEL} + }; + +PLAT_RADIO thing_angle[]={ + {"N",90}, + {"NE",45}, + {"E",0}, + {"SE",315}, + {"S",270}, + {"SW",225}, + {"W",180}, + {"NW",135}, + {NULL,GUI_CANCEL} + }; + +PLAT_MENU vertex_popup[]={ + {"Chain selected vertices",TM_CHAIN}, + {"Chain selected vertices " + "into a sector",TM_CHAIN_SECTOR}, + {"Merge selected vertices",TM_MERGE}, + {"Snap selected vertices",TM_SNAP}, + {"Move",TM_MOVE}, + {"Delete",TM_DELETE}, + {NULL,GUI_CANCEL} + }; + +PLAT_MENU right_popup[]= + { + {"Change upper texture",TM_UPPER_T_R}, + {"Change middle texture",TM_MIDDLE_T_R}, + {"Change lower texture",TM_LOWER_T_R}, + {"Change texture offset",TM_OFFSET_R}, + {"Adjust texture offset",TM_ADJUST_R}, + {"Change sector",TM_SECTOR_R}, + {"Align textures",TM_ALIGN_R}, + + {NULL,GUI_CANCEL} + }; + +PLAT_MENU left_popup[]= + { + {"Change upper texture",TM_UPPER_T_L}, + {"Change middle texture",TM_MIDDLE_T_L}, + {"Change lower texture",TM_LOWER_T_L}, + {"Change texture offset",TM_OFFSET_L}, + {"Adjust texture offset",TM_ADJUST_L}, + {"Change sector",TM_SECTOR_L}, + {"Align textures",TM_ALIGN_L}, + + {NULL,GUI_CANCEL} + }; + +PLAT_MENU linedef_popup[]= + { + {"Change linedef flags",TM_FLAGS}, + {"Change linedef type",TM_TYPE}, + {"Swap sides",TM_SWAP_SIDES}, + {"Split line",TM_SPLIT_LINE}, + {"Select trail from this linedef",TM_TRACK_LINE}, + {"Join linedefs with steps",TM_STEPS}, + + {"Right sidedef =>",TM_RIGHT_SIDE}, + {"Left sidedef =>",TM_LEFT_SIDE}, + + {"Change tag",TM_TAG}, + {"Move",TM_MOVE}, + {"Delete",TM_DELETE}, + {NULL,GUI_CANCEL} + }; + +PLAT_MENU sector_popup[]= + { + {"Change floor height",TM_FLOOR}, + {"Change ceiling height",TM_CEILING}, + {"Change light level",TM_LIGHT}, + {"Change tag",TM_TAG}, + {"Change floor",TM_FLOOR_T}, + {"Change ceiling",TM_CEILING_T}, + {"Change type",TM_TYPE}, + {"Paint sector in style",TM_STYLE}, + + {"Move",TM_MOVE}, + {"Delete",TM_DELETE}, + {NULL,GUI_CANCEL} + }; + +PLAT_MENU multi_popup[]= + { + {"Move",TM_MOVE}, + {NULL,GUI_CANCEL} + }; + + +PLAT_DIALOG offset_dialog[D_OFFSET_NO]= + { + {"X-offset",PLAT_DIAL_INTEGER,{0}}, + {"Y-offset",PLAT_DIAL_INTEGER,{0}} + }; + +PLAT_DIALOG sectorn_dialog[D_OFFSET_NO]= + { + {"Sector no",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG coord_dialog[D_COORD_NO]= + { + {"X",PLAT_DIAL_INTEGER,{0}}, + {"Y",PLAT_DIAL_INTEGER,{0}} + }; + +PLAT_DIALOG vertex_dialog[D_VERTEX_NO]= + { + {"Vertex from",PLAT_DIAL_INTEGER,{0}}, + {"Vertex to",PLAT_DIAL_INTEGER,{0}} + }; + +PLAT_DIALOG sector_fl_dialog[D_SECTOR_FL_NO]= + { + {"Floor height",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG sector_ce_dialog[D_SECTOR_CE_NO]= + { + {"Ceiling height",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG sector_li_dialog[D_SECTOR_LI_NO]= + { + {"Light level",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG sector_val_dialog[D_SECTOR_VAL_NO]= + { + {"Light level",PLAT_DIAL_INTEGER,{0}}, + {"Floor height",PLAT_DIAL_INTEGER,{0}}, + {"Ceiling height",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG tag_dialog[D_TAG_NO]= + { + {"Tag",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG scale_dialog[D_SCALE_NO]= + { + {"Scale",PLAT_DIAL_DOUBLE,{0}}, + }; + +PLAT_DIALOG rotate_dialog[D_ROTATE_NO]= + { + {"Angle",PLAT_DIAL_DOUBLE,{0}}, + }; + +PLAT_DIALOG objno_dialog[D_OBJNO_NO]= + { + {"Object number",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG nosides_dialog[D_NOSIDES_NO]= + { + {"Number of sides",PLAT_DIAL_INTEGER,{0}}, + }; + + +/* ---------------------------------------- DRAWING TABLES +*/ +Point t_arrow[8]={{1,0}, + {1,1}, + {0,1}, + {-1,1}, + {-1,0}, + {-1,-1}, + {0,-1}, + {1,-1}}; + +char *angle_str[8]={"E","NE","N","NW","W","SW","S","SE"}; + + +/* ---------------------------------------- HELP PAGES +*/ +char *general_help_keys= + "F1 - general help |" + "F2 - edit mode help |" + "Escape - finish editting |" + "Cursor keys - move |" + "Shift + Cursor keys - move quickly |" + "Page down/up - zoom in/out |" + "Q/W - alter grid lock scale |" + "G - grid lock lines on/off |" + "X - grid snap on/off |" + "Tab/Shift + Tab - next/previous edit mode |" + "V - VERTEX edit mode |" + "L - LINEDEF edit mode |" + "S - SECTOR edit mode |" + "T - THING edit mode |" + "C - MULTI edit mode |" + "F9 - deselect all |" + "Shift + F9 - invert selection |" + "F10 - select all |" + "Shift + F10 - select by type (if applicable) |" + "F11/Shift + F11 - locate next/previous selection |" + "DELETE - delete selected objects |" + "INSERT - insert new object |" + "F3 - merge a PWAD map |" + "F4 - move selected objects |" + "F5 - rotate selected objects |" + "[ - rotate 5 degrees left |" + "] - rotate 5 degrees right |" + "F6 - scale selected objects |" + "{ - scale by 90% |" + "} - scale by 110% |" + "F7 - set tag (if applicable) |" + "Shift + F7 - select objects with tag |" + "F8 - locate an object number |" + "Shift + F8 - locate and select object number|" + "R - redraw [useful if selected |" + " sectors look unselected] |" + " |" + "Note: Grid lock not honoured on rotate or scale "; + +char *general_help_mouse= + "Left button - select object |" + "Ctrl + Left button - additionally select object |" + "Shift + Left button - select objects in box |" + "Ctrl + Shift + Left button - additionally select objects in box|" + "Right button - pop-up object menu |" + "Middle button - move selected objects "; + +char *mode_help[]= + { + /* SECTOR + */ + "M - change sector move mode |" + "H - toggle SECTOR tag highligting|" + ", - decrease sector floor by 8 |" + ". - increase sector floor by 8 |" + "< - decrease sector ceiling by 8 |" + "> - increase sector ceiling by 8 |" + "- - decrease lighting level by 16|" + "+ - increase lighting level by 16", + + /* LINEDEF + */ + "H - toggle LINEDEF tag highligting |" + "F12 - perform checks for LINEDEF textures", + + /* VERTEX + */ + "F12 - remove vertices to bound to linedefs", + + /* THING + */ + "No additional key functions", + + /* MULTI + */ + "No additional key functions" + }; + + +/* END OF FILE */ diff --git a/editvar.h b/editvar.h new file mode 100644 index 0000000..410b4dd --- /dev/null +++ b/editvar.h @@ -0,0 +1,619 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor global variable definitions + + $Id$ + +*/ + +#ifndef _EDITVAR_H + +#define _EDITVAR_H + +#include "things.h" +#include "linedefs.h" +#include "wad.h" +#include "map.h" +#include "list.h" +#include "platgui.h" +#include "gui.h" +#include "mem.h" + +#define MAXLEN 1024 + + +/* ---------------------------------------- EDIT COLOURS +*/ +#define GRIDCOL V_RGB(0x20,0x20,0x80) + +#define LINECOL V_RGB(0xa0,0x9a,0x90) + +#define SECTCOL V_RGB(0xc0,0x00,0x00) + +#define VERTCOL V_RGB(0xff,0xff,0xff) +#define VERTBOXCOL V_RGB(0x60,0x60,0x60) + +#define THINGCOL V_RGB(0xa0,0x10,0x10) +#define SELCOL V_RGB(0xff,0xff,0x00) +#define OVERCOL V_RGB(0xc0,0xc0,0x00) + +#define TAGCOL V_RGB(0xff,0xe0,0xe0) + + +/* ---------------------------------------- EDIT TYPES +*/ + +#define SECTOR_MODE 0 +#define LINEDEF_MODE 1 +#define VERTEX_MODE 2 +#define THING_MODE 3 +#define MULTI_MODE 4 + +#define NEXT_MODE(m) ((m == MULTI_MODE) ? SECTOR_MODE : m+1) +#define PREV_MODE(m) ((m == SECTOR_MODE) ? MULTI_MODE : m-1) + +extern char *edit_str[]; + +#define SELECT_NONE 0 +#define SELECT_OVER 1 +#define SELECT_SELECTED 2 + + +typedef struct + { + int x,y; + } Point; + +/* Edittable types of the lumps from the WAD +*/ +typedef struct + { + Vertex v; + List l; + } EditVert; + +typedef struct + { + int no; + Linedef l; + Sidedef *sr; + Sidedef *sl; + EditVert *v[2]; + int min_x; + int min_y; + int max_x; + int max_y; + } EditLine; + +typedef struct + { + int no; + Sector s; + int min_x; + int min_y; + int max_x; + int max_y; + List v; + List sr; + List sl; + List all; + } EditSect; + +typedef struct + { + Thing t; + } EditThing; + +typedef struct + { + int type; + int i; + int x,y; + } MultiObj; + +typedef struct + { + int select; + void *data; + } Object; + + +/* ---------------------------------------- EDIT VARS +*/ + +extern void HandleMoveKey(GFXKey k,int check_mouse); + +extern int edit_mode; + +extern Map vertex; +extern Map linedef; +extern Map sidedef; +extern Map sector; +extern Map thing; +extern Map multimap; + +extern int SCRW; +extern int SCRH; +extern int FH; + +extern int scale; +extern int ox; +extern int oy; + +extern GFXMouse ms; + +extern int quit; + +extern int agrid; + +extern int current; +extern List selected; + +extern int new_selection; + +extern Thing ed_thing; + +extern int draw_current_info; + +/* ---------------------------------------- USED AS GENERIC FUNCTIONS AND VALUES +*/ + +/* Data in all these functions is the Object.data pointer +*/ +extern int (*PositionOnObject)(int x, int y, void *data); +extern void (*SelectBox)(int x1, int y1, int x2, int y2); +extern void (*SelectByType)(void); +extern void (*DrawObject)(void *data, int selmode); +extern void (*DrawObjectInfo)(void); +extern void (*DrawObjectHeader)(void); +extern void (*MoveObject)(void); +extern void (*RotateObject)(double angle); +extern void (*ScaleObject)(double scale); +extern void (*SetTagObject)(int tag); +extern void (*LocateObject)(void *obj); +extern void (*ObjectMenu)(void); +extern void (*ObjectInsert)(void); +extern void (*ObjectDelete)(void); +extern void (*ObjectKey)(GFXKey k); +extern int (*ObjectHasTag)(void *obj, int tag); +extern void (*SetSelect)(int i, int mode); + +extern char *typename; +extern Map map; + + +/* ---------------------------------------- MENUS AND DIALOGS +*/ +#define GUI_CANCEL -666 + +#define TM_TYPE 0 +#define TM_MOVE 1 +#define TM_DELETE 2 +#define TM_ANGLE 3 +#define TM_FLAGS 4 +#define TM_INSERT 5 +#define TM_UPPER_T_R 6 +#define TM_MIDDLE_T_R 7 +#define TM_LOWER_T_R 8 +#define TM_OFFSET_R 9 +#define TM_UPPER_T_L 10 +#define TM_MIDDLE_T_L 11 +#define TM_LOWER_T_L 12 +#define TM_OFFSET_L 13 +#define TM_FLOOR 14 +#define TM_CEILING 15 +#define TM_LIGHT 16 +#define TM_TAG 17 +#define TM_FLOOR_T 18 +#define TM_CEILING_T 19 +#define TM_SECTOR_R 20 +#define TM_SECTOR_L 21 +#define TM_CHAIN 22 +#define TM_CHAIN_SECTOR 23 +#define TM_ALIGN_R 24 +#define TM_ALIGN_L 25 +#define TM_SWAP_SIDES 26 +#define TM_SPLIT_LINE 27 +#define TM_MERGE 28 +#define TM_SNAP 29 +#define TM_STYLE 30 +#define TM_TRACK_LINE 31 +#define TM_STEPS 32 +#define TM_RIGHT_SIDE 33 +#define TM_LEFT_SIDE 34 +#define TM_ADJUST_R 35 +#define TM_ADJUST_L 36 + + +extern PLAT_MENU thing_popup[]; + +extern PLAT_RADIO thing_angle[]; + +extern PLAT_MENU vertex_popup[]; + +extern PLAT_MENU right_popup[]; +extern PLAT_MENU left_popup[]; +extern PLAT_MENU linedef_popup[]; + +extern PLAT_MENU sector_popup[]; + +extern PLAT_MENU multi_popup[]; + +#define NO_FIELDS(x) (sizeof(x)/sizeof(x[0])) + +#define D_OFFSET_NO 2 +#define D_OFFSET_OFFX 0 +#define D_OFFSET_OFFY 1 +extern PLAT_DIALOG offset_dialog[D_OFFSET_NO]; + + +#define D_SECTORN_NO 1 +#define D_SECTORN_SECNO 0 +extern PLAT_DIALOG sectorn_dialog[D_OFFSET_NO]; + + +#define D_COORD_NO 2 +#define D_COORD_X 0 +#define D_COORD_Y 1 +extern PLAT_DIALOG coord_dialog[D_COORD_NO]; + + +#define D_VERTEX_NO 2 +#define D_VERTEX_FROM 0 +#define D_VERTEX_TO 1 +extern PLAT_DIALOG vertex_dialog[D_VERTEX_NO]; + + +#define D_SECTOR_FL_NO 1 +#define D_SECTOR_FLOOR 0 +extern PLAT_DIALOG sector_fl_dialog[D_SECTOR_FL_NO]; + + +#define D_SECTOR_CE_NO 1 +#define D_SECTOR_CEILING 0 +extern PLAT_DIALOG sector_ce_dialog[D_SECTOR_CE_NO]; + + +#define D_SECTOR_LI_NO 1 +#define D_SECTOR_LIGHT 0 +extern PLAT_DIALOG sector_li_dialog[D_SECTOR_LI_NO]; + + +#define D_SECTOR_VAL_NO 3 +#define D_SVAL_LIGHT 0 +#define D_SVAL_FLOOR 1 +#define D_SVAL_CEILING 2 +extern PLAT_DIALOG sector_val_dialog[D_SECTOR_VAL_NO]; + + +#define D_TAG_NO 1 +#define D_TAG 0 +extern PLAT_DIALOG tag_dialog[D_TAG_NO]; + + +#define D_SCALE_NO 1 +#define D_SCALE 0 +extern PLAT_DIALOG scale_dialog[D_SCALE_NO]; + + +#define D_ROTATE_NO 1 +#define D_ROTATE 0 +extern PLAT_DIALOG rotate_dialog[D_ROTATE_NO]; + + +#define D_OBJNO_NO 1 +#define D_OBJNO 0 +extern PLAT_DIALOG objno_dialog[D_OBJNO_NO]; + + +#define D_NOSIDES_NO 1 +#define D_NOSIDES 0 +extern PLAT_DIALOG nosides_dialog[D_NOSIDES_NO]; + + + +/* ---------------------------------------- DRAWING TABLES +*/ +extern Point t_arrow[8]; + +extern char *angle_str[8]; + +#define ANGLESTR(a) (angle_str[(((a)+22)/45%8)]) + +/* ---------------------------------------- MACROS +*/ +#define PI_VAL 3.14159265358979323846 + +#define RAD(a) (PI_VAL/180.0*(a)) + +#define XToMap(x) (ox+((x)*scale)) +#define YToMap(y) (oy-((y)*scale)) + +#define MapToX(x) (((x)-ox)/scale) +#define MapToY(y) ((oy-(y))/scale) + +#define MapRect(x,y,w,h,c) \ + GFX_rect(MapToX(x),MapToY(y),(w)/scale,(h)/scale,c) + +#define MapLine(x1,y1,x2,y2,c) \ + GFX_line(MapToX(x1),MapToY(y1),MapToX(x2),MapToY(y2),c) + +#define MapLineD(l,c) GFX_line(MapToX((l)->v[0]->v.x), \ + MapToY((l)->v[0]->v.y), \ + MapToX((l)->v[1]->v.x), \ + MapToY((l)->v[1]->v.y),c) + +#define MapPlot(x,y,c) GFX_plot(MapToX(x),MapToY(y),c) + +#define MapCircle(x,y,r,c) \ + GFX_circle(MapToX(x),MapToY(y),(r)/scale,c) + +#define BOXBOUND(tx,ty,x1,y1,x2,y2) \ + (((tx)>=(x1))&&((tx)<=(x2))&&((ty)>=(y1))&&((ty)<=(y2))) +#define BOXBOUND_FUZZY(tx,ty,x1,y1,x2,y2,f) \ + (((tx)>=(x1-(f)))&&((tx)<=(x2+(f)))&&((ty)>=(y1-(f)))&&((ty)<=(y2+(f)))) + +#define ROUGHLY(a,b) (((a)>=(b)-0.01)&&((a)<=(b)+0.01)) + +#define RADBOUND(tx,ty,x,y,r) \ + (((tx)>=(x)-(r))&&((tx)<=(x)+(r))&& \ + ((ty)>=(y)-(r))&&((ty)<=(y)+(r))) + + +#define GETVERT(n) ((EditVert *)(((Object *)MapElem(vertex,(n)))->data)) +#define VERTFROM(m,n) ((EditVert *)(((Object *)MapElem((m),(n)))->data)) +#define GETLINE(n) ((EditLine *)(((Object *)MapElem(linedef,(n)))->data)) +#define GETSIDE(n) ((Sidedef *)(((Object *)MapElem(sidedef,(n)))->data)) +#define SIDEFROM(m,n) ((Sidedef *)(((Object *)MapElem((m),(n)))->data)) +#define GETSECT(n) ((EditSect *)(((Object *)MapElem(sector,(n)))->data)) +#define GETTHING(n) ((EditThing *)(((Object *)MapElem(thing,(n)))->data)) +#define GETMULTI(n) ((MultiObj *)(((Object *)MapElem(multimap,(n)))->data)) + +#define YESNO(x) ((x) ? "Yes":"No") + +/* ------------------------------ HELP PAGES +*/ +extern char *general_help_keys; +extern char *general_help_mouse; +extern char *mode_help[]; + + +/* ------------------------------ FUNCTION PROTOTYPES FOR ALL EDIT ROUTINES +*/ +void SectorCalcContaining(int no,EditSect *s); +void SectorCalcContainingAll(void); +int SnapX(int x); +int SnapY(int y); +int Len(int x1,int y1,int x2,int y2); +int LinesCross(int x1_1,int y1_1,int x1_2,int y1_2, + int x2_1,int y2_1,int x2_2,int y2_2); +int CalcTextureWidth(DirName u,DirName m,DirName l); +void LineCalcBounding(EditLine *l); +void SectorCalcBounding(EditSect *s); +int LineOnDisplay(EditLine *l); +int SectorOnDisplay(EditSect *s); +int PointOnDisplay(int x,int y,int r); +void DrawArrow(int x1,int y1,int x2,int y2,int c); +void DrawGrid(void); +void DrawMap(void); +void DrawHeader(void); +void FullRedraw(void); + +void SetSelect_GENERIC(int i, int mode); +int TmpAddCurrent(void); +void ClearSelection(void); +void ClearSelectionLeaveCurrent(void); +void *SelHead(void); + +int InIntList(List l, int i); +void IntListUniqAdd(List l, int i); +void IntListRm(List l, int i); + + +/* If set_class is TRUE then *type is set from the classes loaded in the + config file. + + The floor and ceiling values are used to decide which if the lower, middle + and upper textures to ask for. If the selected linedef style is not two + sided these values are ignored anyway and only the middle one on the right + sidedef is requested. +*/ +int GetLinedefValues(int set_class, + int r_floor,int l_floor,int r_ceiling,int l_ceiling, + int *type,int *flag,int *two, + DirName sr_upper,DirName sr_middle,DirName sr_lower, + DirName sl_upper,DirName sl_middle,DirName sl_lower); + +/* This supercedes the above function when creating sectors. + + THe floor, ceiling and light levels are in/out. The displayed dialog is + loaded with the values sent in and any changes are reflected on return. + + The in_floor and in_ceiling values are used to decide which of the + lower, middle and upper textures set up. If the selected linedef style + is not two sided these values are ignored anyway and only the middle + one on the right sidedef is set to non-empty. When doing comparisons it + is assumed that the in_ values are on the left of the linedefs. + + Note that for this routine rather than being individually requested the + linedef textures are obtained from the defined sector styles (unless there + are no sector styles). Style flags is also set to the flags for sector + style (unless there is no styles, in which case it's zero). + + Note the the sector flags for the style indicating if just the inward + or outward facing sidedefs have the textures applied will be ignored, ie. + both the right and left texture values will have the style applied. + + Returns FALSE if at any point the selections are cancelled. +*/ +int GetSectorValues(int *line_type, int *line_flag, int *two_sided, + int *floor, int *ceiling, int *light, + int in_floor, int in_ceiling, + int *style_flags, + DirName floor_t, DirName ceiling_t, + DirName sr_upper, DirName sr_middle, DirName sr_lower, + DirName sl_upper, DirName sl_middle, DirName sl_lower); + +void GenericCheckMouse(void); +int GetTexture(char *t,DirName d); +int GetFlat(char *t,DirName d); +int YesNo(char *fmt,...); + +/* If draw is not NULL it will be used to draw the selection thing. Note that + the x an y coming into the draw will NOT be snapped. They can be updated + by the drawing mechanism if snapping is requried. + + If key is not NULL any keys read will be passed to the key reoutine (after + being passed to HandleMoveKey()). + + Finally if infobox is not NULL this function is used to draw the describing + infobox, rather than PickPoint()s default one. The prompt (p) PickPoint() + was called with will be passed to the infobox routine. +*/ +int PickPoint(char *p,int *x,int *y,void (*draw)(int *x,int *y), + void (*key)(GFXKey k), + void (*infobox)(char *p)); + +void SetEditMode(int mode); +void HandleMoveKey(GFXKey k, int check_mouse); +void HandleKey(GFXKey k); +void HandleMouse(GFXMouse m); + +void MergeWad(void); + +void Rotate(int cx,int cy,int *x,int *y, double ang); +void Scale(int cx,int cy,int *x,int *y, double sc); + +int PositionOnObject_VERTEX(int x,int y,void *data); +void SelectBox_VERTEX(int x1,int y1,int x2,int y2); +void SelectByType_VERTEX(void); +void DrawObject_VERTEX(void *data, int selmode); +void DrawObjectInfo_VERTEX(void); +void DrawObjectHeader_VERTEX(void); +void MoveObject_VERTEX(void); +void RotateObject_VERTEX(double angle); +void ScaleObject_VERTEX(double scale); +void SetTagObject_VERTEX(int tag); +void LocateObject_VERTEX(void *obj); +void ObjectInsert_VERTEX(void); +void ObjectDelete_VERTEX(void); +void ObjectMenu_VERTEX(void); +void ObjectKey_VERTEX(GFXKey k); +int ObjectHasTag_VERTEX(void *obj, int tag); + +List TrackLinedef(int line_no); +void CheckMergeLinedef(EditVert *v); +int CreateNewLinedef(int from, int to, + int flags, int type, int tag, int two_sided, + int sr_ox, int sr_oy, int sr_sector, + DirName sr_upper, DirName sr_middle, DirName sr_lower, + int sl_ox, int sl_oy, int sl_sector, + DirName sl_upper, DirName sl_middle, DirName sl_lower); + +int PositionOnObject_LINEDEF(int x,int y,void *data); +void SelectBox_LINEDEF(int x1,int y1,int x2,int y2); +void SelectByType_LINEDEF(void); +void DrawObject_LINEDEF(void *data, int selmode); +void DrawObjectInfo_LINEDEF(void); +void DrawObjectHeader_LINEDEF(void); +void MoveObject_LINEDEF(void); +void RotateObject_LINEDEF(double angle); +void ScaleObject_LINEDEF(double scale); +void SetTagObject_LINEDEF(int tag); +void LocateObject_LINEDEF(void *obj); +void ObjectInsert_LINEDEF(void); +void ObjectDelete_LINEDEF(void); +void ObjectMenu_LINEDEF(void); +void ObjectKey_LINEDEF(GFXKey k); +int ObjectHasTag_LINEDEF(void *obj, int tag); + +int PositionOnObject_THING(int x,int y,void *data); +void SelectBox_THING(int x1,int y1,int x2,int y2); +void SelectByType_THING(void); +void DrawObject_THING(void *data, int selmode); +void DrawObjectInfo_THING(void); +void DrawObjectHeader_THING(void); +void MoveObject_THING(void); +void RotateObject_THING(double angle); +void ScaleObject_THING(double scale); +void SetTagObject_THING(int tag); +void LocateObject_THING(void *obj); +void ObjectInsert_THING(void); +void ObjectDelete_THING(void); +void ObjectMenu_THING(void); +void ObjectKey_THING(GFXKey k); +int ObjectHasTag_THING(void *obj, int tag); + +/* Returns -1 if point not in a sector +*/ +int SectorHoldingPoint(int x,int y); + +/* Creates a sector for the list of vertex numbers, which is assumed to go + clockwise. Return is TRUE if operation completed, FALSE if cancelled. +*/ +int CreateSector(List v); +int CreateUnboundSector(int special,int floor,int ceiling,int light,int tag, + DirName floor_t,DirName ceiling_t); + +void SectorCalcContaining(int no,EditSect *s); +void SectorCalcContainingAll(void); + +int PositionOnObject_SECTOR(int x,int y,void *data); +void SelectBox_SECTOR(int x1,int y1,int x2,int y2); +void SelectByType_SECTOR(void); +void DrawObject_SECTOR(void *data, int selmode); +void DrawObjectInfo_SECTOR(void); +void DrawObjectHeader_SECTOR(void); +void MoveObject_SECTOR(void); +void RotateObject_SECTOR(double angle); +void ScaleObject_SECTOR(double scale); +void SetTagObject_SECTOR(int tag); +void LocateObject_SECTOR(void *obj); +void ObjectInsert_SECTOR(void); +void ObjectDelete_SECTOR(void); +void ObjectMenu_SECTOR(void); +void ObjectKey_SECTOR(GFXKey k); +int ObjectHasTag_SECTOR(void *obj, int tag); + +void GenerateMultiMap(void); +int PositionOnObject_MULTI(int x,int y,void *data); +void SelectBox_MULTI(int x1,int y1,int x2,int y2); +void SelectByType_MULTI(void); +void DrawObject_MULTI(void *data, int selmode); +void DrawObjectInfo_MULTI(void); +void DrawObjectHeader_MULTI(void); +void MoveObject_MULTI(void); +void RotateObject_MULTI(double angle); +void ScaleObject_MULTI(double scale); +void SetTagObject_MULTI(int tag); +void LocateObject_MULTI(void *obj); +void ObjectInsert_MULTI(void); +void ObjectDelete_MULTI(void); +void ObjectMenu_MULTI(void); +void ObjectKey_MULTI(GFXKey k); +int ObjectHasTag_MULTI(void *obj, int tag); +void SetSelect_MULTI(int i, int mode); + +#endif + +/* END OF FILE */ diff --git a/editvert.c b/editvert.c new file mode 100644 index 0000000..69a4955 --- /dev/null +++ b/editvert.c @@ -0,0 +1,809 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor VERTEX definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "editvar.h" + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static void VertexSelectionCentre(int *x,int *y) +{ + int *f; + EditVert *v; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + min_x=MIN(v->v.x,min_x); + min_y=MIN(v->v.y,min_y); + max_x=MAX(v->v.x,max_x); + max_y=MAX(v->v.y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +static void MergeVertex(int new,int old) +{ + Object *o; + EditVert *v; + EditLine *l; + int f; + + o=MapElem(vertex,old); + v=o->data; + ListClear(v->l); + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; + + v=GETVERT(new); + + for(f=0;fl.from==old) + { + l->l.from=new; + l->v[0]=v; + IntListUniqAdd(v->l,f); + } + + if (l->l.to==old) + { + l->l.to=new; + l->v[1]=v; + IntListUniqAdd(v->l,f); + } + } + + if (merge_linedef!=MERGE_NEVER) + { + v=GETVERT(new); + CheckMergeLinedef(v); + } +} + +/* ---------------------------------------- GENERIC VERTEX FUNCS +*/ +int PositionOnObject_VERTEX(int x,int y,void *data) +{ + EditVert *v; + + TRACE; + + v=data; + return (RADBOUND(x,y,v->v.x,v->v.y,vertex_rad)); +} + + +void SelectBox_VERTEX(int x1,int y1,int x2,int y2) +{ + Object *o; + EditVert *v; + int f; + + TRACE; + + for(f=0;fdata)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(v->v.x,v->v.y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_VERTEX(void) +{ + return; +} + + +void DrawObject_VERTEX(void *data, int selmode) +{ + EditVert *v; + int col; + + TRACE; + v=data; + + MapPlot(v->v.x,v->v.y,VERTCOL); + + switch(selmode) + { + case SELECT_OVER: + col=OVERCOL; + break; + case SELECT_SELECTED: + col=SELCOL; + break; + default: + col=VERTBOXCOL; + break; + } + + MapRect(v->v.x-vertex_rad,v->v.y+vertex_rad,vertex_rad*2,vertex_rad*2,col); +} + + +void DrawObjectInfo_VERTEX(void) +{ + EditVert *v; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((v=GETVERT(current)))) + GuiDrawInfoBox("VERTEX",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Vertex No : %10d|" + "X : %10d|" + "Y : %10d", + current, + v->v.x,v->v.y); + else + GuiDrawInfoBox("VERTEX",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Vertex No : - |" + "X : - |" + "Y : - "); +} + + +void DrawObjectHeader_VERTEX(void) +{ +} + + +void MoveObject_VERTEX(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditVert *v,*v2; + List orig; + int *f; + int r; + Point p; + int cancel; + int done_merge; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + done_merge=FALSE; + orig=ListNew(sizeof(Point)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + p.x=v->v.x; + p.y=v->v.y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move VERTEX",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + memcpy(&p,IteratorData(i2),sizeof(Point)); + v=GETVERT(*f); + v->v.x=p.x; + v->v.y=p.y; + + i=IteratorNext(i); + i2=IteratorNext(i2); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + i=ListIterator(selected); + while(i) + { + f=IteratorData(i); + + v=GETVERT(*f); + + v->v.x+=dmx; + v->v.y+=dmy; + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + + if (!cancel) + { + int ask; + int ok; + + ask=TRUE; + ok=TRUE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + + for(r=0;(rv.x==v2->v.x)&&(v->v.y==v2->v.y)) + { + if (ask) + { + ok=YesNo("Merge overlapping vertexes?"); + ask=FALSE; + } + + if (ok) + { + MergeVertex(*f,r); + done_merge=TRUE; + } + } + } + + i=IteratorNext(i); + } + + if (done_merge) + SectorCalcContainingAll(); + } + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_VERTEX(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditVert *v; + + TRACE; + + VertexSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + x=v->v.x; + y=v->v.y; + + Rotate(cx,cy,&x,&y,angle); + + v->v.x=x; + v->v.y=y; + + i=IteratorNext(i); + } +} + + +void ScaleObject_VERTEX(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditVert *v; + + TRACE; + + VertexSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + x=v->v.x; + y=v->v.y; + + Scale(cx,cy,&x,&y,scale); + + v->v.x=x; + v->v.y=y; + + i=IteratorNext(i); + } +} + + +void SetTagObject_VERTEX(int tag) +{ + TRACE; +} + + +void LocateObject_VERTEX(void *obj) +{ + EditVert *v; + + TRACE; + + v=obj; + + ox=v->v.x-scale*SCRW/2; + oy=v->v.y+scale*SCRH/2; +} + + +void ObjectInsert_VERTEX(void) +{ + Object o; + EditVert *v; + int f; + + TRACE; + + v=Grab(sizeof(EditVert)); + v->v.x=SnapX(XToMap(ms.x)); + v->v.y=SnapY(YToMap(ms.y)); + v->l=ListNew(sizeof(int)); + + f=MapSize(vertex); + + switch(insert_select) + { + case HOVER_NONE: + o.select=SELECT_NONE; + break; + case HOVER_ADD: + case HOVER_SINGLE: + o.select=SELECT_SELECTED; + break; + } + + o.data=v; + DrawObject_VERTEX(v,o.select); + MapAdd(vertex,f,&o); + + switch(insert_select) + { + case HOVER_NONE: + break; + case HOVER_ADD: + ListAppend(selected,&f); + break; + case HOVER_SINGLE: + ClearSelection(); + ListAppend(selected,&f); + FullRedraw(); + break; + } +} + + +void ObjectDelete_VERTEX(void) +{ + Iterator i; + Object *o; + EditVert *v; + int *f; + int bound; + + TRACE; + + i=ListIterator(selected); + bound=FALSE; + + while(i) + { + f=IteratorData(i); + + o=MapElem(vertex,*f); + v=o->data; + + if (ListSize(v->l)) + bound=TRUE; + else + { + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; + } + + i=IteratorNext(i); + } + + ClearSelection(); + FullRedraw(); + + if (bound) + { + GuiInfoBox("WARNING","1 or more VERTEX found still bound to LINEDEF|" + "These have not been deleted"); + + FullRedraw(); + } +} + + +void ObjectMenu_VERTEX(void) +{ + Iterator i; + int from; + int to; + int first; + int type; + int flag; + int two; + int wr,wl; + int oxr,oxl; + DirName sr_upper,sr_middle,sr_lower; + DirName sl_upper,sl_middle,sl_lower; + EditVert *v1=NULL,*v2=NULL; + int cancel=FALSE; + int redraw=FALSE; + int in_sector; + int loop; + int nl; + + TRACE; + + GFX_redraw(); + + switch(GUI_menu("Vertex",ms.x,ms.y,vertex_popup,GUI_CANCEL)) + { + case TM_CHAIN: + cancel=TRUE; + + if (ListSize(selected)<2) + { + GuiInfoBox("ERROR","Need 2 or more vertices|to chain a line"); + redraw=TRUE; + } + else + { + if (GetLinedefValues(TRUE,0,0,0,0, + &type,&flag,&two, + sr_upper,sr_middle,sr_lower, + sl_upper,sl_middle,sl_lower)) + { + if (ListSize(selected)>2) + loop=YesNo("Join last vertex to first one?"); + else + loop=FALSE; + + oxr=0; + oxl=0; + + wr=CalcTextureWidth(sr_upper,sr_middle,sr_lower); + + if (two) + wl=CalcTextureWidth(sl_upper,sl_middle,sl_lower); + else + wl=0; + + i=ListIterator(selected); + + memcpy(&to,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + first=to; + + while(i) + { + from=to; + memcpy(&to,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + + v1=GETVERT(from); + v2=GETVERT(to); + + in_sector=SectorHoldingPoint(v1->v.x,v1->v.y); + + nl=CreateNewLinedef(from,to, + flag,type,0,two, + oxr,0,in_sector, + sr_upper,sr_middle,sr_lower, + oxl,0,in_sector, + sl_upper,sl_middle,sl_lower); + + IntListUniqAdd(v1->l,nl); + IntListUniqAdd(v2->l,nl); + + if (wr) + oxr=(oxr+Len(v1->v.x,v1->v.y,v2->v.x,v2->v.y))%wr; + + if ((two)&&(wl)) + oxl=(oxl+Len(v1->v.x,v1->v.y,v2->v.x,v2->v.y))%wl; + } + + in_sector=SectorHoldingPoint(v2->v.x,v2->v.y); + + if (loop) + { + v1=GETVERT(to); + v2=GETVERT(first); + + nl=CreateNewLinedef(to,first, + flag,type,0,two, + oxr,0,in_sector, + sr_upper,sr_middle,sr_lower, + oxl,0,in_sector, + sl_upper,sl_middle,sl_lower); + + IntListUniqAdd(v1->l,nl); + IntListUniqAdd(v2->l,nl); + } + + cancel=FALSE; + redraw=TRUE; + + SectorCalcContainingAll(); + } + } + + break; + + case TM_CHAIN_SECTOR: + if (CreateSector(selected)) + redraw=TRUE; + else + cancel=TRUE; + break; + + case TM_MERGE: + if (ListSize(selected)<2) + { + GuiInfoBox("ERROR","Need 2 or more vertices|to merge them"); + redraw=TRUE; + cancel=TRUE; + } + else + { + redraw=TRUE; + i=ListIterator(selected); + memcpy(&first,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + + while(i) + { + memcpy(&to,IteratorData(i),sizeof(int)); + MergeVertex(first,to); + i=IteratorNext(i); + } + + SectorCalcContainingAll(); + } + break; + + case TM_SNAP: + { + int orig_lock; + int *f; + EditVert *v; + + orig_lock=grid_lock; + grid_lock=TRUE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + v->v.x=SnapX(v->v.x); + v->v.y=SnapX(v->v.y); + + i=IteratorNext(i); + } + + grid_lock=orig_lock; + redraw=TRUE; + + break; + } + + case TM_DELETE: + ObjectDelete_VERTEX(); + break; + + case TM_MOVE: + MoveObject_VERTEX(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } + else if (redraw) + FullRedraw(); +} + + +void ObjectKey_VERTEX(GFXKey k) +{ + int f; + int n; + Object *o; + EditVert *v; + + switch(k.code) + { + case GFX_F12: + ClearSelection(); + n=0; + + for(f=0;fdata) + { + v=o->data; + + if (ListSize(v->l)==0) + { + ListClear(v->l); + Release(o->data); + o->data=NULL; + n++; + } + } + } + + GuiInfoBox("NOTICE","Deleted %d vertices",n); + FullRedraw(); + + break; + + default: + break; + } +} + + +int ObjectHasTag_VERTEX(void *obj, int tag) +{ + return(FALSE); +} + + +/* END OF FILE */ diff --git a/file.h b/file.h new file mode 100644 index 0000000..76d2248 --- /dev/null +++ b/file.h @@ -0,0 +1,58 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + File system interfaces + + $Id$ + + +*/ + +#ifndef _FILE_H + +#define _FILE_H + +/* Return current working directory +*/ +char *Pwd(void); + +/* Change directory +*/ +void Cd(char *path); + +/* Dirname portion of a path +*/ +char *Dirname(char *path); + +/* Basename portion of a path +*/ +char *Basename(char *path); + +/* Returns TRUE if file exists +*/ +int FileExists(char *path); + +/* Returns TRUE if the the two paths point to the same file +*/ +int FilenamesEqual(char *path1, char *path2); + +#endif diff --git a/gfx.h b/gfx.h new file mode 100644 index 0000000..7194a3c --- /dev/null +++ b/gfx.h @@ -0,0 +1,314 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides a skin of graphics and input functions (in case of future + ports). + + Assumes these features: + + - A true, or hicolor, display + - A Fixed font + - Default origin is in the top left of the display, with X positve + along and Y positive down + - A buffered display. The screen contents should not change until + GFX_redraw() is called. If not honoured viDOOM should still work up + to a point, but it's use of the XOR mode may not be apparent to the + user. + + $Id$ + +*/ +#ifndef _GFX_H + +#define _GFX_H + +/* Opaque type to define a bitmap object and the public creator type, along + with the picklist data providers. Note that the bitmap object is assumed + to have a maximum of 256 unique colours. +*/ +typedef void *GFX_IMAGE; + +#define MAX_GFXBM_W 256 +#define MAX_GFXBM_H 256 + +typedef struct + { + int w; /* Width */ + int h; /* Height */ + int pal[256]; /* Palette */ + unsigned char *data; /* Accessed as data+(x)+(y)*(width) */ + } GFX_BITMAP; + +/* Key press structure +*/ +typedef struct + { + int type; /* Event type (for GFX_await_input()) */ + int shift; /* Is shift pressed? */ + int ctrl; /* Is control pressed? */ + int alt; /* Is ALT pressed? */ + char ascii; /* ASCII code for the char. If zero ... */ + int code; /* ... this holds a special code defined below */ + } GFXKey; + + +/* Special non-ASCII keys that can be returned +*/ +#define GFX_ASCII 0 /* Not a special key - just ASCII */ + +#define GFX_F1 1001 +#define GFX_F2 1002 +#define GFX_F3 1003 +#define GFX_F4 1004 +#define GFX_F5 1005 +#define GFX_F6 1006 +#define GFX_F7 1007 +#define GFX_F8 1008 +#define GFX_F9 1009 +#define GFX_F10 1010 +#define GFX_F11 1011 +#define GFX_F12 1012 + +#define GFX_ESC 1021 +#define GFX_INSERT 1022 +#define GFX_HOME 1023 +#define GFX_PGUP 1024 +#define GFX_DELETE 1025 +#define GFX_END 1026 +#define GFX_PGDN 1027 + +#define GFX_UP 1028 +#define GFX_DOWN 1029 +#define GFX_LEFT 1030 +#define GFX_RIGHT 1031 + +#define GFX_ENTER 1032 +#define GFX_BACKSPACE 1033 +#define GFX_TAB 1034 + + +/* Mouse buttons +*/ +#define GFX_BUTLEFT 0x01 +#define GFX_BUTRIGHT 0x02 +#define GFX_BUTMIDDLE 0x04 + + +/* Event structs for GFX_await_input(). +*/ +#define GFX_KEY_EVENT 1 /* Key pressed */ +#define GFX_MOUSE_EVENT 2 /* Mouse button pressed or mouse moved */ + +typedef struct GFXMouse + { + int type; /* Event type (for GFX_await_input()) */ + int shift; /* Is shift pressed? */ + int ctrl; /* Is control pressed? */ + int alt; /* Is ALT pressed? */ + int x; /* Mouse X co-ord */ + int y; /* Mouse X co-ord */ + int b; /* Mouse button mask */ + } GFXMouse; + +typedef union GFXEvent + { + int type; + GFXKey key; + GFXMouse mouse; + } GFXEvent; + + + +/* Assume an intensity of 0-255 for each RGB component. The library assumes + that colours are represented as an RGB triplet in that order. +*/ +#define V_RGB(r,g,b) ((r)<<16|(g)<<8|(b)) + +#define BLACK 0x000000 +#define WHITE 0xffffff +#define RED 0xff0000 +#define GREEN 0x00ff00 +#define BLUE 0x0000ff +#define GREY(l) V_RGB(l,l,l) + +/* Initialise graphics. This is pretty much called the first thing called. + After calling this it must be that the following functions at least are + operational: + + GFX_close() + GFX_open() + GFX_exit() + GFX_create_image() + + The platform GFX driver can assume no drawing primitives are called till + the screen is opended. + +*/ +void GFX_init(void); + + +/* Closedown for clean, non-error exits. See GFX_exit() for error exits +*/ +void GFX_close(void); + + +/* Create a GFX_IMAGE for the passed GFX_BITMAP. Returns NULL on failure. +*/ +GFX_IMAGE GFX_create_image(GFX_BITMAP *bm); + +/* Destory a bitmap +*/ +void GFX_destroy_image(GFX_IMAGE img); + +/* Draw an image +*/ +void GFX_draw_image(GFX_IMAGE i,int x,int y); + + +/* Fill the screen with an image. Not really crucial as it's just used for + the splash screen. If it cannot be honoured properly just drawing the + GFX_IMAGE centred in the screen should be adequate +*/ +void GFX_fill_screen(GFX_IMAGE i); + + +/* Open a screen/window/whatever. Expected to be true colour, or an + approximation of. Should exit cleanly on failure. +*/ +void GFX_open(int width, int height); + + +/* Clear the screen to a colour +*/ +void GFX_clear(int col); + + +/* It is assumed by viDOOM that what has been drawn will NOT appear on screen + till this is called. +*/ +void GFX_redraw(void); + + +/* Draw a line +*/ +void GFX_line(int x1, int y1, int x2, int y2, int col); + + +/* Plot a point +*/ +void GFX_plot(int x, int y, int col); + + +/* Draw a circle (and filled version) +*/ +void GFX_circle(int x, int y, int radius, int col); +void GFX_fcircle(int x, int y, int radius, int col); + + +/* Draw a rectangle (and filled version). Note that zero and negative width + and heights must be allowed. +*/ +void GFX_rect(int x, int y, int w, int h, int col); +void GFX_frect(int x, int y, int w, int h, int col); + + +/* Sets and clears XOR mode (used for rubber bands, etc). +*/ +void GFX_set_XOR_mode(void); +void GFX_clear_XOR_mode(void); + + +/* printf() text at x,y. The baseline is assumed to be the top left corner of + the box enclosing the text and text is assumed to be transparent +*/ +void GFX_print(int x, int y, int col, char *fmt, ...); + + +/* Return the dimension of the (fixed width!) font used for printing +*/ +int GFX_fh(void); +int GFX_fw(void); + + +/* Return the number of mouse buttons. Should be at least 2. +*/ +int GFX_mouse_buttons(void); + + +/* Sample the current state of the mouse. Return is the button mask. If X or + Y is NULL that position is not returned. +*/ +int GFX_mouse(int *x, int *y); + + +/* Wait for a key to be pressed. key can be NULL if you're not interested in + the key. +*/ +void GFX_waitkey(GFXKey *key); + + +/* Check for a key to be pressed. Returns TRUE or FALSE accordingly and sets + the GFXKey struct up. +*/ +int GFX_key(GFXKey *key); + + +/* If this platform is not event driven, this call should wait kill all keys + and mouse buttons have been released. On event driven ones this may clear + any outstanding input events. +*/ +void GFX_bounce(void); + + +/* Await for any sort of input from the keyboard or mouse buttons. This is + included in the platform specific so that event driven environs (eg. X11) + can work naturally, while non-event driven environments (eg. DOS) can have + the busy polling loop here, rather than in the generic code. +*/ +void GFX_await_input(GFXEvent *ev); + + +/* This works like the above call, but returns mouse movement events (as a + GFX_MOUSE_EVENT) as well. +*/ +void GFX_await_input_full(GFXEvent *ev); + + +/* Tidy up the graphics (switch them off, release mem, etc), print the + supplied error message and then exit with the return code. +*/ +void GFX_exit(int code,char *fmt,...); + + +/* This interface _really_ does not have to do anything. It is just on the + development system so that grabs could be made for the docs. + + If you feel the urge though this should save a snap shot of the current + screen in the passed file. +*/ +void GFX_save_screen(char *path); + + +#endif + + +/* END OF FILE */ diff --git a/gfxtest.c b/gfxtest.c new file mode 100644 index 0000000..8d80731 --- /dev/null +++ b/gfxtest.c @@ -0,0 +1,430 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Test program for GFX interface +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include +#include +#include "gfx.h" +#include "editvar.h" +#include "mem.h" + +#define SCRW 640 +#define SCRH 480 + +#define RND(x) (rand()%(x)) +#define RCOL V_RGB(RND(255),RND(255),RND(255)) + +void TestPrint(void) +{ + int f; + + GFX_clear(BLACK); + + GFX_print(0,0,WHITE,"Top left"); + GFX_print(0,SCRH-GFX_fh(),WHITE,"Bottom left"); + GFX_print(SCRW-GFX_fw()*strlen("Top right"),0,WHITE,"Top right"); + GFX_print(SCRW-GFX_fw()*strlen("Bottom right"), + SCRH-GFX_fh(),WHITE,"Bottom right"); + + for(f=1;f<4;f++) + GFX_print(0,100+f*GFX_fh(),WHITE,"Row %d",f); + + GFX_redraw(); + GFX_waitkey(NULL); +} + + +void TestMouse(void) +{ + GFXEvent e; + int q; + int f; + + GFX_clear(BLACK); + + q=FALSE; + + while(!q) + { + GFX_redraw(); + GFX_await_input_full(&e); + + switch(e.type) + { + case GFX_KEY_EVENT: + if (e.key.code==GFX_ESC) + q=TRUE; + + if (e.key.code==GFX_ENTER) + GFX_clear(BLACK); + break; + + case GFX_MOUSE_EVENT: + f=0; + if (e.mouse.b&GFX_BUTLEFT) + f|=0xff0000; + if (e.mouse.b&GFX_BUTMIDDLE) + f|=0xff00; + if (e.mouse.b&GFX_BUTRIGHT) + f|=0xff; + + if (f==0) + f=0x808080; + + GFX_frect(0,0,SCRW,GFX_fh(),BLACK); + GFX_print(0,0,WHITE,"x:%-4d y:%-4d b:%c%c%c", + e.mouse.x,e.mouse.y, + e.mouse.b&GFX_BUTLEFT ? 'L':' ', + e.mouse.b&GFX_BUTMIDDLE ? 'M':' ', + e.mouse.b&GFX_BUTRIGHT ? 'R':' '); + + GFX_plot(e.mouse.x,e.mouse.y,f); + break; + } + } +} + + +void TestRect(void) +{ + int f,w; + int ox,oy; + + ox=20; + oy=100; + + for(w=3;w>-4;w--) + { + GFX_clear(BLACK); + + GFX_print(0,0,WHITE,"Width/height %d",w); + + for(f=0;f<5;f++) + { + GFX_plot(ox+f*20,oy+20,WHITE); + GFX_rect(ox+f*20+10,oy+20,w,w,WHITE); + + GFX_plot(ox+f*20,oy+40,WHITE); + GFX_frect(ox+f*20+10,oy+40,w,w,WHITE); + + GFX_plot(ox+f*20,oy+60,WHITE); + GFX_rect(ox+f*20+10,oy+60,w,w*2,WHITE); + + GFX_plot(ox+f*20,oy+80,WHITE); + GFX_frect(ox+f*20+10,oy+80,w,w*2,WHITE); + + GFX_plot(ox+f*20,oy+100,WHITE); + GFX_rect(ox+f*20+10,oy+100,w*2,w,WHITE); + + GFX_plot(ox+f*20,oy+120,WHITE); + GFX_frect(ox+f*20+10,oy+120,w*2,w,WHITE); + } + + GFX_redraw(); + GFX_waitkey(NULL); + } +} + + +void TestRotate(void) +{ + GFXEvent e; + int q; + int x1,y1,x2,y2; + + GFX_clear(BLACK); + + q=FALSE; + x1=200; + y1=0; + x2=0; + y2=-190; + + while(!q) + { + GFX_redraw(); + GFX_await_input_full(&e); + + switch(e.type) + { + case GFX_KEY_EVENT: + if (e.key.code==GFX_ESC) + q=TRUE; + + if (e.key.code==GFX_ENTER) + GFX_clear(BLACK); + break; + + case GFX_MOUSE_EVENT: + Rotate(0,0,&x1,&y1,10.0); + Rotate(0,0,&x2,&y2,-10.0); + + GFX_plot(e.mouse.x+x1,e.mouse.y+y1,RCOL); + GFX_plot(e.mouse.x+x2,e.mouse.y+y2,RCOL); + break; + } + } +} + + +void TestScale(void) +{ + GFXEvent e; + int q; + int f; + int x,y; + + GFX_clear(BLACK); + + q=FALSE; + x=10; + y=10; + f=0; + + while(!q) + { + GFX_redraw(); + GFX_await_input_full(&e); + + switch(e.type) + { + case GFX_KEY_EVENT: + if (e.key.code==GFX_ESC) + q=TRUE; + + if (e.key.code==GFX_ENTER) + GFX_clear(BLACK); + break; + + case GFX_MOUSE_EVENT: + if (((f++)%20)>10) + Scale(0,0,&x,&y,0.9); + else + Scale(0,0,&x,&y,1.1); + + GFX_plot(e.mouse.x+x,e.mouse.y+y,RCOL); + break; + } + } +} + + +void TestDim(void) +{ + GFX_clear(BLACK); + + GFX_line(0,0,SCRW-1,0,WHITE); + GFX_line(0,SCRH-1,SCRW-1,SCRH-1,WHITE); + + GFX_line(0,0,0,SCRH-1,WHITE); + GFX_line(SCRW-1,0,SCRW-1,SCRH-1,WHITE); + + GFX_line(0,0,SCRW-1,SCRH-1,WHITE); + GFX_line(SCRW-1,0,0,SCRH-1,WHITE); + + GFX_print(20,SCRH/2,WHITE,"GFX_line()"); + + GFX_redraw(); + GFX_waitkey(NULL); + + GFX_clear(BLACK); + + GFX_rect(0,0,SCRW,SCRH,WHITE); + GFX_print(20,SCRH/2,WHITE,"GFX_rect()"); + + GFX_redraw(); + GFX_waitkey(NULL); + + GFX_clear(BLACK); + + GFX_frect(0,0,SCRW,SCRH,RED); + GFX_print(20,SCRH/2,WHITE,"GFX_frect()"); + + GFX_redraw(); + GFX_waitkey(NULL); +} + + +void TestCol(void) +{ + GFX_clear(BLACK); + + GFX_frect(0,0,SCRW,10,WHITE); + GFX_print(0,10,WHITE,"WHITE"); + + GFX_frect(0,20,SCRW,10,RED); + GFX_print(0,30,RED,"RED"); + + GFX_frect(0,40,SCRW,10,BLUE); + GFX_print(0,50,BLUE,"BLUE"); + + GFX_frect(0,60,SCRW,10,GREEN); + GFX_print(0,70,GREEN,"GREEN"); + + GFX_frect(0,80,SCRW,10,GREY(128)); + GFX_print(0,90,GREY(128),"GREY(128)"); + + GFX_redraw(); + GFX_waitkey(NULL); +} + +static void TestDraw(void) +{ + int f; + + GFX_clear(BLACK); + + for(f=0;f<100;f++) + GFX_plot(f,10,WHITE); + GFX_print(0,22,WHITE,"GFX_plot()"); + + GFX_line(0,40,99,40,WHITE); + GFX_print(0,42,WHITE,"GFX_line()"); + + GFX_rect(0,60,100,10,WHITE); + GFX_print(0,70,WHITE,"GFX_rect()"); + + GFX_frect(0,80,100,10,WHITE); + GFX_print(0,90,WHITE,"GFX_frect()"); + + GFX_circle(50,150,50,WHITE); + GFX_print(50,150,WHITE,"GFX_circle()"); + + GFX_fcircle(50,250,50,GREEN); + GFX_print(50,250,WHITE,"GFX_fircle()"); + + for(f=101;f>=99;f--) + { + GFX_line(f,0,f,100,RED); + GFX_redraw(); + GFX_waitkey(NULL); + } +} + + +static void TestBm(void) +{ + static unsigned char data[64]= + { + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,1,2,2,0,0,1,0, + 0,1,2,2,0,0,1,1, + 0,1,0,0,2,2,1,1, + 0,1,0,0,2,2,1,0, + 0,1,1,1,1,1,1,0, + 0,0,0,1,1,0,0,0, + }; + GFX_IMAGE i; + GFX_BITMAP bm; + int f; + + bm.w=8; + bm.h=8; + bm.pal[0]=BLACK; + bm.pal[1]=RED; + bm.pal[2]=WHITE; + bm.data=data; + + i=GFX_create_image(&bm); + GFX_clear(GREEN); + + for(f=0;f<100;f++) + { + GFX_draw_image(i,f,f); + GFX_redraw(); + } + + GFX_waitkey(NULL); + GFX_fill_screen(i); + GFX_redraw(); + GFX_waitkey(NULL); + + GFX_destroy_image(i); +} + + +int viDOOM(int argc,char *argv[]) +{ + static struct + { + char *t; + char k; + void (*func)(void); + } test[]= { + {"Test printing",'P',TestPrint}, + {"Test mouse",'M',TestMouse}, + {"Test rectangles",'B',TestRect}, + {"Test screen dimensions",'D',TestDim}, + {"Test EDIT Rotate",'R',TestRotate}, + {"Test EDIT Scale",'S',TestScale}, + {"Test colours",'C',TestCol}, + {"Test drawing",'G',TestDraw}, + {"Test bitmap",'X',TestBm}, + {NULL,0,NULL} + }; + + GFXKey k; + int quit; + int f; + + GFX_init(); + GFX_open(SCRW,SCRH); + + quit=FALSE; + + while(!quit) + { + GFX_clear(BLACK); + GFX_print(0,0,RED,"Select (ESC quit):"); + + f=0; + while(test[f].t) + { + GFX_print(0,GFX_fh()*(f+2),WHITE,"%c - %s",test[f].k,test[f].t); + f++; + } + + GFX_redraw(); + GFX_waitkey(&k); + + if (k.code==GFX_ESC) + quit=TRUE; + else + { + f=0; + while(test[f].t) + { + if (toupper(k.ascii)==test[f].k) + test[f].func(); + f++; + } + } + } + + return(EXIT_SUCCESS); +} diff --git a/globals.c b/globals.c new file mode 100644 index 0000000..0eb0ad7 --- /dev/null +++ b/globals.c @@ -0,0 +1,983 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Global data + + All the stuff from INI file and from the config files. Note this object + also drives other objects so that the list of things they maintain is + initialised. + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include +#include +#include + +#include "ini.h" +#include "gfx.h" +#include "texture.h" +#include "things.h" +#include "linedefs.h" +#include "sectors.h" + + +/* Constants +*/ +#define MAXLEN 1024 + +#define M_NONE -1 +#define M_THING_TYPES 0 +#define M_SECTOR_TYPES 1 +#define M_LINEDEF_FLAGS 2 +#define M_INCLUDE 3 +#define M_THING_FLAGS 4 +#define M_LINEDEF_TYPES 5 +#define M_LINEDEF_DEFAULTS 6 +#define M_SECTOR_STYLES 7 +#define M_LINEDEF_FLAGS_EXTRA 8 +#define M_EMPTY_TEXTURE_NAME 9 +#define M_THING_CLASSES 10 +#define M_LINEDEF_CLASSES 11 +#define M_SECTOR_CLASSES 12 +#define M_NORMAL_TYPES 13 +#define M_LINEDEF_CHECK_DEFAULT 14 + + +/* INI sections +*/ +#define GAME_INI "Game" +#define EDITOR_INI "Editor" +#define VIDOOM_INI "viDOOM" +#define CLINEDEF_INI "Check LINEDEF" +#define BUILD_INI "Node Builder" + +#define DOOM_INI "Doom" +#define ULT_DOOM_INI "Ultimate Doom" +#define DOOM2_INI "Doom 2" +#define FINAL_TNT_INI "TNT:Evilution" +#define FINAL_PLUT_INI "Plutonia Experiment" +#define ZDOOM_INI "ZDoom" + +/* ------------------------------ Game type +*/ +GameType game=DOOM_2; +LevelStyle level_style=DOOM_2_LEVELS; +int ask_for_game_type=FALSE; +char *game_name="Doom 2 - Hell on Earth"; + + +/* ------------------------------ Paths +*/ +char IWAD_path[PATH_MAX+1]="." DIRSEP "DOOM2.WAD"; +char PWAD_dir[PATH_MAX+1]="." DIRSEP; +char PWAD_preload[MAX_PRELOAD_LEN]=""; +static char config_file[PATH_MAX+1]="doom2.cfg"; + + +/* ------------------------------ Editor configuration +*/ +int disp_width=640; +int disp_height=480; +int grid_onoff=TRUE; +int grid_lock=TRUE; +int grid_size=64; +double gfx_brighten=1.0; +int vertex_rad=5; +Hover hover_select=HOVER_NONE; +int clear_on_move=TRUE; +int clear_on_menu=FALSE; +Hover insert_select=HOVER_NONE; +SectorMoveMode sector_move=MOVE_RIGHT; +int ask_middle_on_2sided=TRUE; +int default_light_level=200; +int default_floor_height=0; +int default_ceiling_height=256; +NewSelect new_2sided_select=NEWSELECT_ASK; +LinedefMerge merge_linedef=MERGE_ASK; +int auto_block_linedefs=TRUE; +int default_scale=10; +DefaultEdit default_edit_mode=EDIT_SECTOR; +int linedef_select=2; +int tag_highlight=TRUE; +int show_full_linedef_info=FALSE; + + +/* ------------------------------ viDOOM configuration +*/ +int sort_textures=TRUE; +int sort_flats=TRUE; +int show_titlepic=TRUE; +int load_textures=TRUE; +int load_flats=TRUE; +int load_sprites=TRUE; +int map_warn=TRUE; +int map_exit_warn=TRUE; +int initial_empty_map=FALSE; +int overwrite_warning=TRUE; + +/* ------------------------------ Linedef flags bit and mask +*/ +int side2_bit=-1; +int side2_mask; +int block_bit=-1; +int block_mask; +int lower_peg_bit=-1; +int lower_peg_mask; +int upper_peg_bit=-1; +int upper_peg_mask; + +/* ------------------------------ Normal values +*/ +int normal_linedef=0; +int normal_sector=0; + +/* ------------------------------ LINEDEF checking +*/ +int check_line_assume_yes=FALSE; +int check_1side_lower=TRUE; +int check_1side_middle=TRUE; +int check_1side_upper=TRUE; +int check_2side_lower=TRUE; +int check_2side_middle=TRUE; +int check_2side_same_sector=TRUE; +int check_2side_upper=TRUE; + +/* ------------------------------ Node Builder config +*/ +int use_build=FALSE; +char build_cmd[PATH_MAX+1]="bsp.exe"; +char build_ignore[PATH_MAX+1]=""; +char build_in[PATH_MAX+1]="%"; +char build_out[PATH_MAX+1]="%"; +int build_in_before_out=TRUE; +int build_always_view=TRUE; + + + +/* ------------------------------ Texture names +*/ +char empty_texture[256]="-"; +char linedef_check_default[256]="-"; + + +/* ------------------------------ INI tables to data +*/ + +#define INI_FOR_GAME(g) { \ + INI_STR, g, "iwad", \ + IWAD_path, NULL \ + }, \ + { \ + INI_STR, g, "pwad_dir", \ + PWAD_dir, NULL \ + }, \ + { \ + INI_TOK, g, "level_style", \ + &level_style, level_style_tok \ + }, \ + { \ + INI_STR, g, "preload", \ + PWAD_preload, NULL \ + }, \ + { \ + INI_STR, g, "vidoom_config", \ + config_file, NULL \ + } + + +static TokenTable game_type_tok[]= + { + {"Doom",DOOM}, + {"Ultimate Doom",ULTIMATE_DOOM}, + {"Doom 2",DOOM_2}, + {"TNT:Evilution",FINAL_TNT}, + {"Plutonia Experiment",FINAL_PLUTONIA}, + {"ZDoom",ZDOOM}, + {NULL,0} + }; + +static TokenTable level_style_tok[]= + { + {"Doom",DOOM_LEVELS}, + {"Ultimate Doom",ULTIMATE_DOOM_LEVELS}, + {"Doom 2",DOOM_2_LEVELS}, + {NULL,0} + }; + +static TokenTable hover_type_tok[]= + { + {"none",HOVER_NONE}, + {"add",HOVER_ADD}, + {"single",HOVER_SINGLE}, + {NULL,0} + }; + +static TokenTable smove_type_tok[]= + { + {"all",MOVE_ALL}, + {"left",MOVE_LEFT}, + {"right",MOVE_RIGHT}, + {NULL,0} + }; + +static TokenTable new_select_tok[]= + { + {"never",NEWSELECT_NEVER}, + {"ask",NEWSELECT_ASK}, + {"select",NEWSELECT_SELECT}, + {NULL,0} + }; + +static TokenTable merge_mode_tok[]= + { + {"never",MERGE_NEVER}, + {"ask",MERGE_ASK}, + {"always",MERGE_ALWAYS}, + {NULL,0} + }; + +static TokenTable edit_mode_tok[]= + { + {"sector",EDIT_SECTOR}, + {"vertex",EDIT_VERTEX}, + {"linedef",EDIT_LINEDEF}, + {"thing",EDIT_THING}, + {"multi",EDIT_MULTI}, + {NULL,0} + }; + + +static INI_Table part1_ini[]= + { + /* Game type + */ + { + INI_TOK, GAME_INI, "game", + &game, game_type_tok + }, + { + INI_TOK, GAME_INI, "ask", + &ask_for_game_type, ini_yesno + }, + { + INI_INT, EDITOR_INI, "width", + &disp_width, NULL + }, + { + INI_INT, EDITOR_INI, "height", + &disp_height, NULL + }, + }; + +static INI_Table part2_ini[]= + { + /* Editor + */ + { + INI_TOK, EDITOR_INI, "grid", + &grid_onoff, ini_yesno + }, + { + INI_TOK, EDITOR_INI, "grid_lock", + &grid_lock, ini_yesno + }, + { + INI_INT, EDITOR_INI, "grid_size", + &grid_size, NULL + }, + { + INI_DOUBLE, EDITOR_INI, "bright", + &gfx_brighten, NULL + }, + { + INI_INT, EDITOR_INI, "vertex_radius", + &vertex_rad, NULL + }, + { + INI_TOK, EDITOR_INI, "hover_select", + &hover_select, hover_type_tok + }, + { + INI_TOK, EDITOR_INI, "clear_on_move", + &clear_on_move, ini_yesno + }, + { + INI_TOK, EDITOR_INI, "clear_on_menu", + &clear_on_menu, ini_yesno + }, + { + INI_TOK, EDITOR_INI, "insert_select", + &insert_select, hover_type_tok + }, + { + INI_TOK, EDITOR_INI, "sector_move", + §or_move, smove_type_tok + }, + { + INI_TOK, EDITOR_INI, "ask_middle_on_2sided", + &ask_middle_on_2sided, ini_yesno + }, + { + INI_INT, EDITOR_INI, "default_light_level", + &default_light_level, NULL + }, + { + INI_INT, EDITOR_INI, "default_floor_height", + &default_floor_height, NULL + }, + { + INI_INT,EDITOR_INI,"default_ceiling_height", + &default_ceiling_height, NULL + }, + { + INI_TOK, EDITOR_INI, "new_2sided_select", + &new_2sided_select, new_select_tok + }, + { + INI_TOK, EDITOR_INI, "merge_linedef", + &merge_linedef, merge_mode_tok + }, + { + INI_TOK, EDITOR_INI, "auto_block_linedefs", + &auto_block_linedefs, ini_yesno + }, + { + INI_INT, EDITOR_INI, "default_scale", + &default_scale, NULL + }, + { + INI_TOK, EDITOR_INI, "default_edit_mode", + &default_edit_mode, edit_mode_tok + }, + { + INI_INT, EDITOR_INI, "linedef_select", + &linedef_select, NULL + }, + { + INI_TOK, EDITOR_INI,"tag_highlight", + &tag_highlight, ini_yesno + }, + { + INI_TOK,EDITOR_INI,"show_full_linedef_info", + &show_full_linedef_info, ini_yesno + }, + + /* viDOOM + */ + { + INI_TOK, VIDOOM_INI, "sort_texture_names", + &sort_textures, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "sort_flat_names", + &sort_flats, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "show_titlepic", + &show_titlepic, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "load_textures", + &load_textures, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "load_flats", + &load_flats, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "load_sprites", + &load_sprites, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "map_clear_warning", + &map_warn, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "map_exit_warning", + &map_exit_warn, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "initial_empty_map", + &initial_empty_map, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "overwrite_warning", + &overwrite_warning, ini_yesno + }, + + /* Check LINEDEF + */ + { + INI_TOK, CLINEDEF_INI, "assume_yes", + &check_line_assume_yes, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_1side_lower", + &check_1side_lower, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_1side_middle", + &check_1side_middle, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_1side_upper", + &check_1side_upper, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_2side_lower", + &check_2side_lower, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_2side_middle", + &check_2side_middle, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, + "check_2side_same_sector", + &check_2side_same_sector, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_2side_upper", + &check_2side_upper, ini_yesno + }, + + /* Node builder + */ + { + INI_TOK, BUILD_INI, "use", + &use_build, ini_yesno + }, + { + INI_STR, BUILD_INI, "command", + build_cmd, NULL + }, + { + INI_STR, BUILD_INI, "ignore", + build_ignore, NULL + }, + { + INI_STR, BUILD_INI, "infile", + build_in, NULL + }, + { + INI_STR, BUILD_INI, "outfile", + build_out, NULL + }, + { + INI_TOK, BUILD_INI, "in_before_out", + &build_in_before_out, ini_yesno + }, + { + INI_TOK, BUILD_INI, "always_view_output", + &build_always_view, ini_yesno + }, + }; + +static INI_Table doom_ini[]={INI_FOR_GAME(DOOM_INI)}; +static INI_Table ult_doom_ini[]={INI_FOR_GAME(ULT_DOOM_INI)}; +static INI_Table doom_2_ini[]={INI_FOR_GAME(DOOM2_INI)}; +static INI_Table tnt_ini[]={INI_FOR_GAME(FINAL_TNT_INI)}; +static INI_Table plut_ini[]={INI_FOR_GAME(FINAL_PLUT_INI)}; +static INI_Table zdoom_ini[]={INI_FOR_GAME(ZDOOM_INI)}; + + + +/* ------------------------------ TYPES +*/ +typedef struct + { + char *str; + int val; + } StrList; + + +/* ------------------------------ PRIVATE FUNCTIONS +*/ + +static void CheckVals(void) +{ + FILE *fp; + + grid_size=MAX(grid_size,2); + default_light_level=default_light_level%256; + linedef_select=MAX(linedef_select,1); + + /* Check config file exists + */ + if (!(fp=fopen(config_file,"r"))) + GFX_exit(EXIT_FAILURE,"Couldn't open config file %s\n",config_file); + + fclose(fp); +} + + +static int StrToInt(StrList s[],char *val,int def) +{ + int f; + int m; + + f=0; + m=def; + + while((s[f].str)&&(m==def)) + { + if (STREQ(s[f].str,val)) + m=s[f].val; + f++; + } + + return(m); +} + + +static char *GetLine(FILE *fp) +{ + static char s[MAXLEN+1]; + int l,f; + + fgets(s,MAXLEN,fp); + + if (feof(fp)) + return(FALSE); + + l=strlen(s)-1; + + if ((l>=0)&&(s[l]=='\n')) + s[l]=0; + + l=strlen(s)-1; + + if ((l>=0)&&(s[l]=='\r')) + s[l]=0; + + l=strlen(s); + for(f=0;f=0)&&(f<=15)&&(p[2])) + LinedefFlag(f,p[1],*p[2]); + else + err="LINEDEF_FLAGS"; + + break; + } + + case M_INCLUDE: + { + char s[PATH_MAX]; + + strcpy(s,line); + DoLoadConfig(s); + break; + } + + case M_THING_FLAGS: + { + char *p[3]; + int f; + + p[0]=strtok(line,"|"); + + if (p[0]) + p[1]=strtok(NULL,"|"); + + if (p[1]) + p[2]=strtok(NULL,"|"); + + f=ATOI(p[0]); + + if ((f>=0)&&(f<=15)&&(p[2])) + ThingFlag(f,p[1],p[2]); + else + err="THING_FLAGS"; + + break; + } + + case M_LINEDEF_DEFAULTS: + { + int flags; + char *p[2]; + + if (side2_bit==-1) + GFX_exit + (EXIT_FAILURE, + "LINEDEF_DEFAULTS appeared before " + "LINEDEF_FLAGS_EXTRA\n"); + + p[0]=strtok(line,"|"); + + if (p[0]) + p[1]=strtok(NULL,"|"); + + if (p[1]) + { + flags=ATOI(p[1]); + AddLinedefType(p[0],flags,flags&side2_mask); + } + else + err="LINEDEF_DEFAULTS"; + + break; + } + + case M_SECTOR_STYLES: + { + char *p[7]; + int f; + + p[0]=strtok(line,"|"); + + for(f=1;(f<7)&&(p[f-1]);f++) + p[f]=strtok(NULL,"|"); + + if (p[6]) + AddSectorStyle(p[1],ATOI(p[0]),p[2],p[3], + p[4],p[5],p[6]); + else + err="SECTOR_STYLES"; + + break; + } + + case M_LINEDEF_FLAGS_EXTRA: + { + char *p[4]; + int f; + + p[0]=strtok(line,"|"); + + for(f=1;(f<4)&&(p[f-1]);f++) + p[f]=strtok(NULL,"|"); + + if (p[3]) + { + side2_bit=ATOI(p[0]); + side2_mask=1< +#include +#include + +#include "gui.h" +#include "platgui.h" +#include "mem.h" +#include "ini.h" + +/* ---------------------------------------- VARS +*/ +#define GUI_INI "GUI" + +#define GUI_BORDER (fh/2) +#define GUI_BORDERFULL (GUI_BORDER*2) + +#define GUI_TITLEH (fh*2) +#define GUI_TITLEOFF (fh/2) +#define GUI_FOOTERH (fh*2) +#define GUI_FOOTEROFF (fh/2) + +#define GUI_BEVEL 2 + +#define MAXLINES 512 +#define MAXTEXT 4096 + +#define ANY_CLOSE "Press any key/mouse button to close" +#define ESC_CLOSE "Press ESC key to close" + +#define VIEW_LEN 70 + +int GUI_HI=GREY(210); +int GUI_MID=GREY(180); +int GUI_LO=GREY(140); +int GUI_TEXT=WHITE; +int GUI_TEXTSHADOW=BLACK; +int GUI_TEXTBOLD=BLACK; + +static INI_Table gui_ini[]= + { + {INI_INT,GUI_INI,"high",&GUI_HI,NULL}, + {INI_INT,GUI_INI,"mid",&GUI_MID,NULL}, + {INI_INT,GUI_INI,"low",&GUI_LO,NULL}, + {INI_INT,GUI_INI,"text",&GUI_TEXT,NULL}, + {INI_INT,GUI_INI,"shadow",&GUI_TEXTSHADOW,NULL}, + {INI_INT,GUI_INI,"bold",&GUI_TEXTBOLD,NULL} + }; + +static int SCRW; +static int SCRH; +static int fw; +static int fh; + +static char *doom_levels[]= + {"E1M1","E1M2","E1M3","E1M4","E1M5", + "E1M6","E1M7","E1M8","E1M9", + "E2M1","E2M2","E2M3","E2M4","E2M5", + "E2M6","E2M7","E2M8","E2M9", + "E3M1","E3M2","E3M3","E3M4","E3M5", + "E3M6","E3M7","E3M8","E3M9",NULL}; + +static char *ult_doom_levels[]= + {"E1M1","E1M2","E1M3","E1M4","E1M5", + "E1M6","E1M7","E1M8","E1M9", + "E2M1","E2M2","E2M3","E2M4","E2M5", + "E2M6","E2M7","E2M8","E2M9", + "E3M1","E3M2","E3M3","E3M4","E3M5", + "E3M6","E3M7","E3M8","E3M9", + "E4M1","E4M2","E4M3","E4M4","E4M5", + "E4M6","E4M7","E4M8","E4M9",NULL}; + +static char *doom2_levels[]= + {"MAP01","MAP02","MAP03","MAP04","MAP05", + "MAP06","MAP07","MAP08","MAP09","MAP10", + "MAP11","MAP12","MAP13","MAP14","MAP15", + "MAP16","MAP17","MAP18","MAP19","MAP20", + "MAP21","MAP22","MAP23","MAP24","MAP25", + "MAP26","MAP27","MAP28","MAP29","MAP30", + "MAP31","MAP32",NULL}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ + +static void CalcBounding(char *text,int *num,char *t[],int min_len, + int *x,int *y,int *w,int *h) +{ + int no; + int f; + char *p; + + no=0; + p=strtok(text,"|"); + + while(p) + { + t[no++]=p; + p=strtok(NULL,"|"); + } + + t[no]=NULL; + + *h=fh*no+GUI_BORDERFULL; + + for(f=0;fmin_len) + min_len=strlen(t[f]); + + *num=no; + *w=fw*min_len+GUI_BORDERFULL; + *x=SCRW/2-*w/2; + *y=SCRH/2-*h/2; +} + + +static void DrawBox(int x,int y,int w,int h,int bevel) +{ + int f; + + GFX_frect(x,y,w,h,GUI_MID); + + for(f=0;f"); + line[f]=NULL; + + GUI_picklist(title,line); + + for(f=0;f +#include +#include +#include "ini.h" +#include "mem.h" +#include "file.h" +#include "vstring.h" + +#define MAXLEN (PATH_MAX*2) +#define ROOTVAR "%WADDED%" + +typedef struct Token + { + char *key; + char *valkey; + char *val; + struct Token *next; + struct Token *prev; + } Token; + +static Token *ini=NULL; + +static char ini_dir[PATH_MAX]; +static char ini_file[PATH_MAX]; + +/* Token tables to export +*/ +TokenTable ini_yesno[]={{"yes",TRUE}, + {"no",FALSE}, + {"true",TRUE}, + {"false",FALSE}, + {"y",TRUE}, + {"n",FALSE}, + {"1",TRUE}, + {"0",FALSE}, + {NULL,0}}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static int cmpstr(char *a,char *b) +{ + if ((a)&&(b)) + return(StrCaseCmp(a,b)); + else if ((!a)&&(!b)) + return(0); + else if (!a) + return(-1); + else + return(1); +} + + +static int CompareToken(Token *a, Token *b) +{ + int n; + + if ((n=cmpstr(a->key,b->key))) + return(n); + + return (cmpstr(a->valkey,b->valkey)); +} + +static Token *FindToken(char *key, char *val) +{ + Token *tok; + + tok=ini; + + while(tok) + { + if ((cmpstr(tok->key,key)==0)&& + (cmpstr(tok->valkey,val)==0)) + return(tok); + + tok=tok->next; + } + + return(NULL); +} + + +static char *GetLine(FILE *fp, int len) +{ + static char s[MAXLEN]; + int l,f; + + fgets(s,len-1,fp); + + if (feof(fp)) + return(FALSE); + + l=strlen(s)-1; + + if ((l>=0)&&(s[l]=='\n')) + s[l]=0; + + l=strlen(s)-1; + + if ((l>=0)&&(s[l]=='\r')) + s[l]=0; + + for(f=0;fkey=Strdup(key); + tok->valkey=Strdup(valkey); + tok->val=Strdup(val); + tok->next=NULL; + tok->prev=NULL; + + if (!ini) + { + ini=tok; + return; + } + + ins=ini; + + while(ins) + { + if (CompareToken(ins,tok)>0) + if (ins->prev) + { + ins->prev->next=tok; + tok->prev=ins->prev; + tok->next=ins; + ins->prev=tok; + + return; + } + else + { + tok->next=ins; + ins->prev=tok; + ini=tok; + + return; + } + + if (ins->next) + ins=ins->next; + else + { + ins->next=tok; + tok->prev=ins; + return; + } + } +} + +static int TokenToNum(char *val, TokenTable tokens[]) +{ + int f; + + f=0; + + while(tokens[f].token) + if (cmpstr(tokens[f].token,val)==0) + return(tokens[f].val); + else + f++; + + return(0); +} + +static char *NumToToken(int val, TokenTable tokens[]) +{ + int f; + + f=0; + + while(tokens[f].token) + if (tokens[f].val==val) + return(tokens[f].token); + else + f++; + + return(""); +} + + +static char *Expand(char *p) +{ + static char r[MAXLEN]; + + if (strncmp(p,ROOTVAR,strlen(ROOTVAR))==0) + { + strcpy(r,ini_dir); + strcat(r,p+strlen(ROOTVAR)); + return(r); + } + else + return(p); +} + + +static char *Unexpand(char *p) +{ + static char r[MAXLEN]; + + if (strncmp(p,ini_dir,strlen(ini_dir))==0) + { + strcpy(r,ROOTVAR); + strcat(r,p+strlen(ini_dir)); + return(r); + } + else + return(p); +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +int INI_ReadInt(char *key, char *val) +{ + Token *tok; + + if ((tok=FindToken(key,val))) + return((int)strtol(tok->val,(char **)NULL,0)); + else + return(0); +} + +char *INI_ReadStr(char *key, char *val) +{ + Token *tok; + + if ((tok=FindToken(key,val))) + return(Expand(tok->val)); + else + return(""); +} + +int INI_ReadToken(char *key, char *val, TokenTable tokens[]) +{ + Token *tok; + + if ((tok=FindToken(key,val))) + return(TokenToNum(tok->val,tokens)); + else + return(0); +} + +double INI_ReadDouble(char *key, char *val) +{ + Token *tok; + char *dum; + + if ((tok=FindToken(key,val))) + return(strtod(tok->val,&dum)); + else + return(0.0); +} + +void INI_SaveInt(char *key, char *valkey, int val) +{ + char s[MAXLEN]; + Token *tok; + + sprintf(s,"%d",val); + + if ((tok=FindToken(key,valkey))) + { + Release(tok->val); + tok->val=Strdup(s); + } + else + { + sprintf(s,"%s=%d",valkey,val); + AddToken(key,s); + } +} + +void INI_SaveStr(char *key, char *valkey, char *val) +{ + char s[MAXLEN]; + Token *tok; + + if ((tok=FindToken(key,valkey))) + { + Release(tok->val); + tok->val=Strdup(Unexpand(val)); + } + else + { + sprintf(s,"%s=%s",valkey,val); + AddToken(key,s); + } +} + +void INI_SaveToken(char *key, char *valkey, int val, + TokenTable tokens[]) +{ + char s[MAXLEN]; + Token *tok; + + if ((tok=FindToken(key,valkey))) + { + Release(tok->val); + tok->val=Strdup(NumToToken(val,tokens)); + } + else + { + sprintf(s,"%s=%s",valkey,NumToToken(val,tokens)); + AddToken(key,s); + } +} + +void INI_SaveDouble(char *key, char *valkey, double val) +{ + char s[MAXLEN]; + Token *tok; + + sprintf(s,"%f",val); + + if ((tok=FindToken(key,valkey))) + { + Release(tok->val); + tok->val=Strdup(s); + } + else + { + sprintf(s,"%s=%f",valkey,val); + AddToken(key,s); + } +} + +void INI_DeleteKey(char *key,char *valkey) +{ + Token *tok; + + if ((tok=FindToken(key,valkey))) + { + if (tok->prev) + tok->prev->next=tok->next; + + if (tok->next) + tok->next->prev=tok->prev; + + if (ini==tok) + ini=tok->next; + + Release(tok->key); + Release(tok->valkey); + Release(tok->val); + Release(tok); + } +} + +void INI_Load(char *name) +{ + FILE *fp; + char *line; + char token[32]; + + strcpy(ini_dir,Pwd()); + strcpy(ini_file,ini_dir); + strcat(ini_file,DIRSEP); + strcat(ini_file,name); + + if ((fp=fopen(ini_file,"r"))) + while((line=GetLine(fp,MAXLEN))) + if (line[0]=='[') + { + line[strlen(line)-1]=0; + strcpy(token,line+1); + } + else + AddToken(token,line); +} + +void INI_Save(void) +{ + FILE *fp; + Token *tok; + char *last_key; + int first=TRUE; + + if ((fp=fopen(ini_file,"w"))) + { + tok=ini; + last_key=NULL; + + while(tok) + { + if (cmpstr(last_key,tok->key)) + { + if (first) + fprintf(fp,"[%s]\n",tok->key); + else + fprintf(fp,"\n[%s]\n",tok->key); + last_key=tok->key; + first=FALSE; + } + + fprintf(fp,"%s=%s\n",tok->valkey,tok->val); + + tok=tok->next; + } + + fclose(fp); + } +} + +void INI_GetTable(INI_Table table[],int no) +{ + int f; + int *i; + char *p; + double *d; + + for(f=0;fclass==class) + no++; + + i=IteratorNext(i); + } + + picklist[class]=Grab(sizeof(PLAT_PICKLIST)*(no+1)); + + i=ListIterator(line_list); + + f=0; + while(i) + { + li=IteratorData(i); + + if (li->class==class) + { + picklist[class][f].text=li->name; + picklist[class][f].client_index=li->id; + f++; + } + + i=IteratorNext(i); + } + picklist[class][f].text=NULL; + + return(picklist[class]); + } +} + + + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void LinedefNewClass(char *class) +{ + LineClass c; + + if (!line_class) + line_class=MapNew(sizeof(LineClass)); + + c.name=Strdup(class); + + MapAdd(line_class,no_classes++,&c); +} + + +void LinedefAdd(char *class,char *name,int id) +{ + LineInfo *li; + int i_class; + int f; + + if (!line_list) + line_list=ListNew(sizeof(LineInfo)); + + i_class=-1; + + for(f=0;fname,class)) + i_class=f; + } + + if (i_class==-1) + i_class=0; + + li=Grab(sizeof(LineInfo)); + + li->class=i_class; + li->name=Strdup(name); + li->id=id; + ListAppend(line_list,li); +} + + +int SelectLinedef(void) +{ + int class; + int f; + int x,y; + + if (!line_menu) + { + line_menu=Grab(sizeof(PLAT_MENU)*(no_classes+1)); + picklist=Grab(sizeof(PLAT_PICKLIST *)*(no_classes+1)); + + for(f=0;fname; + line_menu[f].client_index=f; + } + + for(f=0;fid==id) + { + IteratorClear(i); + return(li->name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +char *LinedefClass(int id) +{ + LineInfo *li; + LineClass *lc; + Iterator i; + + if (no_classes==0) + return("NO CLASSES!"); + + i=ListIterator(line_list); + + while(i) + { + li=IteratorData(i); + + if (li->id==id) + { + IteratorClear(i); + lc=MapElem(line_class,li->class); + return(lc->name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +void LinedefFlag(int bit,char *s,char sh) +{ + line_flags[bit]=Strdup(s); + line_flags_sh[bit]=sh; + + if (bit>line_flags_max) + line_flags_max=bit; +} + + +char **LinedefFlagArray(void) +{ + return(line_flags); +} + + +char *LinedefFlagText(int flags) +{ + static char s[32]; + int b; + char *p; + + s[0]=0; + p=s; + + for(b=line_flags_max;b>=0;b--) + { + if (flags&(1<name; + } + + line_def_plist[MapSize(line_def)]=NULL; + } + + f=GUI_picklist("LINEDEF TYPE",line_def_plist); + + if (f!=-1) + { + l=MapElem(line_def,f); + *flag=l->id; + *two=l->two; + return(TRUE); + } + else + return(FALSE); +} + + +/* END OF FILE */ diff --git a/linedefs.h b/linedefs.h new file mode 100644 index 0000000..9a0b044 --- /dev/null +++ b/linedefs.h @@ -0,0 +1,100 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Handles definition and storage of the supported LINEDEFs + + $Id$ + +*/ + +#ifndef _LINEDEFS_H + +#define _LINEDEFS_H + +#include "wad.h" +#include "gfx.h" +#include "platgui.h" + + +/* This is not going to be an ID, so is used to detect whether LinedefSelect() + was cancelled. +*/ +#define LINEDEF_NULLID -666 + + +/* Add a new class of linedef +*/ +void LinedefNewClass(char *class); + + +/* Add the named type to the supplied class with the ID +*/ +void LinedefAdd(char *class,char *name,int id); + + +/* Selects a type of linedef, returning the ID or LINEDEF_NULLID if cancelled +*/ +int SelectLinedef(void); + + +/* Returns the name of a linedef type +*/ +char *LinedefName(int id); + + +/* Returns the class of a linedef type +*/ +char *LinedefClass(int id); + + +/* Set the meaning of one of the bits in the options field for a linedef +*/ +void LinedefFlag(int bit,char *name,char shorthand); + + +/* Returns a GUI_multi_box() compatible text array for manipulating a LINEDEFs + flags. +*/ +char **LinedefFlagArray(void); + + +/* Return a static string representing the meaning of the passed in flags +*/ +char *LinedefFlagText(int flag); + + +/* Define a default linedef flags values +*/ +void AddLinedefType(char *name,int flags,int two_sided); + + +/* Return a default linedef flag value into flags after showing a picklist to + choose them from, and two is TRUE if the linedef is 2-sided. Returns TRUE + for accepted, FALSE cancelled. +*/ +int ChooseLinedefType(int *flags,int *two); + + +#endif + + +/* END OF FILE */ diff --git a/list.c b/list.c new file mode 100644 index 0000000..ad23342 --- /dev/null +++ b/list.c @@ -0,0 +1,288 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides a double linked list + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include +#include + +#include "list.h" +#include "mem.h" + +struct _Elem + { + char *data; + struct _Elem *next; + struct _Elem *prev; + }; + +struct _List + { + int no; + int size; + struct _Elem *head; + struct _Elem *tail; + }; + +struct _Iterator + { + List l; + struct _Elem *e; + }; + +/* ---------------------------------------- +*/ +List ListNew(int type_size) +{ + List nl; + + nl=Grab(sizeof(struct _List)); + + nl->no=0; + nl->size=type_size; + nl->head=NULL; + nl->tail=NULL; + + return(nl); +} + +List ListClear(List l) +{ + struct _Elem *e,*d; + + if (l) + { + e=l->head; + + while(e) + { + d=e; + e=e->next; + Release(d->data); + Release(d); + } + + Release(l); + } + + return(NULL); +} + +List ListEmpty(List l) +{ + struct _Elem *e,*d; + + if (l) + { + e=l->head; + + while(e) + { + d=e; + e=e->next; + Release(d->data); + Release(d); + } + + l->no=0; + l->head=NULL; + l->tail=NULL; + } + + return(l); +} + +int ListSize(List l) +{ + if (l) + return(l->no); + else + return(0); +} + +Iterator ListIterator(List l) +{ + struct _Iterator *i; + + if (!l->head) + return(NULL); + + i=Grab(sizeof(struct _Iterator)); + i->l=l; + i->e=l->head; + + return(i); +} + +Iterator IteratorClear(Iterator i) +{ + if (i) + Release(i); + + return(NULL); +} + +void *IteratorData(Iterator i) +{ + if (i) + return(i->e->data); + else + return(NULL); +} + +Iterator IteratorNext(Iterator i) +{ + if (i) + if (!(i->e=i->e->next)) + { + Release(i); + i=NULL; + } + + return(i); +} + +Iterator IteratorPrev(Iterator i) +{ + if (i) + if (!(i->e=i->e->prev)) + { + Release(i); + i=NULL; + } + + return(i); +} + +Iterator IteratorUpdate(Iterator i,void *data) +{ + if (i) + { + Release(i->e->data); + i->e->data=Copy(data,i->l->size); + } + return(i); +} + +Iterator IteratorDelete(Iterator i) +{ + struct _Elem *e; + + e=i->e; + i->e=i->e->next; + + i->l->no--; + + if (e==i->l->head) + i->l->head=e->next; + + if (e==i->l->tail) + i->l->tail=e->prev; + + if (e->next) + e->next->prev=e->prev; + + if (e->prev) + e->prev->next=e->next; + + Release(e->data); + Release(e); + + if (!(i->e)) + { + Release(i); + i=NULL; + } + + return(i); +} + +void ListAppend(List l,void *data) +{ + struct _Elem *e; + + e=Grab(sizeof(struct _Elem)); + + e->next=NULL; + e->prev=l->tail; + e->data=Copy(data,l->size); + l->no++; + + if (l->head) + { + l->tail->next=e; + l->tail=e; + } + else + l->head=l->tail=e; +} + +void ListInsert(List l,void *data) +{ + struct _Elem *e; + + e=Grab(sizeof(struct _Elem)); + + e->prev=NULL; + e->next=l->head; + e->data=Copy(data,l->size); + l->no++; + + if (l->head) + { + l->head->prev=e; + l->head=e; + } + else + l->head=l->tail=e; +} + +Iterator ListFindElem(List l,int (*pred)(void *, void *),void *data) +{ + Iterator i; + struct _Elem *e; + + i=NULL; + + e=l->head; + + while((e)&&(!i)) + { + if ((*pred)(e->data,data)) + { + i=ListIterator(l); + i->e=e; + } + + e=e->next; + } + + return(i); +} + + +/* END OF FILE */ diff --git a/list.h b/list.h new file mode 100644 index 0000000..929df83 --- /dev/null +++ b/list.h @@ -0,0 +1,104 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides a double-linked list + + $Id$ + +*/ + +#ifndef _LIST_H + +#define _LIST_H + +/* Opaque types for the list and iterator. NULL is the null list and iterator. +*/ +struct _List; +typedef struct _List *List; + +struct _Iterator; +typedef struct _Iterator *Iterator; + + +/* Create a list +*/ +List ListNew(int type_size); + +/* Free a list object +*/ +List ListClear(List l); + +/* Free all elements in a list +*/ +List ListEmpty(List l); + +/* Return number of elements in list +*/ +int ListSize(List l); + +/* Create an iterator over the list +*/ +Iterator ListIterator(List l); + +/* Destory an iterator +*/ +Iterator IteratorClear(Iterator i); + +/* Get data for pointed to by this iterator object +*/ +void *IteratorData(Iterator i); + +/* Move the iterator to the next element. NULL once done. +*/ +Iterator IteratorNext(Iterator i); + +/* Move the iterator to the previous element. NULL once done. +*/ +Iterator IteratorPrev(Iterator i); + +/* Replace the data currently stored in this this position with the new one +*/ +Iterator IteratorUpdate(Iterator i,void *data); + +/* Delete the data currently stored in this position and move the iterator to + the next element. +*/ +Iterator IteratorDelete(Iterator i); + +/* Append to the tail of the the list +*/ +void ListAppend(List l,void *data); + +/* Insert at the head of the the list +*/ +void ListInsert(List l,void *data); + +/* Return an iterator for the searched element. Note the fist void* passed + to the predicate will be of the type stored in the lists. The second + argument will be whatever was passed as data. +*/ +Iterator ListFindElem(List l,int (*pred)(void *, void *),void *data); + +#endif + + +/* END OF FILE */ diff --git a/make/djgpp.cfg b/make/djgpp.cfg new file mode 100644 index 0000000..e682b61 --- /dev/null +++ b/make/djgpp.cfg @@ -0,0 +1,41 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program 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. +# +# This program is distributed in the hope that 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# +# Makefile config for DJGPP +# +# $Id: djgpp.cfg,v 1.6 2000/07/28 12:18:35 dosuser Exp dosuser $ +# +CC= gcc +LD= gcc +PLATFORM= djgpp +EXE_EXT= .exe +OBJ_EXT= .o +LIBS= -lalleg +EXTRACF= -g -O -Wall +EXTRALF= +DIRSEP= "/" +MATHLIB= -lm +TRACEFORM= "%s(%d):%s\n",__FILE__,__LINE__,__FUNCTION__ +EXEFLAG= -o +OBJFLAG= -c +DEFINEFLAG= -D +INCFLAG= -I +MAKEINSTALL= make INSTALLDIR='$(INSTALLDIR)' -f install + diff --git a/makefile b/makefile new file mode 100644 index 0000000..036a787 --- /dev/null +++ b/makefile @@ -0,0 +1,256 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program 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. +# +# This program is distributed in the hope that 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# + +# +# START OF CONFIGURATION PART +# +# 1. The platform to compile for. Currently supported ones are: +# djgpp +# +MAKEPLAT=djgpp + + +# 2. Set to the directory where you want to install viDOOM. Note this is not +# used in the default make - a 'make install' must be issued to activate +# this. +# +INSTALLDIR=C:/viDOOM + + +# 3. The directory seperator for this machine. This is unquoted (unlike the +# seperator in the config file) as this is for the makefiles own use. +# +MKDS=/ + + +# +# END OF CONFIGURATION PART +# + + + +# Shouldn't be any need to edit past here +# +include make$(MKDS)$(MAKEPLAT).cfg + + +# Uncomment to build debug version +# +# DEBUG=$(DEFINEFLAG)DEBUG + + +CFLAGS= $(EXTRACF) $(DEFINEFLAG)TRACEFORM='$(TRACEFORM)' $(DEBUG) \ + $(DEFINEFLAG)PLATFORM=$(PLATFORM) \ + $(DEFINEFLAG)DIRSEP='$(DIRSEP)' $(INCFLAG). + +VIDOOM= vidoom +WADDIR= waddir +GFXTEST= gfxtest + +COMMON_OBJ= $(PLATFORM)$(MKDS)main$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)file$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)gfx$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)mem$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)platgui$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)runcmd$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)vstring$(OBJ_EXT) \ + ini$(OBJ_EXT) wad$(OBJ_EXT) \ + list$(OBJ_EXT) map$(OBJ_EXT) gui$(OBJ_EXT) debug$(OBJ_EXT) \ + globals$(OBJ_EXT) texture$(OBJ_EXT) things$(OBJ_EXT) \ + linedefs$(OBJ_EXT) sectors$(OBJ_EXT) edit$(OBJ_EXT) \ + editcord$(OBJ_EXT) editdraw$(OBJ_EXT) editgui$(OBJ_EXT) \ + editevnt$(OBJ_EXT) editline$(OBJ_EXT) editmult$(OBJ_EXT) \ + editsect$(OBJ_EXT) editsel$(OBJ_EXT) editthng$(OBJ_EXT) \ + editvar$(OBJ_EXT) editvert$(OBJ_EXT) editsrot$(OBJ_EXT) \ + editcrse$(OBJ_EXT) editilst$(OBJ_EXT) editmrg$(OBJ_EXT) + +ALL_HEADERS= vidoom.h config.h file.h gfx.h mem.h map.h runcmd.h \ + ini.h wad.h list.h edit.h platgui.h gui.h debug.h globals.h \ + texture.h things.h linedefs.h editvar.h + +VIDOOM_OBJ= vidoom$(OBJ_EXT) $(COMMON_OBJ) +WADDIR_OBJ= waddir$(OBJ_EXT) $(COMMON_OBJ) +GFXTEST_OBJ= gfxtest$(OBJ_EXT) $(COMMON_OBJ) + + + +$(VIDOOM)$(EXE_EXT):$(VIDOOM_OBJ) + $(LD) $(EXTRALF) $(EXEFLAG) $(VIDOOM)$(EXE_EXT) \ + $(VIDOOM_OBJ) $(LIBS) $(MATHLIB) + +$(WADDIR)$(EXE_EXT):$(WADDIR_OBJ) + $(LD) $(EXTRALF) $(EXEFLAG) $(WADDIR)$(EXE_EXT) \ + $(WADDIR_OBJ) $(LIBS) $(MATHLIB) + +$(GFXTEST)$(EXE_EXT):$(GFXTEST_OBJ) + $(LD) $(EXTRALF) $(EXEFLAG) $(GFXTEST)$(EXE_EXT) $(GFXTEST_OBJ) \ + $(LIBS) $(MATHLIB) + +all: $(VIDOOM)$(EXE_EXT) $(WADDIR)$(EXE_EXT) $(GFXTEST)$(EXE_EXT) + + +$(PLATFORM)$(MKDS)main$(OBJ_EXT): $(PLATFORM)$(MKDS)main.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. main.c ; cd .. + +$(PLATFORM)$(MKDS)file$(OBJ_EXT): $(PLATFORM)$(MKDS)file.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. file.c ; cd .. + +$(PLATFORM)$(MKDS)gfx$(OBJ_EXT): $(PLATFORM)$(MKDS)gfx.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. gfx.c ; cd .. + +$(PLATFORM)$(MKDS)mem$(OBJ_EXT): $(PLATFORM)$(MKDS)mem.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. mem.c ; cd .. + +$(PLATFORM)$(MKDS)platgui$(OBJ_EXT): $(PLATFORM)$(MKDS)platgui.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. platgui.c ; cd .. + +$(PLATFORM)$(MKDS)runcmd$(OBJ_EXT): $(PLATFORM)$(MKDS)runcmd.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. runcmd.c ; cd .. + +$(PLATFORM)$(MKDS)vstring$(OBJ_EXT): $(PLATFORM)$(MKDS)vstring.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. vstring.c ; cd .. + + +debug$(OBJ_EXT): debug.c config.h debug.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +edit$(OBJ_EXT): edit.c config.h globals.h edit.h wad.h map.h list.h editvar.h \ + things.h gfx.h platgui.h linedefs.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editcord$(OBJ_EXT): editcord.c config.h globals.h texture.h gfx.h platgui.h \ + editvar.h things.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editdraw$(OBJ_EXT): editdraw.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editevnt$(OBJ_EXT): editevnt.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editgui$(OBJ_EXT): editgui.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h texture.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editline$(OBJ_EXT): editline.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editsect$(OBJ_EXT): editsect.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editsel$(OBJ_EXT): editsel.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editsrot$(OBJ_EXT): editsrot.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editcrse$(OBJ_EXT): editcrse.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editthng$(OBJ_EXT): editthng.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editvar$(OBJ_EXT): editvar.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editvert$(OBJ_EXT): editvert.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editmrg$(OBJ_EXT): editmrg.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editmult$(OBJ_EXT): editmult.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editilst$(OBJ_EXT): editilst.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +gfxtest$(OBJ_EXT): gfxtest.c config.h globals.h gfx.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +globals$(OBJ_EXT): globals.c config.h globals.h ini.h gfx.h texture.h \ + platgui.h things.h linedefs.h sectors.h wad.h map.h list.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +gui$(OBJ_EXT): gui.c config.h globals.h gui.h gfx.h platgui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +ini$(OBJ_EXT): ini.c config.h ini.h mem.h file.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +linedefs$(OBJ_EXT): linedefs.c config.h globals.h linedefs.h wad.h map.h \ + list.h gfx.h platgui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +sectors$(OBJ_EXT): sectors.c config.h globals.h sectors.h wad.h map.h list.h \ + gfx.h platgui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +list$(OBJ_EXT): list.c config.h list.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +map$(OBJ_EXT): map.c config.h map.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +texture$(OBJ_EXT): texture.c config.h globals.h texture.h gfx.h platgui.h \ + wad.h map.h list.h mem.h gui.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +things$(OBJ_EXT): things.c config.h globals.h things.h gfx.h platgui.h mem.h \ + list.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +wad$(OBJ_EXT): wad.c config.h globals.h wad.h map.h list.h gfx.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + + +$(VIDOOM)$(OBJ_EXT): $(VIDOOM).c $(ALL_HEADERS) + $(CC) $(CFLAGS) $(OBJFLAG) $(VIDOOM).c + +$(WADDIR)$(OBJ_EXT): $(WADDIR).c $(ALL_HEADERS) + $(CC) $(CFLAGS) $(OBJFLAG) $(WADDIR).c + + +# Rule for installation +# +install: $(VIDOOM)$(EXE_EXT) FORCE + cd $(PLATFORM) ; $(MAKEINSTALL) + +FORCE: + + +# +# $Id: makefile,v 1.28 2000/07/28 15:30:24 dosuser Exp dosuser $ +# +# END OF FILE diff --git a/map.c b/map.c new file mode 100644 index 0000000..95421a8 --- /dev/null +++ b/map.c @@ -0,0 +1,162 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides a dynamic sort-of-array type + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include + +#include "map.h" +#include "mem.h" + +#define MAPCHUNK 100 + +struct _Map + { + int top; + int alloc; + int size; + char *data; + }; + +/* ---------------------------------------- +*/ +Map MapNew(int type_size) +{ + Map nm; + + nm=Grab(sizeof(struct _Map)); + + nm->top=-1; + nm->size=type_size; + nm->alloc=0; + nm->data=NULL; + + return(nm); +} + +Map MapCopy(Map m) +{ + Map nm; + + nm=NULL; + + if (m) + { + nm=Copy(m,sizeof(struct _Map)); + nm->data=Copy(m->data,m->alloc*m->size); + } + + return(nm); +} + +Map MapClear(Map m) +{ + if (m) + { + if (m->data) + Release(m->data); + Release(m); + } + + return(NULL); +} + +Map MapEmpty(Map m) +{ + if (m) + { + if (m->data) + Release(m->data); + + m->top=-1; + m->alloc=0; + m->data=NULL; + } + + return(m); +} + +int MapSize(Map m) +{ + if (m) + return(m->top+1); + else + return(0); +} + +void *MapElem(Map m,int no) +{ + if ((no<0)||(no>m->top)) + return(NULL); + else + return(m->data+(no*m->size)); +} + +void MapAdd(Map m,int no,void *data) +{ + if (no==-1) + no=m->top+1; + + if (m->allocalloc=(no/MAPCHUNK+1)*MAPCHUNK; + + if (m->data) + m->data=ReGrab(m->data,m->alloc*m->size); + else + m->data=Grab(m->alloc*m->size); + } + + memcpy(m->data+(no*m->size),data,m->size); + + if (m->toptop=no; +} + +void *MapFindElem(Map m,int (*pred)(void *, void *),void *data) +{ + int f; + void *ret,*e; + + ret=NULL; + f=0; + + while((f<=m->top)&&(!ret)) + { + e=MapElem(m,f); + + if ((*pred)(e,data)) + ret=e; + + f++; + } + + return(ret); +} + + +/* END OF FILE */ diff --git a/map.h b/map.h new file mode 100644 index 0000000..9878fe4 --- /dev/null +++ b/map.h @@ -0,0 +1,86 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides a dynamic sort-of-array type + + $Id$ + +*/ + +#ifndef _MAP_H + +#define _MAP_H + +/* Opaque types for the map. NULL is the null map. +*/ +struct _Map; +typedef struct _Map *Map; + +/* Create a new Map that handles objects of type_size +*/ +Map MapNew(int type_size); + + +/* Copy a Map +*/ +Map MapCopy(Map m); + + +/* Destroy a Map object +*/ +Map MapClear(Map m); + + +/* Destroy all elements in a Map +*/ +Map MapEmpty(Map m); + + +/* Return number of elements in the Map +*/ +int MapSize(Map m); + + +/* Get the element from index no +*/ +void *MapElem(Map m,int no); + + +/* Add an element at position no. no==-1 positions the element at the end +*/ +void MapAdd(Map m,int no,void *data); + + +/* Find and element, searching using the passed predicate function. Function + should return TRUE for found, FALSE for not found. + + Note the fist void* passed to the predicate will be of the type stored in + the Map. The second argument will be whatever was passed as data. + + Returns NULL if the entry cannot be found. +*/ +void *MapFindElem(Map m,int (*pred)(void *, void *),void *data); + +#endif + + +/* END OF FILE */ diff --git a/mem.h b/mem.h new file mode 100644 index 0000000..11fdfb7 --- /dev/null +++ b/mem.h @@ -0,0 +1,79 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Memory allocation + + $Id$ + +*/ + +#ifndef _MEM_H + +#define _MEM_H + +/* Notes: All these functions take debug information. The versions actually + used in the code are the #define's following the prototypes +*/ + + +/* Grab len bytes of memory. len==0 is valid. Memory is zereod on allocation. +*/ +void *FGrab(char *file, int line, int len); + + +/* Given a pointer returned by Grab() and a new size reallocates it to a + larger or smaller block. The orignal contents are copied to the new + block. Passing an NULL for ptr makes this call the same as FGrab(len). +*/ +void *FReGrab(char *file, int line, void *ptr, int len); + + +/* Reserve len bytes and copy len bytes from p to the new memory. len==0 is + valid +*/ +void *FCopy(char *file, int line, void *p,int len); + + +/* Reserve space for the nul terminated string and copy the source there. + Return is NULL if source is NULL +*/ +char *FStrdup(char *file, int line, char *s); + + +/* Release allocated memory +*/ +void FRelease(char *file, int line, void *p); + + + +/* Actually use these +*/ +#define Grab(n) FGrab(__FILE__,__LINE__,(n)) +#define ReGrab(p,n) FReGrab(__FILE__,__LINE__,(p),(n)) +#define Copy(p,n) FCopy(__FILE__,__LINE__,(p),(n)) +#define Strdup(p) FStrdup(__FILE__,__LINE__,(p)) +#define Release(p) FRelease(__FILE__,__LINE__,(p)) + +#endif + + +/* END OF FILE */ diff --git a/platgui.h b/platgui.h new file mode 100644 index 0000000..0719ef0 --- /dev/null +++ b/platgui.h @@ -0,0 +1,199 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Platform specific GUI routines + + This is the platform specific routines for pop-up menus, dialogs and + file selectors. More DOOM graphics orientied GUI is handled by the + generic GUI (gui.h) that is built on top of gfx. + + As with the platform specific GFX all calls can be differentiated from + the generic gui by starting with GUI_, rather than Gui. + + Note that all these routines are expected to preserve screen contents. + + $Id$ + +*/ + +#ifndef _PLATGUI_H +#define _PLATGUI_H + +#include "gfx.h" + +/* Type for a picklist, where each entry has an associated grahpic. If the + image is NULL then no picture should be shown for that entry. +*/ +typedef struct + { + char *text; + GFX_IMAGE img; + int client_index; /* Returned by GUI_image_picklist() */ + } PLAT_IMG_PICKLIST; + + +/* Type for a picklist +*/ +typedef struct + { + char *text; + int client_index; /* Returned by GUI_client_picklist() */ + } PLAT_PICKLIST; + + +/* Types to define a menu +*/ +typedef struct + { + char *text; /* Text to display */ + int client_index; /* Value returned by GUI_menu() */ + } PLAT_MENU; + + +/* Types to define a radio box +*/ +typedef struct + { + char *text; /* Label for this button. NULL==end */ + int client_index; /* Value returned by GUI_radio() */ + } PLAT_RADIO; + +/* Types to define a simple dialog +*/ +#define PLAT_DIAL_MAXSTRLEN 128 + +#define PLAT_DIAL_STRING 0 +#define PLAT_DIAL_INTEGER 1 +#define PLAT_DIAL_DOUBLE 2 + +typedef struct + { + char *text; /* Label for item. NULL==no label */ + int type; /* Data type (PLAT_DIAL_xxx) */ + union /* Data */ + { + int i; + char s[PLAT_DIAL_MAXSTRLEN+1]; + double d; + } data; + } PLAT_DIALOG; + + +/* Inform GUI of screen size if required +*/ +void GUI_setscreen(int w,int h); + +/* Display a Yes/No option box. Returns TRUE/FALSE accordingly. +*/ +int GUI_yesno(char *question); + + +/* Pop-up/display a menu. Return the client_index of the selected item from the + menus, or defval for no selection. The co-ords can obviously be ignored or + honoured, though honouring is preferable. + + MENU array is terminated by one with a NULL text entry. +*/ +int GUI_menu(char *title, int x, int y, PLAT_MENU menu[], int defval); + + +/* Allow selection of a filename. Returns NULL if cancelled, otherwise the + selected path with must be Releas()'ed later. + + If supported then files ending with filter should only be displayed. Filter + should be NULL to show all files. +*/ +char *GUI_fsel(char *title, char *default_path, char *filter); + + +/* Display a picklist. The items are described by the array of pointers + passed in, which terminates with a NULL pointer. The index to the selected + item is returned, or -1 if the pickbox was cancelled. +*/ +int GUI_picklist(char *title,char *opts[]); + + +/* Does a picklist as above, but works on structures cntaining client return + values, rather than simple array indexes. +*/ +int GUI_client_picklist(char *title,PLAT_PICKLIST opts[],int defval); + + +/* Display a picklist with associated images. The items are described by the + array of structs passed in, which terminates with a NULL pointer in the + text field. The client index data in the selected item is returned, or + defval if the pickbox was cancelled. + + If this cannot be supported on the platform then the minimum this should + do is a sideways call to GUI_client_picklist() +*/ +int GUI_image_picklist(char *title,PLAT_IMG_PICKLIST opts[],int defval); + + +/* Display a radio box. The items are described by the array of structs + passed in, which terminates with a NULL pointer in the text field. + The client index data in the selected item is returned, or defval if the + radio box was cancelled. + + If one of the entries client index values is the same as current then that + option will be the one selected when the radio box is displayed. Otherwise + the first item will be the selected one. +*/ +int GUI_radio_box(char *title,PLAT_RADIO opts[],int current,int defval); + +/* Display a mutli-selection radio box. The items are described by the array + of char pointers passed in, which terminates with a NULL pointer. + + The passed in integer pointer points to a value which is used to enable/ + disable the options dependent on the integers bit setting. The integer + pointed to is updated on exit of the multi-selection box is not cancelled. + + Note that the bit patterns are matched bit number to opt index. ie. + val & 0x0001 corresponds to opts[0] + val & 0x0002 corresponds to opts[1] + .... + val & 0x0010 corresponds to opts[4] + .... + val & 0x0100 corresponds to opts[8] + .... + val & 0x8000 corresponds to opts[15] + + A maximum of 16 bits should be all that needs supporting currently. + + Returns TRUE if dialog accepted, otherwise FALSE. +*/ +int GUI_multi_box(char *title,char *opts[],int *val); + + +/* Displays a very simple dialog made up of 'no' fields as defined in pd[]. + Returns TRUE if the dialog is accepted, FALSE otherwise. + + Note that as the values in the PLAT_DIALOG array are not pointing to + actual client data they need not be preserved on a cancel of the dialog. +*/ +int GUI_dialog(char *title, int no, PLAT_DIALOG pd[]); + + +#endif + + +/* END OF FILE */ diff --git a/runcmd.h b/runcmd.h new file mode 100644 index 0000000..e1ba406 --- /dev/null +++ b/runcmd.h @@ -0,0 +1,57 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Command execution interface + + $Id$ + + +*/ + +#ifndef _RUNCMD_H + +#define _RUNCMD_H + +/* Run a command. Te output from the command (if any) should NOT disturb the + screen contents. The call should return TRUE if the call succeeds, FALSE + otherwise. + + The argv list is an array of pointers to various sections of the command + and it's arguemnts, terminated with a NULL pointer. + + Note that arguments may contain more than one argument in each line, ie. + the actual command is described simply by concatanating all the + pointers together, eg. + argv[0]="bsp.exe" + argv[1]="x.wad" + argv[2]="-o x.wad" + argv[3]=NULL + + The path argument is a place to copy a file where the output from the + comand has been stored. If this is not supported then the empty string + should be assigned to it. viDOOM will remove() the file after it has + read it. +*/ +int RunCommand(char *argv[],char *path); + + +#endif diff --git a/sectors.c b/sectors.c new file mode 100644 index 0000000..0c6ce40 --- /dev/null +++ b/sectors.c @@ -0,0 +1,318 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Handles definition and storage of the supported SECTORS + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "sectors.h" +#include "mem.h" +#include "list.h" +#include "map.h" + + +/* ---------------------------------------- TYPES AND VARS +*/ +typedef struct + { + char *name; + } + SectorClass; + +typedef struct + { + int class; + int id; + char *long_name; + char *short_name; + } SectorInfo; + +typedef struct + { + int flags; + char *name; + DirName upper; + DirName middle; + DirName lower; + DirName floor; + DirName ceiling; + } SectorStyle; + +static int no_classes=0; + +static Map sect_class=NULL; +static List sect_list=NULL; +static Map sect_style=NULL; + +static PLAT_MENU *menu=NULL; +static PLAT_PICKLIST **picklist=NULL; + +static char **sect_style_plist=NULL; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static PLAT_PICKLIST *SectorPicklist(int class) +{ + SectorInfo *si; + Iterator i; + int no; + int f; + + if (picklist[class]) + return(picklist[class]); + + no=0; + i=ListIterator(sect_list); + + while(i) + { + si=IteratorData(i); + + if (si->class==class) + no++; + + i=IteratorNext(i); + } + + picklist[class]=Grab(sizeof(PLAT_PICKLIST)*(no+1)); + + i=ListIterator(sect_list); + + f=0; + while(i) + { + si=IteratorData(i); + + if (si->class==class) + { + picklist[class][f].text=si->long_name; + picklist[class][f].client_index=si->id; + f++; + } + + i=IteratorNext(i); + } + + picklist[class][f].text=NULL; + + return(picklist[class]); +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void SectorNewClass(char *class) +{ + SectorClass c; + + if (!sect_class) + sect_class=MapNew(sizeof(SectorClass)); + + c.name=Strdup(class); + + MapAdd(sect_class,no_classes++,&c); +} + + +void SectorAdd(char *class,int id,char *long_name,char *short_name) +{ + SectorInfo *s; + int i_class; + int f; + + if (!sect_list) + sect_list=ListNew(sizeof(SectorInfo)); + + s=Grab(sizeof(SectorInfo)); + + i_class=-1; + + for(f=0;fname,class)) + i_class=f; + } + + if (i_class==-1) + i_class=0; + + s->class=i_class; + s->id=id; + s->long_name=Strdup(long_name); + s->short_name=Strdup(short_name); + ListAppend(sect_list,s); +} + + +int SelectSector(void) +{ + int class; + int f; + int x,y; + + if (!menu) + { + menu=Grab(sizeof(PLAT_MENU)*(no_classes+1)); + picklist=Grab(sizeof(PLAT_IMG_PICKLIST *)*(no_classes+1)); + + for(f=0;fname; + menu[f].client_index=f; + } + + for(f=0;fid==id) + { + IteratorClear(i); + return(si->short_name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +void StartSectorStyles(void) +{ + SectorStyle *s; + int f; + + if (!sect_style) + { + for(f=0;fname); + } + + sect_style=MapNew(sizeof(SectorStyle)); + } + else + MapEmpty(sect_style); +} + + +void AddSectorStyle(char *name, int flags, DirName upper, DirName middle, + DirName lower, DirName floor, DirName ceiling) +{ + SectorStyle s; + + s.flags=flags; + s.name=Strdup(name); + strcpy(s.upper,upper); + strcpy(s.middle,middle); + strcpy(s.lower,lower); + strcpy(s.floor,floor); + strcpy(s.ceiling,ceiling); + + MapAdd(sect_style,-1,&s); +} + + +int ChooseSectorStyle(int *flags, DirName upper,DirName middle,DirName lower, + DirName floor,DirName ceiling) +{ + SectorStyle *s; + int f; + + if (!sect_style_plist) + { + sect_style_plist=Grab(sizeof(char *)*(MapSize(sect_style)+1)); + + for(f=0;fname; + } + + sect_style_plist[MapSize(sect_style)]=NULL; + } + + f=GUI_picklist("SECTOR STYLE",sect_style_plist); + + if (f!=-1) + { + s=MapElem(sect_style,f); + *flags=s->flags; + strcpy(lower,s->lower); + strcpy(middle,s->middle); + strcpy(upper,s->upper); + strcpy(floor,s->floor); + strcpy(ceiling,s->ceiling); + return(TRUE); + } + else + return(FALSE); +} + +int NoSectorStyles(void) +{ + return(MapSize(sect_style)); +} + + +/* END OF FILE */ diff --git a/sectors.h b/sectors.h new file mode 100644 index 0000000..b59ec63 --- /dev/null +++ b/sectors.h @@ -0,0 +1,96 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Handles definition and storage of the supported SECTORs + + $Id$ + +*/ + +#ifndef _SECTORS_H + +#define _SECTORS_H + +#include "wad.h" +#include "gfx.h" +#include "platgui.h" + +/* This is not going to be an ID, so is returned from SelectSector() if it is + cancelled. +*/ +#define SECTOR_NULLID -666 + + +/* Meanings for the flags in the sector styles +*/ +#define SSTYLE_FACING_IN 0x01 +#define SSTYLE_FACING_OUT 0x02 +#define SSTYLE_LEAVE_PEG 0x04 +#define SSTYLE_UPPER_PEG 0x08 +#define SSTYLE_LOWER_PEG 0x10 + + +/* Add a new class of sector +*/ +void SectorNewClass(char *class); + + +/* Add the named type to the supplied class with the ID +*/ +void SectorAdd(char *class,int id,char *long_name, char *short_name); + + +/* Select the ID type for a sector. Returns SECTOR_NULLID if cancelled +*/ +int SelectSector(void); + + +/* Returns the short name of a sector type +*/ +char *SectorName(int id); + + +/* Start defining sector styles. +*/ +void StartSectorStyles(void); + +/* Define a linedef style +*/ +void AddSectorStyle(char *name, int flags, + DirName upper,DirName middle,DirName lower, + DirName floor,DirName ceiling); + +/* Return the number of defined sector styles +*/ +int NoSectorStyles(void); + +/* Choose a sector style. TRUE is accepted, FALSE cancelled. +*/ +int ChooseSectorStyle(int *flags, + DirName upper,DirName middle,DirName lower, + DirName floor,DirName ceiling); + + +#endif + + +/* END OF FILE */ diff --git a/texture.c b/texture.c new file mode 100644 index 0000000..eb29d01 --- /dev/null +++ b/texture.c @@ -0,0 +1,594 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Stores lists of the graphical information from the WADs + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include + +#include "texture.h" +#include "wad.h" +#include "mem.h" +#include "gfx.h" +#include "platgui.h" +#include "gui.h" +#include "vstring.h" + + +PLAT_IMG_PICKLIST *flat_picklist=NULL; +PLAT_IMG_PICKLIST *texture_picklist=NULL; + +/* The height and width of a texture are actually stored along with the + texture name +*/ +#define TXTNUMWID 8 +#define TXTHEIGHT 10 +#define TXTWIDTH 20 +#define TXTMALLOC 31 + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static int CmpText(const void *a,const void *b) +{ + const PLAT_IMG_PICKLIST *p1,*p2; + + p1=a; + p2=b; + + return(StrCaseCmp(p1->text,p2->text)); +} + + +static Byte *GetShort(Byte *p,Short *s) +{ + *s=(Short)(*p++); + *s|=((Short)(*p++))<<8; + return(p); +} + + +static Byte *GetLong(Byte *p,Long *l) +{ + *l=(Long)(*p++); + *l|=((Long)(*p++))<<8; + *l|=((Long)(*p++))<<16; + *l|=((Long)(*p++))<<24; + return(p); +} + +static Byte *GetName(Byte *p,char *s) +{ + int f; + + for(f=0;f<8;f++) + *s++=*p++; + + *s=0; + return(p); +} + + +static void BMPlot(int x,int y,int c,GFX_BITMAP *bm) +{ + if ((x>=0)&&(xw)&&(y>=0)&&(yh)) + *(bm->data+(x)+(y*bm->w))=c; +} + + +static void DecodeLump(Byte *lump, int ox, int oy, GFX_BITMAP *bm) +{ + Short lw,lh,lox,loy; + Byte *base; + Byte *col; + Long off; + int x,y,f; + Byte cno; + + base=lump; + lump=GetShort(lump,&lw); + lump=GetShort(lump,&lh); + lump=GetShort(lump,&lox); + lump=GetShort(lump,&loy); + + lox=MAX(lox,0); + loy=MAX(loy,0); + + for(x=0;xw=MIN(w,MAX_GFXBM_W); + + t_ent=GetShort(t_ent,&h); + bm->h=MIN(h,MAX_GFXBM_H); + + /* Once we have the width and height, return if the actual image is not to + be loaded + */ + if (!load_textures) + return(NULL); + + /* Skip over always zero fields + */ + t_ent+=4; + + /* The bitmap is filled with the transparent colour + */ + memset(bm->data,243,w*h); + + /* Get no of patches that make up this texture + */ + t_ent=GetShort(t_ent,&no); + + /* Read each patch and add to the texture + */ + for(f=0;fw); + sprintf(texture_picklist[*i].text+TXTHEIGHT, + "%*.*d",TXTNUMWID,TXTNUMWID,bm->h); + + + (*i)++; + } +} + + +/* ------------------------------ EXPORTED FUNCTIONS +*/ + +void ReadWADFlats(void) +{ + WadDir *wd; + Iterator i; + int found; + int done; + GFX_BITMAP bm; + Byte *pal; + int no; + int ip; + int f; + + if (!(pal=GetLump("PLAYPAL",NULL))) + GFX_exit(EXIT_FAILURE,"There MUST be a PLAYPAL lump in the WADs!!\n"); + + if (flat_picklist) + { + ip=0; + while(flat_picklist[ip].text) + { + Release(flat_picklist[ip].text); + if (flat_picklist[ip].img) + GFX_destroy_image(flat_picklist[ip].img); + } + + Release(flat_picklist); + } + + /* Get number of flats (Naughty.. Means we read through dir twice...) + */ + i=GetWadDir(); + + found=FALSE; + done=FALSE; + no=0; + + while((i)&&(!done)) + { + wd=IteratorData(i); + + if (!found) + found=!StrCaseCmp(wd->name,"F_START"); + else + if (!(done=!StrCaseCmp(wd->name,"F_END"))) + if (wd->size==0x1000) + no++; + + i=IteratorNext(i); + } + + IteratorClear(i); + flat_picklist=Grab(sizeof(PLAT_IMG_PICKLIST)*(no+1)); + flat_picklist[no].text=NULL; + flat_picklist[no].img=NULL; + + /* Palette and size for bitmap + */ + bm.w=64; + bm.h=64; + + for(f=0;f<256;f++) + { + int r,g,b; + + r=(int)(pal[f*3]*gfx_brighten); + g=(int)(pal[f*3+1]*gfx_brighten); + b=(int)(pal[f*3+2]*gfx_brighten); + + r=MIN(255,r); + g=MIN(255,g); + b=MIN(255,b); + + bm.pal[f]=V_RGB(r,g,b); + } + + /* Load in the names and graphics + */ + i=GetWadDir(); + + found=FALSE; + done=FALSE; + ip=0; + + while((i)&&(!done)) + { + wd=IteratorData(i); + + if (!found) + found=!StrCaseCmp(wd->name,"F_START"); + else + if (!(done=!StrCaseCmp(wd->name,"F_END"))) + if (wd->size==0x1000) + { + flat_picklist[ip].text=Strdup(wd->name); + + if (load_flats) + { + /* GFX_BITMAP and DOOM flats are actually in the same + format + */ + if (!(bm.data=GetLump(wd->name,NULL))) + GFX_exit(EXIT_FAILURE, + "Failed to load flat %s\n",wd->name); + + flat_picklist[ip].img=GFX_create_image(&bm); + + Release(bm.data); + } + else + flat_picklist[ip].img=NULL; + + GuiDrawInfoBox((load_flats ? + "Please wait. Reading flat graphics": + "Please wait. Reading flat names"), + GUI_CENTRE,GUI_CENTRE,TRUE, + "Flat %s|%d%% complete", + wd->name,ip*100/no); + GFX_redraw(); + + ip++; + } + + i=IteratorNext(i); + } + + IteratorClear(i); + Release(pal); + + /* Sort the list if requested + */ + if (sort_flats) + qsort(flat_picklist,no-1,sizeof(PLAT_IMG_PICKLIST),CmpText); + + /* Set the client indexes + */ + for(f=0;fclass==class) + no++; + + i=IteratorNext(i); + } + + picklist[class]=Grab(sizeof(PLAT_IMG_PICKLIST)*(no+1)); + + i=ListIterator(thing_list); + + f=0; + while(i) + { + ti=IteratorData(i); + + if (ti->class==class) + { + picklist[class][f].text=ti->name; + picklist[class][f].img=ti->img; + picklist[class][f].client_index=ti->id; + f++; + } + + i=IteratorNext(i); + } + picklist[class][f].text=NULL; + picklist[class][f].img=NULL; + + return(picklist[class]); + } +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void ThingNewClass(char *class, int col) +{ + ThingClass c; + + if (!thing_class) + thing_class=MapNew(sizeof(ThingClass)); + + c.name=Strdup(class); + c.col=col; + + MapAdd(thing_class,no_classes++,&c); +} + + +void ThingAdd(char *class,char *name,int id,int rad,GFX_IMAGE sprite) +{ + ThingInfo *ti; + ThingRad *tr; + int i_class; + int col; + int f; + + if (!thing_list) + { + thing_list=ListNew(sizeof(ThingInfo)); + rad_list=ListNew(sizeof(ThingInfo)); + } + + i_class=-1; + col=DEFAULT_COL; + + for(f=0;fname,class)) + { + i_class=f; + col=c->col; + } + } + + if (i_class==-1) + i_class=0; + + ti=Grab(sizeof(ThingInfo)); + + ti->class=i_class; + ti->name=Strdup(name); + ti->id=id; + ti->img=sprite; + ListAppend(thing_list,ti); + + tr=Grab(sizeof(ThingRad)); + tr->id=id; + tr->rad=rad; + tr->col=col; + ListAppend(rad_list,tr); +} + + +int SelectThing(void) +{ + int class; + int f; + int x,y; + + if (!thing_menu) + { + thing_menu=Grab(sizeof(PLAT_MENU)*(no_classes+1)); + picklist=Grab(sizeof(PLAT_IMG_PICKLIST *)*(no_classes+1)); + + for(f=0;fname; + thing_menu[f].client_index=f; + } + + for(f=0;fid==id) + { + IteratorClear(i); + + if (col) + *col=r->col; + + return(r->rad); + } + + i=IteratorNext(i); + } + + if (col) + *col=DEFAULT_COL; + + return(DEFAULT_RAD); +} + + +char *ThingName(int id) +{ + ThingInfo *ti; + Iterator i; + + i=ListIterator(thing_list); + + while(i) + { + ti=IteratorData(i); + + if (ti->id==id) + { + IteratorClear(i); + return(ti->name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +void ThingFlag(int bit,char *s,char *sh) +{ + thing_flags[bit]=Strdup(s); + thing_flags_sh[bit]=Strdup(sh); +} + + +char **ThingFlagArray(void) +{ + return(thing_flags); +} + + +char *ThingFlagText(int flags) +{ + static char s[512]; + int b; + + s[0]=0; + + for(b=0;b<16;b++) + if (flags&(1< +#include +#include + +#include "wad.h" +#include "platgui.h" +#include "gui.h" +#include "gfx.h" +#include "file.h" +#include "mem.h" +#include "edit.h" +#include "texture.h" +#include "things.h" +#include "runcmd.h" + +/* ---------------------------------------- VARS +*/ +static WadMap *wad=NULL; +static char mapname[32]="NONE"; +static GFX_IMAGE doom_image; + +/* Menu for asking game type +*/ +static PLAT_MENU game_type_menu[]= + { + {"Doom", DOOM}, + {"Ultimate Doom", ULTIMATE_DOOM}, + {"Doom II", DOOM_2}, + {"TNT:Evilution", FINAL_TNT}, + {"The Plutonia Experiment", FINAL_PLUTONIA}, + {"ZDoom", ZDOOM}, + {NULL,0} + }; + + +/* ---------------------------------------- PROTOS +*/ +static void MainMenu(void); +static void GPL_clear(void); + + +/* ---------------------------------------- MAIN +*/ +int viDOOM(int argc,char *argv[]) +{ + char *load,*p; + int f; + + GFX_init(); + GFX_clear_XOR_mode(); + + if (GFX_mouse_buttons()<2) + GFX_exit(EXIT_FAILURE,"viDOOM expects at least a 2-button mouse\n"); + + LoadGlobalsPart1(); + + if ((disp_width<640)||(disp_height<480)) + GFX_exit(EXIT_FAILURE,"viDOOM expects at least a display of 640x480\n"); + + GFX_open(disp_width,disp_height); + EditSetScreen(disp_width,disp_height); + GuiSetScreen(disp_width,disp_height); + GUI_setscreen(disp_width,disp_height); + + GPL_clear(); + + /* Ask for game type? + */ + if (ask_for_game_type) + { + int new; + + GFX_redraw(); + + new=GUI_menu("Select type of game to edit", + disp_width/2,disp_height/2,game_type_menu,-666); + + if (new!=-666) + game=(GameType)new; + } + + LoadGlobalsPart2(); + + if (AddIWAD(IWAD_path)!=WAD_OK) + { + GuiInfoBox("ERROR","AddIWAD(%s): %s",IWAD_path,WadErrorString()); + GFX_close(); + return(EXIT_FAILURE); + } + + /* Read in resource WADS from preloaded config + */ + if (PWAD_preload[0]) + { + load=Strdup(PWAD_preload); + + p=strtok(load,";"); + + while(p) + { + if (AddPWAD(p)!=WAD_OK) + GuiInfoBox("ERROR","AddPWAD(%s): %s",p,WadErrorString()); + + p=strtok(NULL,";"); + } + + Release(load); + } + + /* Read in WADS from command line + */ + for(f=1;fname,wd->off,wd->size,Basename(wd->wad)); + list[f++]=Strdup(s); + } + + list[f]=NULL; + + GUI_picklist("WAD DIR (Name, Offset, Size, WAD file)",list); + + f=0; + while(list[f]) + Release(list[f++]); + + Release(list); + + break; + } + + case MENU_PREVIEW: + { + char *name; + WadMap *preview; + + if ((name=GuiPickLevel("Pick map to preview"))) + if (!(preview=LoadMap(name))) + GuiInfoBox("ERROR","LoadMap(%s): %s", + name,WadErrorString()); + else + { + EditPreviewWadMap(name,preview); + preview=ClearMap(preview); + } + + break; + } + + case MENU_ABOUT: + GuiInfoBox ("viDOOM " VIDOOMVER " " VIDOOMRELEASE, + "Copyright (c) 2000 Ian Cowburn|" + "http://www.noddybox.demon.co.uk/vidoom/| |" + + "viDOOM comes with ABSOLUTELY NO WARRANTY.|" + "For details see LICENSE.| |" + + "This is free software, and you are welcome|" + "to redistribute it under certain conditions.|" + "See LICENSE for details.| |" + + "DOOM, Ultimate DOOM, DOOM 2 and Final DOOM|" + "(c) id Software.|" + "http://www.idsoftware.com/| |" + "Levels in DOOM, DOOM 2 and Ultimate DOOM|" + "designed by id Software.| |" + "Levels in The Plutonia Experiment designed by|" + "Milo & Dario Casali whilst in Team TNT.| |" + "Levels in TNT:Evilution designed by|" + "various members of Team TNT. Get details at|" + "http://www.teamtnt.com/| |" + "Thanks to all concerned for some of my favourite|" + "Lovecraftian Dark Evil Places.| |" + "viDOOM will only work if you have the registered|" + "version of any of the follow id Sofwtare games:|" + "DOOM, Ultimate DOOM, DOOM 2 or Final DOOM"); + break; + + case MENU_QUIT: + if ((map_exit_warn)&&(editted)) + quit=GUI_yesno("Map may have been changed " + "- really quit?"); + else + quit=TRUE; + break; + +#ifdef DEBUG + case MENU_DEBUG: + GuiInfoBox("DEBUG", + "block_bit=%d|" + "block_mask=%d|" + "side2_bit=%d|" + "side2_mask=%d|" + "upper_bit=%d|" + "upper_mask=%d|" + "lower_bit=%d|" + "lower_mask=%d|" + "empty_texture='%s'|" + "", + block_bit,block_mask, + side2_bit,side2_mask, + upper_peg_bit,upper_peg_mask, + lower_peg_bit,lower_peg_mask, + empty_texture); + break; +#endif + + default: + break; + } + } +} + + +/* END OF FILE */ diff --git a/vidoom.h b/vidoom.h new file mode 100644 index 0000000..2ba884b --- /dev/null +++ b/vidoom.h @@ -0,0 +1,44 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + viDOOM main entry point + + Provided to allow systems that don't start via main() to be used. The + platform dependent object main.o should do any necessary initialisation + for this port and then call the entry point here. + + $Id$ + +*/ + +#ifndef _VIDOOM_H + +#define _VIDOOM_H + +/* Main viDOOM entry point +*/ +int viDOOM(int argc, char *argv[]); + +#endif + +/* END OF FILE */ + diff --git a/vstring.h b/vstring.h new file mode 100644 index 0000000..f2f7b04 --- /dev/null +++ b/vstring.h @@ -0,0 +1,44 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides portable versions of necessary string routines + + $Id$ + + +*/ + +#ifndef _VSTRING_H + +#define _VSTRING_H + +/* Does exactly the same as strcmp(), but ignores case. + The passed in strings should not be altered. +*/ +int StrCaseCmp(char *a, char *b); + +/* Does exactly the same as strncmp(), but ignores case. + The passed in strings should not be altered. +*/ +int StrNCaseCmp(char *a, char *b, int n); + +#endif diff --git a/wad.c b/wad.c new file mode 100644 index 0000000..ca7f28a --- /dev/null +++ b/wad.c @@ -0,0 +1,806 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + WAD file definitions and readers + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include +#include + +#include "wad.h" +#include "gfx.h" +#include "mem.h" +#include "file.h" + +/* ---------------------------------------- TYPES +*/ + +typedef struct WadEnt + { + DirName name; + Long off; + Long size; + } WadEnt; + +typedef struct WadDirTable + { + int no; + WadEnt *ent; + } WadDirTable; + +typedef struct WadFile + { + FILE *fp; + char path[PATH_MAX+1]; + } WadFile; + + +/* ---------------------------------------- VARS +*/ + +#define IGNORE_LUMP 0 +#define THING_LUMP 1 +#define VERTEX_LUMP 2 +#define LINEDEF_LUMP 3 +#define SIDEDEF_LUMP 4 +#define SECTOR_LUMP 5 + +#define ERR(e,r) do {wad_err=e;return(r);} while(0) +static const char *wad_errstr[WAD_NOERROR]= + { + "no error", + "File not found", + "File not an IWAD or PWAD", + "File not an IWAD", + "File not a PWAD", + "Map not found", + "Lump not found", + "Could not create file", + __FILE__ " - ??? BROKEN ???", + }; + +static int wad_err=WAD_OK; + +static List waddir=NULL; +static List wadlist=NULL; + + +/* ---------------------------------------- MACROS +*/ +#define ERR(e,r) do {wad_err=e;return(r);} while(0) + + +/* ---------------------------------------- PREDICATE FUNCTIONS +*/ +static int FindDirEnt(void *a,void *b) +{ + WadDir *aa; + + aa=(WadDir *)a; + + return(STREQ(aa->name,b)); +} + + +static int FindWAD(void *a,void *b) +{ + WadFile *aa; + + aa=a; + + return(FilenamesEqual(aa->path,b)); +} + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static Word GetShort(FILE *fp) +{ + return ((Short)fgetc(fp)|((Short)fgetc(fp))<<8); +} + + +static Long GetLong(FILE *fp) +{ + return ((Long)fgetc(fp)| + ((Long)fgetc(fp))<<8| + ((Long)fgetc(fp))<<16| + ((Long)fgetc(fp))<<24); +} + + +static char *GetName(FILE *fp) +{ + static DirName d; + + fread(d,1,8,fp); + d[sizeof(d)-1]=0; + return(d); +} + + +static void PutShort(FILE *fp,Short s) +{ + fputc(s&0xff,fp); + fputc((s>>8)&0xff,fp); +} + + +static void PutLong(FILE *fp,Long l) +{ + fputc(l&0xff,fp); + fputc((l>>8)&0xff,fp); + fputc((l>>16)&0xff,fp); + fputc((l>>24)&0xff,fp); +} + + +static void PutName(FILE *fp,char *p) +{ + int f; + + f=0; + while(f<8) + { + fputc(*p,fp); + + if (*p) + p++; + + f++; + } +} + + +static void PutDirEnt(FILE *fp,Long off,Long size,char *p) +{ + PutLong(fp,off); + PutLong(fp,size); + PutName(fp,p); +} + + +static int IsMapLump(char *n) +{ + return(STREQ("THINGS",n)|| + STREQ("LINEDEFS",n)|| + STREQ("SIDEDEFS",n)|| + STREQ("VERTEXES",n)|| + STREQ("SEGS",n)|| + STREQ("SSECTORS",n)|| + STREQ("NODES",n)|| + STREQ("SECTORS",n)|| + STREQ("REJECT",n)|| + STREQ("BLOCKMAP",n)); +} + +static int HandledMapLump(char *n) +{ + static struct + { + char *name; + int lump; + } lump[]= { + {"THINGS",THING_LUMP}, + {"VERTEXES",VERTEX_LUMP}, + {"SIDEDEFS",SIDEDEF_LUMP}, + {"LINEDEFS",LINEDEF_LUMP}, + {"SECTORS",SECTOR_LUMP}, + {NULL,IGNORE_LUMP}, + }; + + int f; + + f=0; + while(lump[f].name) + { + if (STREQ(lump[f].name,n)) + return(lump[f].lump); + + f++; + } + + return(IGNORE_LUMP); +} + + +static WadDir *GetDir(char *name) +{ + Iterator i; + WadDir *w; + + if (!(i=ListFindElem(waddir,FindDirEnt,name))) + return(NULL); + + w=IteratorData(i); + IteratorClear(i); + + return(w); +} + + +static WadFile *GetWADFile(char *name) +{ + Iterator i; + WadFile *w; + + if (!(i=ListFindElem(wadlist,FindWAD,name))) + return(NULL); + + w=IteratorData(i); + IteratorClear(i); + + return(w); +} + + +static void *LoadDirEnt(WadDir *d,Long *size) +{ + void *ret; + WadFile *wf; + + if (!(wf=GetWADFile(d->wad))) + return(NULL); + + ret=Grab(d->size); + fseek(wf->fp,(long)d->off,SEEK_SET); + fread(ret,1,d->size,wf->fp); + + if (size) + *size=d->size; + + return(ret); +} + + +static WadDirTable *ReadDir(char *wad, char *expect) +{ + char type[4]; + WadDirTable *d; + int f; + FILE *fp; + + if (!(fp=fopen(wad,"rb"))) + ERR(WAD_FILE_NOT_FOUND,NULL); + + fread(type,1,4,fp); + + if (STRNEQ("IWAD",expect)&&(!STRNEQ("IWAD",type))) + ERR(WAD_NOT_IWAD,NULL); + else if (STRNEQ("PWAD",expect)&&(!STRNEQ("PWAD",type))) + ERR(WAD_NOT_PWAD,NULL); + + d=Grab(sizeof(WadDirTable)); + d->no=GetLong(fp); + + d->ent=Grab(sizeof(WadEnt)*d->no); + + fseek(fp,(long)GetLong(fp),SEEK_SET); + + for(f=0;fno;f++) + { + d->ent[f].off=GetLong(fp); + d->ent[f].size=GetLong(fp); + strcpy(d->ent[f].name,GetName(fp)); + } + + return(d); +} + + +static int AddWAD(char *wad,char *type) +{ + Iterator i; + WadDirTable *d; + WadDir w; + int f; + char *wadname; + WadFile *wf; + int check; + int e2m1; + int map01; + + /* Read in the directory from the WAD + */ + if (!waddir) + { + waddir=ListNew(sizeof(WadDir)); + wadlist=ListNew(sizeof(WadFile)); + } + + if (!(d=ReadDir(wad,type))) + return(wad_err); + + /* Find the WAD name in the WAD list + */ + if ((i=ListFindElem(wadlist,FindWAD,wad))) + { + wadname=((WadFile *)IteratorData(i))->path; + IteratorClear(i); + } + else + { + wf=Grab(sizeof(WadFile)); + + if (!(wf->fp=fopen(wad,"rb"))) + GFX_exit(EXIT_FAILURE,"BIZARRE: WAD opening failed after " + "first open succeeded on\nt%s\n",wad); + + strcpy(wf->path,wad); + wadname=wf->path; + ListInsert(wadlist,wf); + } + + /* Add the directory entries to the global dir + */ + e2m1=FALSE; + map01=FALSE; + check=STRNEQ("IWAD",type); + + for(f=d->no-1;f>=0;f--) + { + w.wad=wadname; + w.off=d->ent[f].off; + w.size=d->ent[f].size; + strcpy(w.name,d->ent[f].name); + + if (check) + { + if (STREQ("E2M1",d->ent[f].name)) + e2m1=TRUE; + + if (STREQ("MAP01",d->ent[f].name)) + map01=TRUE; + } + + ListInsert(waddir,&w); + } + + /* Shareware checks fo IWAD files + */ + if (check) + switch(level_style) + { + case DOOM_LEVELS: + case ULTIMATE_DOOM_LEVELS: + if (e2m1) + break; + case DOOM_2_LEVELS: + if (map01) + break; + default: + GFX_exit(EXIT_FAILURE, + "You MUST have an IWAD from the registered " + "version of\nDOOM, ULTIMATE DOOM, DOOM II " + "or FINAL DOOM\n"); + break; + } + + Release(d->ent); + Release(d); + + ERR(WAD_OK,WAD_OK); +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +int AddIWAD(char *wad) +{ + return (AddWAD(wad,"IWAD")); +} + + +int AddPWAD(char *wad) +{ + return (AddWAD(wad,"PWAD")); +} + + +int CloseWad(char *wad) +{ + WadDir *w; + Iterator i; + + if (!(i=ListFindElem(wadlist,FindWAD,wad))) + ERR(WAD_FILE_NOT_FOUND,WAD_FILE_NOT_FOUND); + + i=IteratorDelete(i); + IteratorClear(i); + + i=ListIterator(waddir); + + while(i) + { + w=IteratorData(i); + + if (strcmp(w->wad,wad)==0) + i=IteratorDelete(i); + else + i=IteratorNext(i); + } + + IteratorClear(i); + + ERR(WAD_OK,WAD_OK); +} + + +char *OpenWads(void) +{ + Iterator i; + WadFile *w; + char *ret; + + if (!(i=ListIterator(wadlist))) + ret=Strdup(""); + else + { + w=IteratorData(i); + ret=Grab(PATH_MAX+1); + strcpy(ret,w->path); + i=IteratorNext(i); + + while(i) + { + strcat(ret,"|"); + w=IteratorData(i); + ret=ReGrab(ret,strlen(ret)+PATH_MAX+1); + strcat(ret,w->path); + i=IteratorNext(i); + } + } + + return(ret); +} + + +Iterator GetWadDir(void) +{ + return(ListIterator(waddir)); +} + + +int GetWadDirSize(void) +{ + return(ListSize(waddir)); +} + + +void *GetLump(char *name, Long *size) +{ + WadDir *d; + void *ret; + + if (size) + *size=0; + + if (!(d=GetDir(name))) + ERR(WAD_LUMP_NOT_FOUND,NULL); + + if ((ret=LoadDirEnt(d,size))) + ERR(WAD_OK,ret); + else + ERR(WAD_FILE_NOT_FOUND,NULL); +} + + +WadMap *LoadMap(char *name) +{ + Iterator i; + WadMap *map; + WadDir *dir; + WadFile *wf; + Thing thing; + Vertex vertex; + Sidedef sidedef; + Linedef linedef; + Sector sector; + int f; + + if (!(i=ListFindElem(waddir,FindDirEnt,name))) + ERR(WAD_MAP_NOT_FOUND,NULL); + + dir=IteratorData(i); + if (!(wf=GetWADFile(dir->wad))) + ERR(WAD_FILE_NOT_FOUND,NULL); + + map=Grab(sizeof(WadMap)); + map->thing=MapNew(sizeof(Thing)); + map->vertex=MapNew(sizeof(Vertex)); + map->sidedef=MapNew(sizeof(Sidedef)); + map->linedef=MapNew(sizeof(Linedef)); + map->sector=MapNew(sizeof(Sector)); + + /* Step through the items following the map in the dir to load the + lumps for the level in. + */ + while(TRUE) + { + i=IteratorNext(i); + dir=IteratorData(i); + + if (!IsMapLump(dir->name)) + ERR(WAD_OK,map); + + switch (HandledMapLump(dir->name)) + { + case THING_LUMP: + fseek(wf->fp,(long)dir->off,SEEK_SET); + + for(f=0;fsize/THING_SIZE;f++) + { + thing.x=GetShort(wf->fp); + thing.y=GetShort(wf->fp); + thing.ang=GetShort(wf->fp); + thing.type=GetShort(wf->fp); + thing.opt=GetShort(wf->fp); + + MapAdd(map->thing,f,&thing); + } + break; + + case VERTEX_LUMP: + fseek(wf->fp,(long)dir->off,SEEK_SET); + + for(f=0;fsize/VERTEX_SIZE;f++) + { + vertex.x=GetShort(wf->fp); + vertex.y=GetShort(wf->fp); + MapAdd(map->vertex,f,&vertex); + } + break; + + case SIDEDEF_LUMP: + fseek(wf->fp,(long)dir->off,SEEK_SET); + + for(f=0;fsize/SIDEDEF_SIZE;f++) + { + sidedef.x=GetShort(wf->fp); + sidedef.y=GetShort(wf->fp); + strcpy(sidedef.upper,GetName(wf->fp)); + strcpy(sidedef.lower,GetName(wf->fp)); + strcpy(sidedef.middle,GetName(wf->fp)); + sidedef.sector=GetShort(wf->fp); + MapAdd(map->sidedef,f,&sidedef); + } + break; + + case LINEDEF_LUMP: + fseek(wf->fp,(long)dir->off,SEEK_SET); + + for(f=0;fsize/LINEDEF_SIZE;f++) + { + linedef.from=GetShort(wf->fp); + linedef.to=GetShort(wf->fp); + linedef.flags=GetShort(wf->fp); + linedef.type=GetShort(wf->fp); + linedef.tag=GetShort(wf->fp); + linedef.right=GetShort(wf->fp); + linedef.left=GetShort(wf->fp); + MapAdd(map->linedef,f,&linedef); + } + break; + + case SECTOR_LUMP: + fseek(wf->fp,(long)dir->off,SEEK_SET); + + for(f=0;fsize/SECTOR_SIZE;f++) + { + sector.floor=GetShort(wf->fp); + sector.ceiling=GetShort(wf->fp); + strcpy(sector.floor_t,GetName(wf->fp)); + strcpy(sector.ceiling_t,GetName(wf->fp)); + sector.light=GetShort(wf->fp); + sector.special=GetShort(wf->fp); + sector.tag=GetShort(wf->fp); + MapAdd(map->sector,f,§or); + } + break; + + default: + break; + } + } + + ERR(WAD_OK,map); +} + + +WadMap *NewMap(void) +{ + WadMap *map; + + map=Grab(sizeof(WadMap)); + map->thing=MapNew(sizeof(Thing)); + map->vertex=MapNew(sizeof(Vertex)); + map->sidedef=MapNew(sizeof(Sidedef)); + map->linedef=MapNew(sizeof(Linedef)); + map->sector=MapNew(sizeof(Sector)); + + return(map); +} + + +WadMap *ClearMap(WadMap *map) +{ + MapClear(map->thing); + MapClear(map->vertex); + MapClear(map->sidedef); + MapClear(map->linedef); + MapClear(map->sector); + Release(map); + return(NULL); +} + + +int SaveMap(WadMap *map, char *name, char *wad) +{ + FILE *fp; + Long off; + int f; + + if (!(fp=fopen(wad,"wb"))) + ERR(WAD_COULD_NOT_CREATE,WAD_COULD_NOT_CREATE); + + off=MapSize(map->vertex)*VERTEX_SIZE+ + MapSize(map->sidedef)*SIDEDEF_SIZE+ + MapSize(map->linedef)*LINEDEF_SIZE+ + MapSize(map->sector)*SECTOR_SIZE+ + MapSize(map->thing)*THING_SIZE+12; + + /* Put PWAD header + */ + fputs("PWAD",fp); + PutLong(fp,10); + PutLong(fp,off); + + /* Put THINGS + */ + for(f=0;fthing);f++) + { + Thing *t; + + t=MapElem(map->thing,f); + PutShort(fp,t->x); + PutShort(fp,t->y); + PutShort(fp,t->ang); + PutShort(fp,t->type); + PutShort(fp,t->opt); + } + + /* Put LINEDEFS + */ + for(f=0;flinedef);f++) + { + Linedef *l; + + l=MapElem(map->linedef,f); + PutShort(fp,l->from); + PutShort(fp,l->to); + PutShort(fp,l->flags); + PutShort(fp,l->type); + PutShort(fp,l->tag); + PutShort(fp,l->right); + PutShort(fp,l->left); + } + + /* Put SIDEDEFS + */ + for(f=0;fsidedef);f++) + { + Sidedef *s; + + s=MapElem(map->sidedef,f); + PutShort(fp,s->x); + PutShort(fp,s->y); + PutName(fp,s->upper); + PutName(fp,s->lower); + PutName(fp,s->middle); + PutShort(fp,s->sector); + } + + /* Put VERTEXES + */ + for(f=0;fvertex);f++) + { + Vertex *v; + + v=MapElem(map->vertex,f); + PutShort(fp,v->x); + PutShort(fp,v->y); + } + + /* Skip SEGS, SSECTORS, NODE + */ + + /* Put SECTORS + */ + for(f=0;fsector);f++) + { + Sector *s; + + s=MapElem(map->sector,f); + PutShort(fp,s->floor); + PutShort(fp,s->ceiling); + PutName(fp,s->floor_t); + PutName(fp,s->ceiling_t); + PutShort(fp,s->light); + PutShort(fp,s->special); + PutShort(fp,s->tag); + } + + /* Skip REJECT, BLOCKMAP + */ + + /* Create directory + */ + off=12; + + PutDirEnt(fp,off,0,name); + + PutDirEnt(fp,off,MapSize(map->thing)*THING_SIZE,"THINGS"); + off+=MapSize(map->thing)*THING_SIZE; + + PutDirEnt(fp,off,MapSize(map->linedef)*LINEDEF_SIZE,"LINEDEFS"); + off+=MapSize(map->linedef)*LINEDEF_SIZE; + + PutDirEnt(fp,off,MapSize(map->sidedef)*SIDEDEF_SIZE,"SIDEDEFS"); + off+=MapSize(map->sidedef)*SIDEDEF_SIZE; + + PutDirEnt(fp,off,MapSize(map->vertex)*VERTEX_SIZE,"VERTEXES"); + off+=MapSize(map->vertex)*VERTEX_SIZE; + + PutDirEnt(fp,off,0,"SEGS"); + PutDirEnt(fp,off,0,"SSECTORS"); + PutDirEnt(fp,off,0,"NODES"); + + PutDirEnt(fp,off,MapSize(map->sector)*SECTOR_SIZE,"SECTORS"); + off+=MapSize(map->sector)*SECTOR_SIZE; + + PutDirEnt(fp,off,0,"REJECT"); + PutDirEnt(fp,off,0,"BLOCKMAP"); + + fclose(fp); + + ERR(WAD_OK,WAD_OK); +} + + +int WadError(void) +{ + return(wad_err); +} + + +const char *WadErrorString(void) +{ + return(wad_errstr[wad_err]); +} + +/* END OF FILE */ diff --git a/wad.h b/wad.h new file mode 100644 index 0000000..7d9a9f5 --- /dev/null +++ b/wad.h @@ -0,0 +1,242 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + WAD file definitions and readers + + These things should be noted about the handling of mutiple entries + from different wad files: + + - Entries in later WADs overwrite earlier loaded WADs. + + - New entries for MAPxy and ExMy automatically overwrite the + following entries from the previous map: + THINGS + LINEDEFS + SIDEDEFS + VERTEXES + SEGS + SSECTORS + NODES + SECTORS + REJECT + BLOCKMAP + + If these entries don't appear in the new map they are + replaced by dummy entries of zero length. + + $Id$ + +*/ + +#ifndef _WAD_H + +#define _WAD_H + +#include "map.h" +#include "list.h" + +/* Basic WAD types +*/ +#define DIRNAME_LEN 8 +typedef char DirName[DIRNAME_LEN+1]; + +/* Directory types +*/ +typedef struct WadDir + { + char *wad; /* WAD the entry is from */ + DirName name; /* Lump name */ + Long off; /* Lump offset */ + Long size; /* Lump size */ + } WadDir; + + +/* Base level types and their sizes in the WAD +*/ +#define THING_SIZE (sizeof(Short)*5) + +typedef struct Thing + { + Short x; + Short y; + Short ang; + Short type; + Short opt; + } Thing; + +#define VERTEX_SIZE (sizeof(Short)*2) + +typedef struct Vertex + { + Short x; + Short y; + } Vertex; + +#define SIDEDEF_SIZE (sizeof(Short)*3+DIRNAME_LEN*3) + +typedef struct Sidedef + { + Short x; + Short y; + DirName upper; + DirName lower; + DirName middle; + Short sector; + } Sidedef; + +#define LINEDEF_SIZE (sizeof(Short)*7) + +typedef struct + { + Short from; + Short to; + Short flags; + Short type; + Short tag; + Short right; + Short left; + } Linedef; + +#define SECTOR_SIZE (sizeof(Short)*5+DIRNAME_LEN*2) + +typedef struct Sector + { + Short floor; + Short ceiling; + DirName floor_t; + DirName ceiling_t; + Short light; + Short special; + Short tag; + } Sector; + +typedef struct WadMap + { + Map thing; + Map vertex; + Map linedef; + Map sidedef; + Map sector; + } WadMap; + + +/* Error codes +*/ +#define WAD_OK 0 +#define WAD_FILE_NOT_FOUND 1 +#define WAD_NOT_WAD 2 +#define WAD_NOT_IWAD 3 +#define WAD_NOT_PWAD 4 +#define WAD_MAP_NOT_FOUND 5 +#define WAD_LUMP_NOT_FOUND 6 +#define WAD_COULD_NOT_CREATE 7 +#define WAD_BROKEN 8 /* Must be last error code */ + +#define WAD_NOERROR (WAD_BROKEN+1) + + +/* Add the named IWAD to the list of open WADs. Returns non-zero on error. +*/ +int AddIWAD(char *wad); + + +/* Add the named PWAD to the list of open WADs. Returns non-zero on error. + AddPWAD() and AddIWAD() are by and large identical - they just include + different checking so that the initial loading of IWAD will not allow it + be a PWAD, and also do shareware checking. +*/ +int AddPWAD(char *wad); + + +/* Close a wad from the open list. Removes entries for this wad fom the + global directory, replacing entries from prevous WADs (if any). + + Returns non-zero on error. +*/ +int CloseWad(char *wad); + + +/* Returns a list of open WADS as a string like "||..". The return + must be Release()ed after use. +*/ +char *OpenWads(void); + + +/* If you wish access to the directory of all the open wads, this allows + them to retrieved as a List of WadDir. Returns NULL if none. + + Note the directory is organised with the last loaded WAD files first. + This is the quickest (though hungriest) method for ensuring that later + WAD resources override earlier ones. +*/ +Iterator GetWadDir(void); + +/* No of entries in WadDir list +*/ +int GetWadDirSize(void); + + +/* Retrieves the named lump from the WADs. Return is a pointer to size + bytes. If size is NULL it is not set. + + The pointer must be Release()'ed by the user afterwards. + + NULL indicates the lump could not be found. +*/ +void *GetLump(char *name, Long *size); + + +/* Load a MAPxx or ExMy map from the open wads. Returns NULL on error. +*/ +WadMap *LoadMap(char *name); + + +/* Create a new empty map +*/ +WadMap *NewMap(void); + + +/* Release the memory for a WadMap +*/ +WadMap *ClearMap(WadMap *map); + + +/* Save the passed WadMap as a MAPxx or ExMy PWAD. Note that this PWAD is + overwritten and the map is the sole object written to the PWAD. Returns + non-zero on error. +*/ +int SaveMap(WadMap *map, char *name, char *wad); + + +/* Return the current error code +*/ +int WadError(void); + + +/* Return a string for the error code +*/ +const char *WadErrorString(void); + + +#endif + +/* END OF FILE */ diff --git a/waddir.c b/waddir.c new file mode 100644 index 0000000..d7bf4ae --- /dev/null +++ b/waddir.c @@ -0,0 +1,75 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program is distributed in the hope that 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Tester for routines in wad.c + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include + +#include "wad.h" +#include "gfx.h" +#include "mem.h" +#include "file.h" + +#define SCRW 640 +#define SCRH 480 + + +/* ---------------------------------------- MAIN +*/ +int viDOOM(int argc,char *argv[]) +{ + Iterator i; + + if (argc<2) + GFX_exit(1,"usage:%s wad\n",argv[0]); + + LoadGlobals(); + + if (AddIWAD(argv[1])!=WAD_OK) + if (AddPWAD(argv[1])!=WAD_OK) + GFX_exit(1,"wadderr=%s\n",WadErrorString()); + + i=GetWadDir(); + + while(i) + { + WadDir *w; + + w=IteratorData(i); + + printf("%-10s 0x%.8x 0x%.8x %s\n", + w->name,w->off,w->size,Basename(w->wad)); + + i=IteratorNext(i); + } + + return(0); +} + + +/* END OF FILE */ -- cgit v1.2.3