From a9022b5972dc49d86f617a27940fafe9c4d0e7e7 Mon Sep 17 00:00:00 2001 From: Ian C Date: Thu, 9 Jun 2011 13:46:28 +0000 Subject: Initial import of (very old) vidoom sources. --- LICENSE | 341 ++++ Makefile | 334 ++++ README | 29 + base.ini | 154 ++ config.h | 109 ++ debug.c | 231 +++ debug.h | 66 + djgpp/file.c | 118 ++ djgpp/gfx.c | 559 +++++++ djgpp/install | 31 + djgpp/install.c | 119 ++ djgpp/main.c | 34 + djgpp/mem.c | 262 +++ djgpp/platgui.c | 4235 +++++++++++++++++++++++++++++++++++++++++++++++++ djgpp/runcmd.c | 143 ++ djgpp/vstring.c | 48 + doc/bugs.htm | 40 + doc/building.htm | 88 + doc/changelog.htm | 64 + doc/djgpp.htm | 58 + doc/ed_ex1.gif | Bin 0 -> 530 bytes doc/ed_ex2.gif | Bin 0 -> 596 bytes doc/ed_ex3.gif | Bin 0 -> 702 bytes doc/ed_l_hex.gif | Bin 0 -> 2499 bytes doc/ed_line.gif | Bin 0 -> 15339 bytes doc/ed_lninf.gif | Bin 0 -> 2275 bytes doc/ed_merge.gif | Bin 0 -> 19280 bytes doc/ed_multi.gif | Bin 0 -> 19790 bytes doc/ed_sect.gif | Bin 0 -> 17537 bytes doc/ed_step.gif | Bin 0 -> 15527 bytes doc/ed_t_hx1.gif | Bin 0 -> 2383 bytes doc/ed_t_hx2.gif | Bin 0 -> 2177 bytes doc/ed_thing.gif | Bin 0 -> 17621 bytes doc/ed_vert.gif | Bin 0 -> 13192 bytes doc/editing.htm | 1603 +++++++++++++++++++ doc/glossary.htm | 152 ++ doc/index.htm | 45 + doc/license.htm | 360 +++++ doc/mainmenu.htm | 177 +++ doc/overview.htm | 1164 ++++++++++++++ doc/porting.htm | 1452 +++++++++++++++++ doc/sys.htm | 24 + doc/thanks.htm | 91 ++ doom.cfg | 571 +++++++ doom2.cfg | 77 + edit.c | 751 +++++++++ edit.h | 70 + edit3d.c | 474 ++++++ editcord.c | 225 +++ editcrse.c | 397 +++++ editdraw.c | 349 ++++ editevnt.c | 1079 +++++++++++++ editgui.c | 519 ++++++ editilst.c | 106 ++ editline.c | 3812 ++++++++++++++++++++++++++++++++++++++++++++ editlump.c | 330 ++++ editmrg.c | 564 +++++++ editmult.c | 708 +++++++++ editsect.c | 1735 ++++++++++++++++++++ editsel.c | 133 ++ editsrot.c | 76 + editthng.c | 1126 +++++++++++++ editvar.c | 492 ++++++ editvar.h | 701 ++++++++ editvert.c | 834 ++++++++++ file.h | 58 + flags.c | 203 +++ flags.h | 66 + gdb.ini | 1 + genlines.c | 460 ++++++ genlines.h | 86 + gensect.c | 423 +++++ gensect.h | 80 + gfx.h | 319 ++++ gfxtest.c | 862 ++++++++++ globals.c | 1375 ++++++++++++++++ globals.h | 232 +++ gui.c | 337 ++++ gui.h | 84 + ini.c | 532 +++++++ ini.h | 106 ++ linedefs.c | 316 ++++ linedefs.h | 84 + linux/file.c | 103 ++ linux/gfx.c | 1013 ++++++++++++ linux/main.c | 33 + linux/mem.c | 107 ++ linux/platgui.c | 3703 ++++++++++++++++++++++++++++++++++++++++++ linux/runcmd.c | 82 + linux/vstring.c | 48 + list.c | 288 ++++ list.h | 104 ++ make/cygwin-xfree.cfg | 41 + make/djgpp.cfg | 41 + make/linux.cfg | 41 + map.c | 162 ++ map.h | 86 + mem.h | 79 + names.c | 256 +++ names.h | 43 + platgui.h | 258 +++ runcmd.h | 57 + sectors.c | 319 ++++ sectors.h | 95 ++ specials.c | 319 ++++ specials.h | 74 + texture.c | 592 +++++++ texture.h | 69 + things.c | 288 ++++ things.h | 72 + todo | 4 + util.c | 253 +++ util.h | 132 ++ vidoom.c | 892 +++++++++++ vidoom.h | 44 + vidoom.ini | 186 +++ vstring.h | 48 + wad.c | 1144 +++++++++++++ wad.h | 294 ++++ waddir.c | 76 + wadtest | Bin 0 -> 703835 bytes wadtest.c | 79 + zdoom.cfg | 719 +++++++++ 123 files changed, 45128 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile 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/changelog.htm create mode 100644 doc/djgpp.htm create mode 100755 doc/ed_ex1.gif create mode 100755 doc/ed_ex2.gif create mode 100755 doc/ed_ex3.gif create mode 100755 doc/ed_l_hex.gif create mode 100755 doc/ed_line.gif create mode 100755 doc/ed_lninf.gif create mode 100755 doc/ed_merge.gif create mode 100755 doc/ed_multi.gif create mode 100755 doc/ed_sect.gif create mode 100755 doc/ed_step.gif create mode 100755 doc/ed_t_hx1.gif create mode 100755 doc/ed_t_hx2.gif create mode 100755 doc/ed_thing.gif create mode 100755 doc/ed_vert.gif create mode 100755 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/sys.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 edit3d.c 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 editlump.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 flags.c create mode 100644 flags.h create mode 100644 gdb.ini create mode 100644 genlines.c create mode 100644 genlines.h create mode 100644 gensect.c create mode 100644 gensect.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 linux/file.c create mode 100644 linux/gfx.c create mode 100644 linux/main.c create mode 100644 linux/mem.c create mode 100644 linux/platgui.c create mode 100644 linux/runcmd.c create mode 100644 linux/vstring.c create mode 100644 list.c create mode 100644 list.h create mode 100644 make/cygwin-xfree.cfg create mode 100644 make/djgpp.cfg create mode 100644 make/linux.cfg create mode 100644 map.c create mode 100644 map.h create mode 100644 mem.h create mode 100644 names.c create mode 100644 names.h create mode 100644 platgui.h create mode 100644 runcmd.h create mode 100644 sectors.c create mode 100644 sectors.h create mode 100644 specials.c create mode 100644 specials.h create mode 100644 texture.c create mode 100644 texture.h create mode 100644 things.c create mode 100644 things.h create mode 100644 todo create mode 100644 util.c create mode 100644 util.h create mode 100644 vidoom.c create mode 100644 vidoom.h create mode 100644 vidoom.ini create mode 100644 vstring.h create mode 100644 wad.c create mode 100644 wad.h create mode 100644 waddir.c create mode 100755 wadtest create mode 100644 wadtest.c create mode 100644 zdoom.cfg 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/Makefile b/Makefile new file mode 100644 index 0000000..c048fe1 --- /dev/null +++ b/Makefile @@ -0,0 +1,334 @@ +# 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 (Currently unmaintained) +# linux +# cygwin-xfree (Same as linux) +# +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)VIDOOM_DEBUG + + +CFLAGS= $(INCFLAG). $(EXTRACF) $(DEFINEFLAG)TRACEFORM='$(TRACEFORM)' \ + $(DEBUG) $(DEFINEFLAG)PLATFORM=$(PLATFORM) \ + $(DEFINEFLAG)DIRSEP='$(DIRSEP)' + +VIDOOM= vidoom +WADDIR= waddir +GFXTEST= gfxtest +WADTEST= wadtest + +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) util$(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) \ + edit3d$(OBJ_EXT) genlines$(OBJ_EXT) gensect$(OBJ_EXT) \ + names$(OBJ_EXT) editlump$(OBJ_EXT) specials$(OBJ_EXT) \ + flags$(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 genlines.h gensect.h \ + names.h specials.h flags.h + +VIDOOM_OBJ= vidoom$(OBJ_EXT) $(COMMON_OBJ) +WADDIR_OBJ= waddir$(OBJ_EXT) $(COMMON_OBJ) +GFXTEST_OBJ= gfxtest$(OBJ_EXT) $(COMMON_OBJ) +WADTEST_OBJ= $(WADTEST)$(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) + +$(WADTEST)$(EXE_EXT):$(WADTEST_OBJ) + $(LD) $(EXTRALF) $(EXEFLAG) $(WADTEST)$(EXE_EXT) $(WADTEST_OBJ) \ + $(LIBS) $(MATHLIB) + + +all: $(VIDOOM)$(EXE_EXT) $(WADDIR)$(EXE_EXT) \ + $(GFXTEST)$(EXE_EXT) $(WADTEST)$(EXE_EXT) + + +$(PLATFORM)$(MKDS)main$(OBJ_EXT): $(PLATFORM)$(MKDS)main.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(INCFLAG).. $(CFLAGS) $(OBJFLAG) main.c ; cd .. + +$(PLATFORM)$(MKDS)file$(OBJ_EXT): $(PLATFORM)$(MKDS)file.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(INCFLAG).. $(CFLAGS) $(OBJFLAG) file.c ; cd .. + +$(PLATFORM)$(MKDS)gfx$(OBJ_EXT): $(PLATFORM)$(MKDS)gfx.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(INCFLAG).. $(CFLAGS) $(OBJFLAG) gfx.c ; cd .. + +$(PLATFORM)$(MKDS)mem$(OBJ_EXT): $(PLATFORM)$(MKDS)mem.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(INCFLAG).. $(CFLAGS) $(OBJFLAG) mem.c ; cd .. + +$(PLATFORM)$(MKDS)platgui$(OBJ_EXT): $(PLATFORM)$(MKDS)platgui.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(INCFLAG).. $(CFLAGS) $(OBJFLAG) platgui.c ; cd .. + +$(PLATFORM)$(MKDS)runcmd$(OBJ_EXT): $(PLATFORM)$(MKDS)runcmd.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(INCFLAG).. $(CFLAGS) $(OBJFLAG) runcmd.c ; cd .. + +$(PLATFORM)$(MKDS)vstring$(OBJ_EXT): $(PLATFORM)$(MKDS)vstring.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(INCFLAG).. $(CFLAGS) $(OBJFLAG) vstring.c ; cd .. + + +debug$(OBJ_EXT): debug.c config.h debug.h vstring.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +edit$(OBJ_EXT): edit.c config.h debug.h vstring.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) $< + +edit3d$(OBJ_EXT): edit3d.c config.h debug.h vstring.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) $< + +editcord$(OBJ_EXT): editcord.c config.h debug.h vstring.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) $< + +editcrse$(OBJ_EXT): editcrse.c config.h debug.h vstring.h globals.h editvar.h \ + things.h gfx.h platgui.h linedefs.h wad.h map.h list.h \ + gui.h mem.h sectors.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editdraw$(OBJ_EXT): editdraw.c config.h debug.h vstring.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 debug.h vstring.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 debug.h vstring.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 sectors.h specials.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editilst$(OBJ_EXT): editilst.c config.h debug.h vstring.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) $< + +editline$(OBJ_EXT): editline.c config.h debug.h vstring.h globals.h editvar.h \ + things.h gfx.h platgui.h linedefs.h wad.h map.h list.h \ + gui.h mem.h sectors.h texture.h genlines.h specials.h \ + flags.h util.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editlump$(OBJ_EXT): editlump.c config.h debug.h vstring.h globals.h editvar.h \ + things.h gfx.h platgui.h linedefs.h wad.h map.h list.h \ + gui.h mem.h runcmd.h file.h util.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editmrg$(OBJ_EXT): editmrg.c config.h debug.h vstring.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 debug.h vstring.h globals.h util.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 debug.h vstring.h globals.h sectors.h \ + wad.h map.h list.h gfx.h platgui.h editvar.h things.h \ + linedefs.h gui.h mem.h gensect.h util.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editsel$(OBJ_EXT): editsel.c config.h debug.h vstring.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 debug.h vstring.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 debug.h vstring.h globals.h specials.h \ + flags.h util.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 debug.h vstring.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 debug.h vstring.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) $< + +flags$(OBJ_EXT): flags.c config.h debug.h vstring.h globals.h platgui.h gfx.h \ + flags.h mem.h list.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +genlines$(OBJ_EXT): genlines.c config.h debug.h vstring.h globals.h platgui.h \ + gfx.h genlines.h mem.h map.h linedefs.h wad.h list.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +gensect$(OBJ_EXT): gensect.c config.h debug.h vstring.h globals.h platgui.h \ + gfx.h gensect.h mem.h map.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +globals$(OBJ_EXT): globals.c config.h debug.h vstring.h globals.h ini.h gfx.h \ + mem.h texture.h platgui.h things.h linedefs.h wad.h map.h \ + list.h sectors.h genlines.h gensect.h specials.h flags.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +gui$(OBJ_EXT): gui.c config.h debug.h vstring.h globals.h gui.h gfx.h \ + platgui.h mem.h ini.h names.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +ini$(OBJ_EXT): ini.c config.h debug.h vstring.h ini.h mem.h file.h gfx.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +linedefs$(OBJ_EXT): linedefs.c config.h debug.h vstring.h globals.h platgui.h \ + gfx.h linedefs.h wad.h map.h list.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +list$(OBJ_EXT): list.c config.h debug.h vstring.h list.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +map$(OBJ_EXT): map.c config.h debug.h vstring.h map.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +names$(OBJ_EXT): names.c config.h debug.h vstring.h names.h globals.h file.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +sectors$(OBJ_EXT): sectors.c config.h debug.h vstring.h globals.h sectors.h \ + wad.h map.h list.h gfx.h platgui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +specials$(OBJ_EXT): specials.c config.h debug.h vstring.h globals.h platgui.h \ + gfx.h gui.h specials.h mem.h list.h map.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +texture$(OBJ_EXT): texture.c config.h debug.h vstring.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 debug.h vstring.h globals.h platgui.h \ + gfx.h things.h mem.h list.h map.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +util$(OBJ_EXT): util.c config.h debug.h vstring.h mem.h util.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +wad$(OBJ_EXT): wad.c config.h debug.h vstring.h globals.h wad.h map.h list.h \ + gfx.h mem.h file.h util.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 + +$(GFXTEST)(OBJ_EXT): $(GFXTEST).c $(ALL_HEADERS) + $(CC) $(CFLAGS) $(OBJFLAG) $(GFXTEST).c + +$(WADTEST)(OBJ_EXT): $(WADTEST).c $(ALL_HEADERS) + $(CC) $(CFLAGS) $(OBJFLAG) $(WADTEST).c + + +# Rule for installation +# +install: $(VIDOOM)$(EXE_EXT) FORCE + cd $(PLATFORM) ; $(MAKEINSTALL) + +FORCE: + +# Rule for cleaning up +# +clean: + $(RMCMD) $(COMMON_OBJ) + $(RMCMD) vidoom$(OBJ_EXT) + $(RMCMD) waddir$(OBJ_EXT) + $(RMCMD) gfxtest$(OBJ_EXT) + $(RMCMD) vidoom$(EXE_EXT) + $(RMCMD) waddir$(EXE_EXT) + $(RMCMD) gfxtest$(EXE_EXT) + +# +# $Id: Makefile,v 1.48 2002/09/05 20:00:47 ianc Exp ianc $ +# +# END OF FILE diff --git a/README b/README new file mode 100644 index 0000000..af04e60 --- /dev/null +++ b/README @@ -0,0 +1,29 @@ + viDOOM v0.03 + + +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'. + +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.5 2000/09/24 22:50:28 dosuser Exp dosuser $ diff --git a/base.ini b/base.ini new file mode 100644 index 0000000..1cabe0f --- /dev/null +++ b/base.ini @@ -0,0 +1,154 @@ +# 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.43 2002/06/08 22:29:05 ianc Exp ianc $ +# + +[Game] +game=doom +ask=yes + +[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 +left_click_move=yes +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] +auto_loadmap=MAP01,E1M1 +initial_empty_map=no +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 + +[ACS] +always_view_output=yes +command=acc.exe +dir=c:\acc +script=vidoom.acs +object=vidoom.o +args=%S %O + + +[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 +mapinfo_lump=yes +create_hexen=ask +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + + +# Platform dependent info +# +[linux] +edit= diff --git a/config.h b/config.h new file mode 100644 index 0000000..c1c4669 --- /dev/null +++ b/config.h @@ -0,0 +1,109 @@ +/* + + 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 VIDOOM_CONFIG_H + +#define VIDOOM_CONFIG_H + +/* Usual constants +*/ +#include +#include +#include + + +/* Global viDOOM includes +*/ +#include "debug.h" +#include "vstring.h" + + +/* Version +*/ +#define VIDOOMVER "0.03" +#define VIDOOMRELEASE "(Unsupported development version)" + + +/* Basic, global machine types +*/ +typedef unsigned char Byte; +typedef unsigned short Word; +typedef unsigned short UShort; +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..e318482 --- /dev/null +++ b/debug.c @@ -0,0 +1,231 @@ +/* + + 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" + +/* Set this true if you want to use stderr for debug output +*/ +static int use_stderr=TRUE; + +static FILE *trace_fp=NULL; + +void VIDOOM_Debug(char *fmt,...) +{ + static char last[512]=""; + static char this[512]=""; + static int rep=0; + int f; + va_list va; + + if (!trace_fp) + { + if (use_stderr) + trace_fp=stderr; + else + { + 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..1fe51ab --- /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 VIDOOM_DEBUG_H + +#define VIDOOM_DEBUG_H + +#include + +#ifdef VIDOOM_DEBUG +# define Debug(x) VIDOOM_Debug x +#else +# define Debug(x) +#endif + +/* Macro for function tracing. Use as: + void func(void) + { + int a; + + VIDOOM_TRACE; + ... + } +*/ +#define VIDOOM_TRACE VIDOOM_Trace(TRACEFORM) + +void VIDOOM_Debug(char *fmt,...); +void VIDOOM_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..5f5d49f --- /dev/null +++ b/djgpp/file.c @@ -0,0 +1,118 @@ +/* + + 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); + + 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) +{ + return(__file_exists(path)); +} + +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..b93f6ea --- /dev/null +++ b/djgpp/gfx.c @@ -0,0 +1,559 @@ +/* + + 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_SETTEXT(void) +{ + if (set_gfx_mode(GFX_TEXT,80,25,0,0)<0) + GFX_exit(EXIT_FAILURE,"Couldn't open text screen\n"); + + show_mouse(NULL); + remove_mouse(); + remove_timer(); + remove_keyboard(); +} + + +void GFX_SETGRAPHICS(void) +{ + if (set_gfx_mode(GFX_AUTODETECT,width,height,0,0)<0) + GFX_exit(EXIT_FAILURE,"Couldn't re-open graphics screen\n"); + + install_keyboard(); + install_timer(); + install_mouse(); + 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..fd7774a --- /dev/null +++ b/djgpp/mem.c @@ -0,0 +1,262 @@ +/* + + 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 "file.h" + +#include "debug.h" + +/* Set MEMSTAT to the following levels : + + 0 - Nodebug information + 1 - Fatal debug information (still allocated block on failure, + general release errors) + 2 - All debug information + + Regardless of the above no debug is generated if DEBUG is not set +*/ +#ifndef DEBUG +#define MEMSTAT 0 +#else +#define MEMSTAT 1 +#endif + +typedef struct memmap + { + char file[64]; + int line; + void *addr; + struct memmap *next; + struct memmap *prev; + } MemMap; + +static MemMap *mmap=NULL; + + +static void DumpMemList(char *p) +{ + MemMap *m; + +# if MEMSTAT == 0 + return; +# endif + + Debug(("**** %s ****\n",p)); + Debug(("Still waiting to be freed:\n")); + + if ((m=mmap)) + while(m) + { + Debug(("\t%p allocated to %s:%d\n",m->addr,m->file,m->line)); + m=m->next; + } + else + Debug(("\tNONE\n")); + +} + + +static void AddMM(char *mode,char *file, int line, void *addr) +{ + MemMap *n; + +# if MEMSTAT == 0 + return; +# endif + + n=malloc(sizeof(MemMap)); + strcpy(n->file,Basename(file)); + n->line=line; + n->addr=addr; + + if (!mmap) + { + mmap=n; + n->next=NULL; + n->prev=NULL; + } + else + { + mmap->prev=n; + n->next=mmap; + n->prev=NULL; + mmap=n; + } + +# if MEMSTAT == 2 + Debug(("%s: Memory %p allocated to %s:%d\n",mode,addr,file,line)); +# endif +} + + +static void RmMM(char *mode, char *file, int line, void *addr) +{ + MemMap *n; + int del; + +# if MEMSTAT == 0 + return; +# endif + + del=0; + n=mmap; + + while(n) + if (n->addr==addr) + { +# if MEMSTAT == 2 + Debug(("%s: Address %p freed by %s:%d\n",mode,addr,file,line)); +# endif + + if (n->prev) + n->prev->next=n->next; + else + mmap=n->next; + + if (n->next) + n->next->prev=n->prev; + + free(n); + n=NULL; + del=1; + } + else + n=n->next; + + if (!del) + Debug(("%s: ***** Address %p not found - freed by %s:%d\n", + mode,addr,file,line)); +} + + +void *FGrab(char *fn, int line, int len) +{ + char *ptr; + + if (len==0) + len=1; + + if (!(ptr=malloc(len))) + { + DumpMemList("GRAB FAILED"); + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Grab(%d)\n",fn,line,len); + } + + memset(ptr,0,len); + + AddMM("Grab",fn,line,ptr); + + return(ptr); +} + + +void *FReGrab(char *fn, int line, void *ptr, int len) +{ + if (len==0) + len=1; + + if (ptr) + RmMM("ReGrab(RELEASE)",fn,line,ptr); + + if (!(ptr=realloc(ptr,len))) + { + DumpMemList("REGRAB FAILED"); + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d ReGrab(%d)\n",fn,line,len); + } + + AddMM("ReGrab(ACQUIRE)",fn,line,ptr); + + return(ptr); +} + + +void FRelease(char *fn, int line, void *p) +{ + RmMM("Release",fn,line,p); + free(p); +} + + +void *FCopy(char *fn, int line, void *p,int len) +{ + void *ptr; + + if (len==0) + ptr=malloc(1); + else + ptr=malloc(len); + + if (!ptr) + { + DumpMemList("COPY FAILED"); + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Copy(%p,%d)\n",fn,line,p,len); + } + + if (len) + memcpy(ptr,p,len); + + AddMM("Copy",fn,line,ptr); + + return(ptr); +} + + +char *FStrdup(char *fn, int line, char *p) +{ + char n_fn[PATH_MAX]; + char *ptr; + + strcpy(n_fn,fn); + strcat(n_fn," [STRDUP]"); + + if (p) + { + if (!(ptr=malloc(strlen(p)+1))) + { + DumpMemList("STRDUP FAILED"); + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Stdup(%s)\n",fn,line,p); + } + + strcpy(ptr,p); + AddMM("Strdup",fn,line,ptr); + return(ptr); + } + else + return(NULL); +} + +/* END OF FILE */ diff --git a/djgpp/platgui.c b/djgpp/platgui.c new file mode 100644 index 0000000..3f50964 --- /dev/null +++ b/djgpp/platgui.c @@ -0,0 +1,4235 @@ +/* + + 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 "file.h" +#include "util.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 + +#define PL_COL 0xb0b0ff /* Col for active picklist */ + +#define BUFF_LEN 1024 + +/* ---------------------------------------- VARS +*/ +static int SCRW,SCRH; +static int FW,FH; + +/* Vars for GUI_yesno_all() +*/ +static int all_pressed=FALSE; +static int all_result=FALSE; + +/* Global picklist data and the picklist dialog +*/ +#define PL_BORDER 0 +#define PL_TITLE 1 +#define PL_PICKLIST 2 +#define PL_OK 3 +#define PL_CANCEL 4 +#define PL_END 5 + +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_OK 5 +#define IPL_CANCEL 6 +#define IPL_END 7 + +static DIALOG img_picklist[IPL_END+1]; +static int img_pick_no; +static PLAT_IMG_PICKLIST + *img_pick_data; + + +/* Global data and the file viewer dialog +*/ +#define FV_BORDER 0 +#define FV_TITLE 1 +#define FV_TEXTBOX 2 +#define FV_TEXT 3 +#define FV_VERT_SCROLL 4 +#define FV_HORIZ_SCROLL 5 +#define FV_OK 6 +#define FV_END 7 + +#define FV_SCROLLWIDTH 10 +#define FV_WIDTH 75 +#define FV_HEIGHT 40 + +static DIALOG fv_dialog[FV_END+1]; + +typedef struct + { + double one; + int size; + int pos; + } ScrollbarData; + + +/* Global data for the text editor dialog +*/ +#define TE_BORDER 0 +#define TE_TITLE 1 +#define TE_TEXTBOX 2 +#define TE_TEXT 3 +#define TE_OK 4 +#define TE_CANCEL 5 +#define TE_END 6 + +#define TE_WIDTH 75 +#define TE_CHUNK 256 +#define TE_HEIGHT 40 + +static DIALOG te_dialog[TE_END+1]; + +typedef struct + { + char t[TE_HEIGHT][TE_WIDTH+1]; + int top; + int x,y; + int col; + int lines; + int start; + } TextEditData; + +typedef struct + { + int len; + char *p; + } TextEditLine; + + +/* Types for the menu +*/ +typedef struct + { + int x; + int y; + int w; + int h; + } BoundBox; + +#define MENU_OK 0 +#define MENU_CANCEL_ESC 1 +#define MENU_CANCEL_CLICK 2 +#define MENU_CHILD_RETURN 3 + +typedef struct + { + int ret; + int mode; + } MenuControl; + + +static int MouseInBox(BoundBox *box,int no); + +/* 'Hidden' interfaces to gfx.c +*/ +extern void GFX_FORCE_REDRAW(void); +extern void GFX_SETTEXT(void); +extern void GFX_SETGRAPHICS(void); + + +/* ---------------------------------------- FILE VEIWER SUPPORT FUNCS +*/ +static char *ConvertFileText(char *p) +{ + static char s[BUFF_LEN+1]; + int f; + + f=0; + + while((*p)&&(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) + { + rectfill(screen,d->x,d->y,d->x+d->w-1,d->y+d->h-1,ACOL(BLACK)); + + if ((bm=d->dp)) + draw_rle_sprite(screen,bm,d->x,d->y); + } + + 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_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=ACOL(WHITE); + 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) + if (d->d1) + 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)); + else + DrawTick(x+SMALL_BEVEL,d->y+SMALL_BEVEL, + d->h-SMALL_BEVEL*2,d->h-SMALL_BEVEL*2); + + return D_O_K; + } + + /* Group zero is done as a check box, not a radio box + */ + if (d->d1) + return d_radio_proc(msg, d, c); + else + return d_button_proc(msg, d, c); +} + + +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_GOTFOCUS) + rect(screen,d->x-1,d->y-1,d->x+d->w,d->y+d->h,ACOL(BLACK)); + else + rect(screen,d->x-1,d->y-1,d->x+d->w,d->y+d->h,ACOL(GUI_MID)); + + 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-FH/2,d->fg,TRUE); + + break; + + default: + return(d_button_proc(msg,d,c)); + break; + } + + return (D_O_K); +} + + +static int d_ro_textbox(int msg, DIALOG *d, int c) +{ + char **p; + int x,y; + int f; + + p=d->dp; + + if(msg==MSG_DRAW) + { + text_mode(-1); + + y=d->d2; + x=d->d1; + + vsync(); + + rectfill(screen,d->x,d->y,d->x+d->w-1,d->y+d->h-1,ACOL(WHITE)); + + for(f=0;(fx) + textprintf(screen,font,d->x,d->y+(f*FH),ACOL(BLACK), + "%-.*s",FV_WIDTH,p[y]+x); + + } + + return (D_O_K); +} + + +static int d_vert_scrollbar(int msg, DIALOG *d, int c) +{ + ScrollbarData *sd; + int *ip; + DIALOG *dp; + int last_y; + + /* Special case for 'zero' length scrollbars - just ignore interactions + and draw a full length scrollbar + */ + if (d->d2==0) + { + if (msg==MSG_DRAW) + { + rect(screen,d->x,d->y,d->x+d->w,d->y+d->h,ACOL(BLACK)); + Rect3D(d->x+1,d->y+1,d->w-1,d->h-1,FALSE,BEVEL); + } + + return(D_O_K); + } + + switch(msg) + { + case MSG_START: + /* Calc box size, etc + */ + sd=Grab(sizeof(*sd)); + d->dp3=sd; + + sd->one=(double)d->h/(double)(d->d2+d->d1); + sd->size=(int)(sd->one*d->d1); + sd->pos=0; + ip=d->dp; + *ip=0; + + break; + + case MSG_END: + Release(d->dp3); + break; + + case MSG_DRAW: + { + BITMAP *pattern; + + sd=d->dp3; + + /* draw frame + */ + rect(screen,d->x,d->y,d->x+d->w,d->y+d->h,ACOL(BLACK)); + + /* create and draw the scrollbar + */ + pattern=create_bitmap(2,2); + + 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)); + + drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0); + rectfill(screen,d->x+1,d->y+1,d->x+d->w-1,d->y+d->h-2,0); + solid_mode(); + Rect3D(d->x+1,d->y+1+sd->pos,d->w-1,sd->size,FALSE,BEVEL); + + destroy_bitmap(pattern); + + break; + } + + case MSG_WANTFOCUS: + return(D_WANTFOCUS); + break; + + case MSG_CLICK: + sd=d->dp3; + ip=d->dp; + dp=d->dp2; + + if (mouse_y<(d->y+sd->pos)) + { + while((mouse_b)&&(mouse_y<(d->y+sd->pos))) + if (*ip) + { + (*ip)--; + + sd->pos=(int)((*ip)*sd->one); + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + SEND_MESSAGE(dp,MSG_DRAW,0); + show_mouse(screen); + } + } + else if (mouse_y>(d->y+sd->pos+sd->size)) + { + while((mouse_b)&&(mouse_y>(d->y+sd->pos+sd->size))) + if ((*ip)d2) + { + (*ip)++; + + sd->pos=(int)((*ip)*sd->one); + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + SEND_MESSAGE(dp,MSG_DRAW,0); + show_mouse(screen); + } + } + else + { + last_y=mouse_y; + + /* I'm sure there's a better way of doing this, but I couldn't + get the sums to work out... + */ + while(mouse_b) + { + int my; + int diff; + int np; + + my=mouse_y; + diff=my-last_y; + np=sd->pos+diff; + + if ((diff<0)&&((*ip)>0)) + { + while((sd->pos>np)&&(*ip)) + { + (*ip)--; + sd->pos=(int)((*ip)*sd->one); + } + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + SEND_MESSAGE(dp,MSG_DRAW,0); + show_mouse(screen); + } + else if ((diff>0)&&((*ip)d2)) + { + while((sd->posd2)) + { + (*ip)++; + sd->pos=(int)((*ip)*sd->one); + } + + if (sd->pos==(d->h-sd->size)) + *ip=d->d2; + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + SEND_MESSAGE(dp,MSG_DRAW,0); + show_mouse(screen); + } + + last_y=my; + } + } + + break; + + default: + break; + } + + return(D_O_K); +} + + +static int d_horiz_scrollbar(int msg, DIALOG *d, int c) +{ + ScrollbarData *sd; + int *ip; + DIALOG *dp; + int last_x; + + /* Special case for 'zero' length scrollbars - just ignore interactions + and draw a full length scrollbar + */ + if (d->d2==0) + { + if (msg==MSG_DRAW) + { + rect(screen,d->x,d->y,d->x+d->w,d->y+d->h,ACOL(BLACK)); + Rect3D(d->x+1,d->y+1,d->w-1,d->h-1,FALSE,BEVEL); + } + + return(D_O_K); + } + + switch(msg) + { + case MSG_START: + /* Calc box size, etc + */ + sd=Grab(sizeof(*sd)); + d->dp3=sd; + + sd->one=(double)d->w/(double)(d->d2+d->d1); + sd->size=(int)(sd->one*d->d1); + sd->pos=0; + ip=d->dp; + *ip=0; + + break; + + case MSG_END: + Release(d->dp3); + break; + + case MSG_DRAW: + { + BITMAP *pattern; + + sd=d->dp3; + + /* draw frame + */ + rect(screen,d->x,d->y,d->x+d->w,d->y+d->h,ACOL(BLACK)); + + /* create and draw the scrollbar + */ + pattern=create_bitmap(2,2); + + 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)); + + drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0); + rectfill(screen,d->x+1,d->y+1,d->x+d->w-1,d->y+d->h-2,0); + solid_mode(); + Rect3D(d->x+1+sd->pos,d->y+1,sd->size,d->h-1,FALSE,BEVEL); + + destroy_bitmap(pattern); + + break; + } + + case MSG_WANTFOCUS: + return(D_WANTFOCUS); + break; + + case MSG_CLICK: + sd=d->dp3; + ip=d->dp; + dp=d->dp2; + + if (mouse_x<(d->x+sd->pos)) + { + while((mouse_b)&&(mouse_x<(d->x+sd->pos))) + if (*ip) + { + (*ip)--; + + sd->pos=(int)((*ip)*sd->one); + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + SEND_MESSAGE(dp,MSG_DRAW,0); + show_mouse(screen); + } + } + else if (mouse_x>(d->x+sd->pos+sd->size)) + { + while((mouse_b)&&(mouse_x>(d->x+sd->pos+sd->size))) + if ((*ip)d2) + { + (*ip)++; + + sd->pos=(int)((*ip)*sd->one); + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + SEND_MESSAGE(dp,MSG_DRAW,0); + show_mouse(screen); + } + } + else + { + last_x=mouse_x; + + /* I'm sure there's a better way of doing this, but I couldn't + get the sums to work out... + */ + while(mouse_b) + { + int mx; + int diff; + int np; + + mx=mouse_x; + diff=mx-last_x; + np=sd->pos+diff; + + if ((diff<0)&&((*ip)>0)) + { + while((sd->pos>np)&&(*ip)) + { + (*ip)--; + sd->pos=(int)((*ip)*sd->one); + } + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + SEND_MESSAGE(dp,MSG_DRAW,0); + show_mouse(screen); + } + else if ((diff>0)&&((*ip)d2)) + { + while((sd->posd2)) + { + (*ip)++; + sd->pos=(int)((*ip)*sd->one); + } + + if (sd->pos==(d->h-sd->size)) + *ip=d->d2; + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + SEND_MESSAGE(dp,MSG_DRAW,0); + show_mouse(screen); + } + + last_x=mx; + } + } + + break; + + default: + break; + } + + return(D_O_K); +} + + +static int d_textedit(int msg, DIALOG *d, int c) +{ + static char out[2]=" "; + char *tmp; + TextEditData *te; + TextEditLine *p; + int y,sx,sy; + int f; + + p=d->dp; + + switch(msg) + { + case MSG_START: + /* Memory for text buffer + */ + te=Grab(sizeof(*te)); + d->dp3=te; + te->start=TRUE; + te->top=0; + te->x=0; + te->y=0; + te->col=0; + + te->lines=0; + + while(p[te->lines].p) + te->lines++; + + for(sx=0;sxt[sy][sx]=0; + break; + + case MSG_END: + Release(d->dp3); + break; + + case MSG_WANTFOCUS: + return(D_WANTFOCUS); + break; + + case MSG_LOSTFOCUS: + return(D_WANTFOCUS); + break; + + case MSG_DRAW: + te=d->dp3; + + if (te->start) + { + rectfill(screen,d->x,d->y,d->x+d->w-1,d->y+d->h-1,ACOL(WHITE)); + te->start=FALSE; + } + + text_mode(ACOL(WHITE)); + + y=te->top; + + rectfill(screen,d->x+d->w-FW,d->y, + d->x+d->w-1,d->y+d->h-1,ACOL(WHITE)); + + for(sy=0;sylines) + { + for(sx=0;sxcol+sx>=p[y].len)|| + (te->t[sy][sx]!=p[y].p[te->col+sx])) + { + if (te->col+sx>=p[y].len) + te->t[sy][sx]=0; + else + te->t[sy][sx]=p[y].p[te->col+sx]; + + if (isprint(te->t[sy][sx])) + out[0]=te->t[sy][sx]; + else + out[0]=' '; + + textout(screen,font,out, + d->x+(sx*FW),d->y+(sy*FH),ACOL(BLACK)); + } + } + else + { + memset(te->t[sy],0,TE_WIDTH+1); + rectfill(screen,d->x,d->y+(sy*FH), + d->x+d->w-1,d->y+(sy*FH)+FH-1,ACOL(WHITE)); + } + + text_mode(ACOL(BLACK)); + out[0]=isprint(te->t[te->y-te->top][te->x-te->col]) ? + te->t[te->y-te->top][te->x-te->col] : ' '; + textout(screen,font,out, + d->x+((te->x-te->col)*FW), + d->y+((te->y-te->top)*FH),ACOL(WHITE)); + te->t[te->y-te->top][te->x-te->col]=-1; + + break; + + case MSG_CLICK: + te=d->dp3; + + te->y=(mouse_y-d->y)/FH; + te->x=te->col+(mouse_x-d->x)/FW; + + if (te->y>=te->lines) + te->y=te->lines-1; + + if (te->x>p[te->y].len) + te->x=p[te->y].len; + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + show_mouse(screen); + break; + + case MSG_CHAR: + te=d->dp3; + + /* Pressing shift and space seems to generate odd values + */ + if ((c>>8)==KEY_SPACE) + c=(c&0xff00)|' '; + + switch(c>>8) + { + case KEY_HOME: + te->x=0; + te->col=0; + break; + + case KEY_END: + te->x=p[te->y].len; + te->col=MAX(0,te->x-TE_WIDTH); + break; + + case KEY_LEFT: + { + int ctrl; + + ctrl=key_shifts&(KB_CTRL_FLAG|KB_SHIFT_FLAG); + + if (ctrl) + while((te->x)&&(isspace(p[te->y].p[te->x]))) + { + if (te->x) + te->x--; + else + ctrl=FALSE; + + if (te->xcol) + te->col--; + } + + do { + if (te->x) + te->x--; + else + ctrl=FALSE; + + if (te->xcol) + te->col--; + + if (isspace(p[te->y].p[te->x])) + ctrl=FALSE; + + } while(ctrl); + + break; + } + + case KEY_RIGHT: + { + int ctrl; + + ctrl=key_shifts&(KB_CTRL_FLAG|KB_SHIFT_FLAG); + + if (ctrl) + while((te->xy].len)&& + (isspace(p[te->y].p[te->x]))) + { + te->x++; + + if ((te->x-TE_WIDTH)>te->col) + te->col++; + } + + do { + if (te->xy].len) + { + te->x++; + + if ((te->x-TE_WIDTH)>te->col) + te->col++; + } + else + ctrl=FALSE; + + if (isspace(p[te->y].p[te->x])) + ctrl=FALSE; + + } while(ctrl); + + break; + } + + case KEY_UP: + if (te->y) + { + te->y--; + + if (te->ytop) + te->top--; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-TE_WIDTH); + } + } + break; + + case KEY_PGUP: + if (te->y) + { + te->y-=TE_HEIGHT; + + if (te->y<0) + te->y=0; + + if (te->ytop) + te->top=te->y; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-TE_WIDTH); + } + } + break; + + case KEY_DOWN: + if (p[te->y+1].p) + { + te->y++; + + if (te->y>=te->top+TE_HEIGHT) + te->top=te->y-TE_HEIGHT+1; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-TE_WIDTH); + } + } + break; + + case KEY_PGDN: + te->y+=TE_HEIGHT; + + if (te->y>=te->lines) + te->y=te->lines-1; + + if (te->y>=te->top+TE_HEIGHT) + te->top=te->y-TE_HEIGHT+1; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-TE_WIDTH); + } + + break; + + case KEY_DEL: + if (p[te->y].p[te->x]) + { + for(f=te->x;fy].len;f++) + p[te->y].p[f]=p[te->y].p[f+1]; + + p[te->y].len--; + p[te->y].p[p[te->y].len]=0; + } + else if (p[te->y+1].p) + { + p[te->y].len+=p[te->y+1].len; + + p[te->y].p=ReGrab(p[te->y].p, + (p[te->y].len/TE_CHUNK+1)*TE_CHUNK+1); + + strcat(p[te->y].p,p[te->y+1].p); + + Release(p[te->y+1].p); + + for(f=te->y+1;flines;f++) + p[f]=p[f+1]; + + te->lines--; + + p=d->dp=ReGrab(d->dp, + sizeof(TextEditLine)*(te->lines+1)); + p[te->lines].p=NULL; + } + break; + + case KEY_BACKSPACE: + if (te->x) + { + for(f=te->x;fy].len;f++) + p[te->y].p[f-1]=p[te->y].p[f]; + + p[te->y].len--; + te->x--; + p[te->y].p[p[te->y].len]=0; + + if (te->xcol) + te->col--; + } + else if (te->y) + { + te->x=p[te->y-1].len; + te->col=MAX(0,te->x-TE_WIDTH); + + p[te->y-1].len+=p[te->y].len; + + p[te->y-1].p=ReGrab(p[te->y-1].p, + (p[te->y-1].len/TE_CHUNK+1)*TE_CHUNK+1); + + strcat(p[te->y-1].p,p[te->y].p); + + Release(p[te->y].p); + + for(f=te->y;flines;f++) + p[f]=p[f+1]; + + if (--te->ytop) + te->top--; + + te->lines--; + p=d->dp=ReGrab(d->dp, + sizeof(TextEditLine)*(te->lines+1)); + p[te->lines].p=NULL; + } + break; + + case KEY_ENTER: + te->lines++; + p=d->dp=ReGrab(d->dp,sizeof(TextEditLine)*(te->lines+1)); + + for(f=te->lines;f>te->y;f--) + p[f]=p[f-1]; + + tmp=Strdup(p[te->y].p+te->x); + tmp=ReGrab(tmp,(strlen(tmp)/TE_CHUNK+1)*TE_CHUNK+1); + + p[te->y].p[te->x]=0; + p[te->y].len=strlen(p[te->y].p); + + te->y++; + te->x=0; + te->col=0; + + p[te->y].p=tmp; + p[te->y].len=strlen(tmp); + + if (te->y>=te->top+TE_HEIGHT) + te->top=te->y-TE_HEIGHT+1; + + break; + + case KEY_TAB: + for(f=te->x%4+1;f<=4;f++) + simulate_keypress(KEY_SPACE<<8|' '); + break; + + default: + if (isprint(c&0xff)) + { + p[te->y].len++; + + if (!(p[te->y].len%TE_CHUNK)) + p[te->y].p=ReGrab(p[te->y].p, + (p[te->y].len/TE_CHUNK+1)* + TE_CHUNK+1); + + for(f=p[te->y].len;f>te->x;f--) + p[te->y].p[f]=p[te->y].p[f-1]; + + p[te->y].p[te->x]=(c&0xff); + + te->x++; + + if ((te->x-TE_WIDTH)>te->col) + te->col++; + } + break; + } + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + show_mouse(screen); + return(D_USED_CHAR); + break; + } + + return (D_O_K); +} + + +static int d_dial_picklist(int msg, DIALOG *d, int c) +{ + char **text; + int lx,ly; + + text=d->dp; + + switch(msg) + { + case MSG_START: + break; + + case MSG_END: + break; + + case MSG_DRAW: + { + int bx1,by1,bx2,by2; + + bx1=d->x+d->w-d->h+1; + by1=d->y; + bx2=d->x+d->w-1; + by2=d->y+d->h-1; + + text_mode(-1); + + if (d->flags&D_GOTFOCUS) + rectfill(screen,d->x,d->y,d->x+d->w-1,d->y+d->h-1,ACOL(PL_COL)); + else + rectfill(screen,d->x,d->y,d->x+d->w-1,d->y+d->h-1,ACOL(WHITE)); + + Rect3D(bx1,by1,d->h,d->h,FALSE,BEVEL); + + textout(screen,font,text[d->d1],d->x,d->y,d->fg); + break; + } + + case MSG_WANTFOCUS: + return(D_WANTFOCUS); + break; + + case MSG_CLICK: + { + BITMAP *under; + int done; + BoundBox b; + int fg,bg; + int f; + int draw; + int cur; + int last; + int new; + int press; + int first; + + text_mode(-1); + cur=d->d1; + press=FALSE; + first=TRUE; + + done=FALSE; + b.h=d->d2*(FH+1)+1; + b.w=d->w; + b.x=d->x; + b.y=d->y; + + if ((b.x+b.w)>SCRW) + b.x=SCRW-b.w; + + if ((b.y+b.h)>SCRH) + b.y=SCRH-b.h; + + if (!(under=create_bitmap(b.w+1,b.h+1))) + GFX_exit(EXIT_FAILURE,"No more memory to create save under\n"); + + show_mouse(NULL); + blit(screen,under,b.x,b.y,0,0,b.w+1,b.h+1); + show_mouse(screen); + + show_mouse(NULL); + rectfill(screen,b.x,b.y,b.x+b.w,b.y+b.h,ACOL(WHITE)); + rect(screen,b.x,b.y,b.x+b.w,b.y+b.h,ACOL(BLACK)); + + for(f=0;fd2;f++) + { + if (f==cur) + { + fg=ACOL(WHITE); + bg=ACOL(BLACK); + } + else + { + fg=ACOL(BLACK); + bg=ACOL(WHITE); + } + + rectfill(screen,b.x+1,b.y+1+(FH+1)*f, + b.x+b.w-1,b.y+b.h-1,bg); + textout(screen,font,text[f],b.x+1,b.y+1+(FH+1)*f,fg); + } + + show_mouse(screen); + + draw=FALSE; + last=-1; + lx=-1; + ly=-1; + + while(!done) + { + if (draw) + { + show_mouse(NULL); + + for(f=0;fd2;f++) + { + if (f==cur) + { + fg=ACOL(WHITE); + bg=ACOL(BLACK); + + rectfill(screen,b.x+1,b.y+1+(FH+1)*f, + b.x+b.w-1,b.y+(FH+1)*(f+1),bg); + textout(screen,font,text[f], + b.x+1,b.y+1+(FH+1)*f,fg); + } + else if (f==last) + { + fg=ACOL(BLACK); + bg=ACOL(WHITE); + + rectfill(screen,b.x+1,b.y+1+(FH+1)*f, + b.x+b.w-1,b.y+(FH+1)*(f+1),bg); + textout(screen,font,text[f], + b.x+1,b.y+1+(FH+1)*f,fg); + } + } + + show_mouse(screen); + draw=FALSE; + } + + if (first) + { + while(mouse_b); + first=FALSE; + } + + if (keypressed()) + { + int k; + + k=readkey(); + + switch(k>>8) + { + case KEY_UP: + draw=TRUE; + + if (cur==-1) + cur=d->d2-1; + else + if (--cur<0) + cur+=d->d2; + break; + + case KEY_DOWN: + draw=TRUE; + + if (cur==-1) + cur=0; + else + cur=(cur+1)%d->d2; + break; + + case KEY_ESC: + cur=-1; + done=TRUE; + break; + + case KEY_ENTER: + done=TRUE; + break; + + default: + break; + } + } + else + { + if ((mouse_b)&&(!press)) + press=TRUE; + + if ((!mouse_b)&&(press)) + { + done=TRUE; + lx=-1; + ly=-1; + } + + last=cur; + + if ((lx!=mouse_x)||(ly!=mouse_y)) + { + lx=mouse_x; + ly=mouse_y; + + if (MouseInBox(&b,1)!=-1) + { + new=(mouse_y-b.y)/(FH+1); + + if (new>=d->d2) + new=d->d2-1; + + if (new!=cur) + { + cur=new; + draw=TRUE; + } + } + else + { + if (cur!=-1) + draw=TRUE; + + cur=-1; + } + } + } + } + + if (cur!=-1) + d->d1=cur; + + show_mouse(NULL); + blit(under,screen,0,0,b.x,b.y,b.w+1,b.h+1); + SEND_MESSAGE(d,MSG_DRAW,0); + show_mouse(screen); + + break; + } + + case MSG_CHAR: + switch(c>>8) + { + case KEY_ENTER: + SEND_MESSAGE(d,MSG_CLICK,0); + break; + + default: + return(D_O_K); + break; + } + + show_mouse(NULL); + SEND_MESSAGE(d,MSG_DRAW,0); + show_mouse(screen); + return(D_USED_CHAR); + break; + + default: + break; + } + + return(D_O_K); +} + + +static int d_title_proc(int msg, DIALOG *d, int c) +{ + char *t; + int x,y; + int l; + + if (msg==MSG_DRAW) + { + t=d->dp; + l=strlen(t); + + x=d->x-l*(FW/2); + y=d->y; + + text_mode(d->bg); + textout(screen,font,t,x,y,d->fg); + + line(screen,active_dialog[0].x+BEVEL+1,d->y+FH+1, + active_dialog[0].x+active_dialog[0].w-BEVEL-1, + d->y+FH+1,ACOL(GUI_HI)); + + line(screen,active_dialog[0].x+BEVEL+1,d->y+FH+2, + active_dialog[0].x+active_dialog[0].w-BEVEL-1, + d->y+FH+2,ACOL(GUI_LO)); + } + + return(D_O_K); +} + + +static int d_my_ctext_proc(int msg, DIALOG *d, int c) +{ + char *t; + int x,y; + int l; + + if (msg==MSG_DRAW) + { + t=d->dp; + l=strlen(t); + + x=d->x-l*(FW/2); + y=d->y; + + text_mode(d->bg); + textout(screen,font,t,x,y,d->fg); + } + + return(D_O_K); +} + + +static int d_my_text_proc(int msg, DIALOG *d, int c) +{ + if (msg==MSG_DRAW) + { + text_mode(d->bg); + textout(screen,font,d->dp,d->x,d->y,d->fg); + } + + 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. + + 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_my_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,PLAT_MENU *child) +{ + int h,hy; + 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-FH/2,fg); + + if (child) + { + h=b->h-(SMALL_BEVEL*2)-2; + hy=b->y+SMALL_BEVEL+1; + + line(screen,b->x+b->w-SMALL_BEVEL-2-h/2,hy, + b->x+b->w-SMALL_BEVEL-2,hy+h/2,ACOL(GUI_HI)); + + line(screen,b->x+b->w-SMALL_BEVEL-2-h/2,hy, + b->x+b->w-SMALL_BEVEL-2-h/2,hy+h,ACOL(GUI_HI)); + + line(screen,b->x+b->w-SMALL_BEVEL-2-h/2,hy+h, + b->x+b->w-SMALL_BEVEL-2,hy+h/2,ACOL(GUI_LO)); + } +} + + +static int MouseInBox(BoundBox *box,int no) +{ + int f; + + for(f=0;f=box[f].x)&&(mouse_x=box[f].y)&&(mouse_ySCRW) + menu_box.x=SCRW-menu_box.w; + + if ((menu_box.y+menu_box.h)>SCRH) + menu_box.y=SCRH-menu_box.h; + + if ((menu_box.x<0)||(menu_box.y<0)) + { + alert("Cannot display menu:",title,"Menu is bigger than display!", + "OK",NULL,0,0); + + ret.mode=MENU_CHILD_RETURN; + ret.ret=defval; + + return(ret); + } + + cx=menu_box.x+menu_box.w/2; + + /* Save screen contents + */ + show_mouse(NULL); + + if (!(under=create_bitmap(menu_box.w+1,menu_box.h+1))) + GFX_exit(EXIT_FAILURE,"No more memory to create MENU save under\n"); + + blit(screen,under,menu_box.x,menu_box.y,0,0,menu_box.w+1,menu_box.h+1); + + /* Draw menu border and title + */ + Rect3D(menu_box.x,menu_box.y,menu_box.w,menu_box.h,FALSE,BEVEL); + text_mode(-1); + textout_centre(screen,font,title,cx,menu_box.y+BEVEL*2,ACOL(GUI_TEXTBOLD)); + + /* Draw menu items + */ + cur=0; + last_cur=-1; + + by=menu_box.y+BEVEL*2+FH+4; + + for(f=0;f>8) + { + case KEY_ESC: + quit=TRUE; + ret.mode=MENU_CANCEL_ESC; + break; + + case KEY_ENTER: + ret.mode=MENU_OK; + done=TRUE; + break; + + case KEY_DOWN: + show_mouse(NULL); + DrawMenuItem(&box[cur],menu[cur].text,FALSE, + menu[cur].child); + + cur=(cur+1)%no; + + DrawMenuItem(&box[cur],menu[cur].text,TRUE, + menu[cur].child); + show_mouse(screen); + break; + + case KEY_UP: + show_mouse(NULL); + DrawMenuItem(&box[cur],menu[cur].text,FALSE, + menu[cur].child); + + if (cur) + cur--; + else + cur=no-1; + + DrawMenuItem(&box[cur],menu[cur].text,TRUE, + menu[cur].child); + show_mouse(screen); + break; + + case KEY_RIGHT: + if (menu[cur].child) + do_child=TRUE; + + break; + + case KEY_LEFT: + if (is_child) + { + quit=TRUE; + ret.mode=MENU_CHILD_RETURN; + } + break; + } + else if ((lx!=mouse_x)||(ly!=mouse_y)) + { + int new; + + lx=mouse_x; + ly=mouse_y; + + new=MouseInBox(box,no); + + if (new!=-1) + cur=new; + } + } + + + /* Draw menu selection if changed + */ + if (cur!=last_cur) + { + show_mouse(NULL); + + if (last_cur!=-1) + DrawMenuItem(&box[last_cur],menu[last_cur].text,FALSE, + menu[last_cur].child); + + DrawMenuItem(&box[cur],menu[cur].text,TRUE, + menu[cur].child); + show_mouse(screen); + } + + last_cur=cur; + + /* Handle child menus + */ + if (do_child) + { + do_child=FALSE; + + cr=do_GUI_menu(menu[cur].text, + box[cur].x+box[cur].w,box[cur].y, + menu[cur].child,defval,TRUE); + + switch(cr.mode) + { + case MENU_OK: + child_done=TRUE; + break; + + case MENU_CANCEL_ESC: + quit=TRUE; + ret.mode=MENU_CANCEL_ESC; + break; + + case MENU_CANCEL_CLICK: + if (MouseInBox(&menu_box,1)==-1) + { + quit=TRUE; + ret.mode=MENU_CANCEL_CLICK; + } + else + { + if ((cur=MouseInBox(box,no))==-1) + cur=0; + else if (menu[cur].child) + do_child=TRUE; + } + + break; + + case MENU_CHILD_RETURN: + break; + } + } + } + + show_mouse(NULL); + blit(under,screen,0,0,menu_box.x,menu_box.y,menu_box.w+1,menu_box.h+1); + show_mouse(screen); + destroy_bitmap(under); + Release(box); + + if (child_done) + ret=cr; + else + { + if (!quit) + ret.ret=menu[cur].client_index; + else + ret.ret=defval; + } + + return(ret); +} + + +int GUI_menu(char *title, int x, int y, PLAT_MENU menu[],int defval) +{ + return(do_GUI_menu(title,x,y,menu,defval,FALSE).ret); +} + + +char *GUI_fsel(char *title, char *default_path, char *filter) +{ + int ret; + char path[PATH_MAX+1]; + + if ((filter)&&(*filter=='.')) + filter++; + + strcpy(path,default_path); + + GFX_bounce(); + + ret=my_file_select(title,path,filter); + + GFX_FORCE_REDRAW(); + + if (ret) + return(Strdup(path)); + + return(NULL); +} + + +int GUI_picklist(char *title,char *opt[]) +{ + int ml; + int ret; + + pick_no=0; + + /* Enough room for the OK/CANCEL + */ + ml=(FW*16)+30; + ml=MAX(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(); + + switch(ret) + { + case PL_OK: + case PL_PICKLIST: + return(picklist[IPL_PICKLIST].d1); + break; + + default: + return(-1); + break; + } +} + + +int GUI_client_picklist(char *title,PLAT_PICKLIST opt[],int defval) +{ + int ml; + int ret; + char **c_opt; + int f; + + pick_no=0; + + /* Enough room for the OK/CANCEL + */ + ml=(FW*16)+30; + ml=MAX(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+=FH*4; + ml+=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_my_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+=FH*4; + ml+=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_my_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;ftl)) + tl=l; + + pl=DIALOG_STRLEN*FW; + + for(f=0;fpl) + pl=l; + + ml=tl+pl+(FW*4); + + if (ml<(text_length(font,title)+FW*4)) + ml=text_length(font,title)+FW*4; + + h+=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_my_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=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;fd[6+(f*3)].w) + d[6+(f*3)].w=l; + + d[5+(f*3)].w=d[6+(f*3)].w+BEVEL*2; + + d[6+(f*3)].proc=d_dial_picklist; + d[6+(f*3)].x=d[5+(f*3)].x+BEVEL; + d[6+(f*3)].y=y+20+BEVEL+1+f*15; + d[6+(f*3)].h=FH; + d[6+(f*3)].fg=ACOL(BLACK); + d[6+(f*3)].bg=ACOL(WHITE); + d[6+(f*3)].key=0; + d[6+(f*3)].flags=0; + d[6+(f*3)].d1=pd[f].data.pl.current; + d[6+(f*3)].d2=pd[f].data.pl.no; + d[6+(f*3)].dp=pd[f].data.pl.text; + d[6+(f*3)].dp2=d[6+(f*3)].dp3=NULL; + } + else + { + if (pd[f].type==PLAT_DIAL_INTEGER) + { + tmp=pd[f].data.i; + sprintf(pd[f].data.s,"%d",tmp); + } + + if (pd[f].type==PLAT_DIAL_DOUBLE) + { + d_tmp=pd[f].data.d; + sprintf(pd[f].data.s,"%G",d_tmp); + } + + d[5+(f*3)].proc=d_inv_3d_box; + d[5+(f*3)].x=d[4+(f*3)].x+tl+FW; + d[5+(f*3)].y=y+21+f*15; + d[5+(f*3)].w=text_length(font," ")*DIALOG_STRLEN+2*BEVEL; + d[5+(f*3)].h=8+BEVEL*2; + d[5+(f*3)].fg=ACOL(GUI_LO); + d[5+(f*3)].bg=ACOL(GUI_MID); + d[5+(f*3)].key=0; + d[5+(f*3)].flags=0; + d[5+(f*3)].d1=d[5+(f*3)].d2=0; + d[5+(f*3)].dp=d[5+(f*3)].dp2=d[5+(f*3)].dp3=NULL; + + d[6+(f*3)].proc=d_edit_proc; + d[6+(f*3)].x=d[5+(f*3)].x+BEVEL; + d[6+(f*3)].y=y+20+BEVEL+1+f*15; + d[6+(f*3)].w=text_length(font," ")*DIALOG_STRLEN; + d[6+(f*3)].h=10; + /* + d[6+(f*3)].fg=ACOL(GUI_TEXT); + d[6+(f*3)].bg=ACOL(GUI_MID); + */ + d[6+(f*3)].fg=ACOL(BLACK); + d[6+(f*3)].bg=ACOL(WHITE); + d[6+(f*3)].key=0; + d[6+(f*3)].flags=0; + d[6+(f*3)].d1=PLAT_DIAL_MAXSTRLEN; + d[6+(f*3)].d2=strlen(pd[f].data.s); + d[6+(f*3)].dp=pd[f].data.s; + d[6+(f*3)].dp2=d[6+(f*3)].dp3=NULL; + } + } + + d[4+(no*3)].proc=NULL; + + GFX_bounce(); + if(do_dialog(d,-1)==2) + { + for(f=0;f +#include +#include +#include +#include +#include + +#define MAX_ARGS 128 + +static void CopyArgs(char *argv[],char *new[]) +{ + char *na; + char *p; + int len; + int f; + + len=0; + f=0; + while(argv[f]) + len+=strlen(argv[f++])+1; + + len++; + + na=Grab(len); + + f=0; + while(argv[f]) + { + strcat(na,argv[f++]); + strcat(na," "); + } + + f=0; + p=strtok(na," \t"); + + while((f + + +int StrCaseCmp(char *a, char *b) +{ + if (!a || !b) + return 0; + + return strcasecmp(a,b); +} + +int StrNCaseCmp(char *a, char *b, int n) +{ + if (!a || !b) + return 0; + + return strncasecmp(a,b,n); +} + + +/* END OF FILE */ diff --git a/doc/bugs.htm b/doc/bugs.htm new file mode 100644 index 0000000..92e5262 --- /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.
+ +

Also check the system dependent +documentation to see if there is any bugs specific to your +system.

+ +
+ +

Back to index

+ +

$Id$

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

Building

+ +

This part of the documentation simply expands slightly +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 separator for this platform. +This is used so that the makefile can safely access +sub directories:

+ +
+

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.5 2000/08/13 00:35:59 dosuser Exp dosuser $

+ + diff --git a/doc/changelog.htm b/doc/changelog.htm new file mode 100644 index 0000000..8fd333c --- /dev/null +++ b/doc/changelog.htm @@ -0,0 +1,64 @@ + + + + +viDOOM - Free Software DOOM editor + + + + +

Changelog

+ +

Below is a list of the major features added or bugs fixed in +each release:

+ + + + + + + + + + + + + + + + + + + + + + +
Version Date Changes
0.0105/08/2000Initial release
0.0213/08/2000
    +
  1. Fixed bug in step creation
  2. +
  3. Added functionality to allow the selection of + overlapping objects
  4. +
+
0.03Not yet completed
    +
  1. Fixed embarrassingly bad file pointer leaks.
  2. +
  3. Added conditional directives to config file.
  4. +
  5. Altered some configuration so that thing flags, + etc, can be different in HEXEN and DOOM mode.
  6. +
  7. Added support for generalised linedefs and sector + types.
  8. +
  9. Added support for ZDOOM HEXEN maps.
  10. +
  11. Added support for editting the MAPINFO lump for + ZDOOM levels.
  12. +
  13. Support for editting a SCRIPTS lump and + generating the HEXEN BEAHVIOR.
  14. +
  15. Fixed a small memory leak when closing a WAD + file.
  16. +
+
+ +
+ +

Back to index

+ +

$Id$

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

DJGPP

+ + + +
+ +

GUI

+ +

Hopefully the GUI employed is fairly self explanatory. All the +dialogs (apart from the file viewing one used to view the license +and node builder outputs - and that's read only anyway) have an OK +and Cancel button which behave as you would +expect.

+ +

All the dialogs, apart from the text editor (used for editing +the MAPINFO lump in ZDoom mode) can be cancelled by pressing the +ESCAPE key. On all dialogs the TAB key will give the focus to +different objects on the dialog for keyboard control. Note that +the file viewer does not currently honour keyboard controls (ie. +you cannot use cursor keys, page up, etc to navigate the file).

+ +

Note that if the yes/no question box is cancelled with the ESCAPE key, it +is taken as No.

+ +
+ +

Known bugs and problems

+ + + + + + +
External CommandsOn some PCs there has been occasions + where running external commands (e.g. the node builder) + fails for no apparent reason. If this does happen on your + system, then you must disable the command via the + VIDOOM.INI file and run it seperately outside of viDOOM.
+ +
+ +

Back to index

+ +

$Id$

+ + diff --git a/doc/ed_ex1.gif b/doc/ed_ex1.gif new file mode 100755 index 0000000..49f03f7 Binary files /dev/null and b/doc/ed_ex1.gif differ diff --git a/doc/ed_ex2.gif b/doc/ed_ex2.gif new file mode 100755 index 0000000..e50d72f Binary files /dev/null and b/doc/ed_ex2.gif differ diff --git a/doc/ed_ex3.gif b/doc/ed_ex3.gif new file mode 100755 index 0000000..c68be6a Binary files /dev/null and b/doc/ed_ex3.gif differ diff --git a/doc/ed_l_hex.gif b/doc/ed_l_hex.gif new file mode 100755 index 0000000..044078d Binary files /dev/null and b/doc/ed_l_hex.gif differ diff --git a/doc/ed_line.gif b/doc/ed_line.gif new file mode 100755 index 0000000..094e0d4 Binary files /dev/null and b/doc/ed_line.gif differ diff --git a/doc/ed_lninf.gif b/doc/ed_lninf.gif new file mode 100755 index 0000000..f663393 Binary files /dev/null and b/doc/ed_lninf.gif differ diff --git a/doc/ed_merge.gif b/doc/ed_merge.gif new file mode 100755 index 0000000..806d808 Binary files /dev/null and b/doc/ed_merge.gif differ diff --git a/doc/ed_multi.gif b/doc/ed_multi.gif new file mode 100755 index 0000000..207a96e Binary files /dev/null and b/doc/ed_multi.gif differ diff --git a/doc/ed_sect.gif b/doc/ed_sect.gif new file mode 100755 index 0000000..5d8f9b4 Binary files /dev/null and b/doc/ed_sect.gif differ diff --git a/doc/ed_step.gif b/doc/ed_step.gif new file mode 100755 index 0000000..58285e3 Binary files /dev/null and b/doc/ed_step.gif differ diff --git a/doc/ed_t_hx1.gif b/doc/ed_t_hx1.gif new file mode 100755 index 0000000..d6d0dee Binary files /dev/null and b/doc/ed_t_hx1.gif differ diff --git a/doc/ed_t_hx2.gif b/doc/ed_t_hx2.gif new file mode 100755 index 0000000..61ed203 Binary files /dev/null and b/doc/ed_t_hx2.gif differ diff --git a/doc/ed_thing.gif b/doc/ed_thing.gif new file mode 100755 index 0000000..af4785a Binary files /dev/null and b/doc/ed_thing.gif differ diff --git a/doc/ed_vert.gif b/doc/ed_vert.gif new file mode 100755 index 0000000..eaf5a0f Binary files /dev/null and b/doc/ed_vert.gif differ diff --git a/doc/editing.htm b/doc/editing.htm new file mode 100755 index 0000000..a276a86 --- /dev/null +++ b/doc/editing.htm @@ -0,0 +1,1603 @@ + + + + +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.
  • +
+ +

Note that the information bar at the top of the screen will +also indicate what format the level you're editing is in. If the +background to the title bar is blue, this map is in the original +DOOM format. If the background is red then the map is in the +extended HEXEN format.

+ +

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

+ +

Spread around the bottom 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.

+ +

Moving the mouse over an object will change it's colour, +indicating it can be selected. 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 Editing
Cursor KeysMove the map display
Shift + Cursor KeysMove the map display quickly
Ctrl + Cursor KeysMove the map by one pixel (i.e. by + whatever value the scale is currently set to).
Page Up/DownZoom in/out
Q/WAlert the grid lock scale
GSwitch grid lines on/off
XSwitch grid snapping on/off
Tab/Shift TabGo to next/previous edit mode
VVERTEX edit mode
LLINEDEF edit + mode
SSECTOR edit mode
TTHING edit mode
CMULTI edit mode
HOMELump edit menu. + Note that this only applies when the game type is ZDoom.
F9Deselect all objects
Shift + F9Invert current selection
F10Select all objects
Shift + F10Select all objects with a specific type + (not applicable to VERTEX objects).

Note that if the + map is in HEXEN format, then this will select special + actions, rather than types for LINEDEFS. Likewise, when + in THING edit mode you will be asked whether to search + for a THING's type or it's special action.

+
Ctrl + F10Select one object at the current + position. This is mainly useful for THING and VERTEX + where it may not be possible to select objects that are + overlaid one another.

When pressed if there are more + than one object at the current position a list will be + displayed with object numbers (and perhaps some extra + identifying information). Selecting one of the objects + from this list will select that object, whereas + cancelling the list leaves the current selection as is.

+

Note that it may not be possible to see the selected + object in it's selected colours if it is not on top of + the stack of overlapping objects.

+

Also bear in mind, that though sectors can be moved so + they overlap, and these can be picked using this method, + a DOOM level should never have overlapping sectors. + Unless you want the Cyberdemon to come and take you away + in the night.

+
Alt + F10As above, but any selected object is + selected in addition to the objects currently selected.
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 merge map 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: In viDOOM it is not permissible 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 scaling 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 screen 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 + visibly 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. Note that for an HEXEN format map a special + action will be asked for instead.
  • +
  • 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 typeChanges the sector type. The classes and their sector types are + defined in the config file.
Change generalised typeIf any generalised sector types have + been defined in the config file, this option allows you + to set them.
Set type to valueSimply allows you to enter any number to + set the sector type too.
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.
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 linedefs 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 screen 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.

+ +

Note that in HEXEN maps the showing of full linedef info +switch is ignored, and the full action special name shown. In +addition to this the special arguments are displayed:

+ +

+ +

Note that in this mode the tag highlighting will be based on +any special action arguments called "tag".

+ +

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: When prompted whether to fix a + problem, you can either elect to say Yes, + No, Yes to All or No + to All. If you select either No to All + or Yes to All then it applies to all + further answers in all of the different tests.

+

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 vertices +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 type
+ (Doom only)
Change 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.
Set Generalised linedef
+ (Doom only)
If any generalised linedef types have + been defined in the config file, this option allows you + to set them.
Set type to value
+ (Doom only)
Allows the linedef type to be set to an + arbitrary value.
Change special action
+ (Hexen only)
Change the special action of the + selected linedefs. On selecting this a list will appear + so a class of special 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 special action + from that class can be selected. The types are also + defined in the config file.
Set special action args
+ (Hexen only)
Change the arguments for the selected + linedefs. If all the linedefs are of the same special + action type then the arguments are entered once and set + for all the selected linedefs. If the special actions are + different you are asked if you want to set them all + individually.

If you select yes then + the argument setting dialog is displayed for each + selected linedef in turn. If no is + selected then the first selected linedef is used to work + out what args to ask for, and all selected linedefs have + their arguments set to those.

+
Set special action to + value
+ (Hexen only)
Allows the linedef special action to be + set to an arbitrary value.
Clear special action args
+ (Hexen only)
Clears all the special action arguments + to zero in the selected linedefs.
Set ranged special action + args
+ (Hexen only)
Change the arguments for the selected + linedefs, allowing the values to be modified for each + linedef. If all the linedefs are not of the same special + action type then you are asked if you want to continue.

If + you select yes, or all the linedefs are + of the same special action, then the arguments for the + first line are displayed and can be editted to the + initial values. After this the dialog is redisplayed for + you to enter how much the arguments should change by for + each subsequent line. Once this is entered the arguments + are applied.

+
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.
Swap sidesSwaps the sides of the linedef, so that + the linedef points in the other direction. Note that on + two sided linedefs the sidedefs are re-arranged so that + the texturing and sector numbers on the sides of the + linedef are not switched.

viDOOM will not swap + one-sided by default. Once a one-sided linedef is + detected a question box is displayed to say whether you + want to swap one-sided linedefs (either all or just this + one) or skip them (again either all or this one).

+
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 tag
+ (Doom only)
Change 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 textures to any + valueDisplays a dialog where the texture + names can be entered manually. This is mainly of use to + set texture names to the special values ZDoom supports on + linedefs that describe fog colours and so on.
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:

+ +

+ +

(Actually, it would be allowed, but wouldn't look too nice +when you played the level...)

+ +

Having got the excuses over with we can now go onto the +process involved with creating the steps. On selecting 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 corridor seen above.
+ Obviously, the butterfly effect is not what is + wanted...
+ +

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 linedefs 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 screen is a box which shows the details +of the thing the pointer is currently over. When editing Hexen +maps this will shows extra information for the thing ID, Z +position and special actions:

+ +

+ +

+ +

Extra Keys in Thing Mode

+ + + + + + + + + + + + + + + + + + +
, (comma)Rotate the selected things angles + anticlockwise.
. (period)Rotate the selected things angles + clockwise.
<Decrement the Z co-ord. This only + applies when the map is in Hexen format.
>Increment the Z co-ord. This only + applies when the map is in Hexen format.
+ +

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.
Set type to valueAllows the type of the selected things + to be set to any arbitrary value.
Change special action
+ (Hexen only)
These options select and set + the special action details for the selected things. This + operates identically to the linedef + special action selection.
Set special action to + value
+ (Hexen only)
Change special action + args
+ (Hexen only)
Clear special action args
+ (Hexen only)
Set ranged special action + args
+ (Hexen only)
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.
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 angle to value
+ (Hexen only)
Allows the angle of the selected things + to be changed to an arbitrary value. This is used to set + the angle field to a Polyobject number.
Set Z Position
+ (Hexen only)
Sets the Z position of the selected + things.
Set thing ID
+ (Hexen only)
Sets the thing ID of the selected + things.
SnapSnaps 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 linedefs 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 Cyber demons 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 vertexes (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.
SnapSnaps 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 linedefs 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 vertexes 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.

+ +

Multi Edit Popup Menu

+ +

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

+ + + + + + + + + + + + + + + + + + +
SnapSnap the selected things and vertices to + the current grid.
RotateRotate the selected things and vertices + around their common centre.
ScaleRotate the selected things and vertices + around their common centre.
MoveMoves the selected things and vertices.
+ +
+ +

Merging 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 (note that the 'first' map means +MAP01 if editing DOOM II maps, and E1M1 if editing DOOM maps). 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 +and don't opt to have floors/ceilings automatically adjusted then +it is generally a good idea to check the sidedefs to make sure +they have all their necessary upper/lower textures.

+ +

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.

+ +
+ +

Lump Editing

+ +

Pressing the HOME key provides you with the lump editing menu. +This menu is different depending on whether the map you are +editting is a DOOM format map or an HEXEN format map.

+ +

Doom

+ + + + + + + + + + +
Edit MAPINFOThis option only appears if the ability + to edit the MAPINFO lump is enabled in the config file. On + selecting this option the loaded MAPINFO lump is + displayed in the text editor for editing.
Switch to HEXEN modeThis switches a DOOM map to an HEXEN + map.

NOTE: Take heed of the displayed + warning. viDOOM makes no pretence at doing a proper + conversion - special actions, arguments, thing IDs and so + on are simply zeroed.

+
+ +

Hexen

+ + + + + + + + + + + + + + + + + + +
Edit MAPINFOThis option only appears if the ability + to edit the MAPINFO lump is enabled in the config file. On + selecting this option the loaded MAPINFO lump is + displayed in the text editor for editing.
Edit SCRIPTSThis displays the SCRIPTS lump from the + current map in the text editor for changing.
Create BEHAVIORCreates the BEHAVIOR lump from the + SCRIPTS. The ACS compiler must be configured for this to work. + Depending on other configuration + the output from the compilation will always be shown, or + just when an error occurs. Note that the current BEHAVIOR + lump is not replaced if an error occurs.
Switch to DOOM modeThis switches an HEXEN map to a DOOM + map.

NOTE: Take heed of the displayed + warning. viDOOM makes no pretence at doing a proper + conversion - linedef types will be wrong and any entered + SCRIPTS will be lost.

+
+ +
+ +

Back to index

+ +

$Id$

+ + diff --git a/doc/glossary.htm b/doc/glossary.htm new file mode 100644 index 0000000..c0dc89f --- /dev/null +++ b/doc/glossary.htm @@ -0,0 +1,152 @@ + + + + +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.

+ +

DOOM

+ +

If you're unsure what this is, you've probably come to the +wrong place by accident.

+ +

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.

+ +

LUMP

+ +

A lump is an entry in a WAD file. For +instance a MAP is made up of a number of +lumps, one defining the sectors for the +map, another the things, and so on.

+ +

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.

+ +

Also note that viDOOM supports two different map formats. The +original one, as used in DOOM and DOOM 2, and the extended HEXEN format supported by ZDoom.

+ +

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. Note that if you are to edit HEXEN levels you will need a node builder that +understands the different data structures used.

+ +

BSP is perhaps the best known of +these, and the one that was used all through viDOOM's initial +development. When developing the HEXEN edit mode for ZDoom WARM was used.

+ +

HEXEN

+ +

HEXEN is a game by Raven software that uses the DOOM graphics +engine. The WAD format for this is slightly different to DOOM, +having a BEHAVIOR lump for each MAP and +different formats for THINGS and LINEDEFS.

+ +

ZDoom supports this format.

+ +
+ +

Back to index

+ +

$Id$

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

viDOOM 0.03

+ +

"... 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. System dependent documentation
  12. +
  13. Porting
  14. +
  15. Bug Reports
  16. +
  17. Building (only needs to be + read for the source distribution)
  18. +
  19. Changelog
  20. +
+ +
+ +

viDOOM home +page

+ +

$Id$

+ + diff --git a/doc/license.htm b/doc/license.htm new file mode 100644 index 0000000..e7ba3e2 --- /dev/null +++ b/doc/license.htm @@ -0,0 +1,360 @@ + + + + +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..fb8b498 --- /dev/null +++ b/doc/mainmenu.htm @@ -0,0 +1,177 @@ + + + + +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 proceed. + This warning can be disabled in the INI file (see overview).

+
+ +
+

If you are editing for ZDOOM and the mapinfo_lump option has + been switched on, if there is a MAPINFO.WAD file in the PWAD directory it will be + loaded in as well for editing.

+
+ +

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.

+
+ +
+

If you are editing for ZDOOM and the mapinfo_lump option has + been switched on, a MAPINFO.WAD file will be generated in the + PWAD directory.

+
+ +
+

Note that the saved map must be built with a node builder before it can be + played in DOOM if the node + building 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 proceed. + This warning can be disabled in the INI file (see overview).

+
+ +
+

If you are editing for ZDOOM and the mapinfo_lump option has + been switched on, if there is a MAPINFO.WAD file in the PWAD directory it will be + loaded in as well for editing.

+
+ +

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.

+
+ +

List entries in WAD directory

+ +
+

This will list all the lumps defined in the directory of + the loaded IWAD and any loaded PWAD files. The entires will + be displayed in a picklist window.

+
+ +

About viDOOM

+ +
+

See who was responsible for this.

+
+ +

View License

+ +
+

View the license you must accept if you are to run viDOOM. + The license is repeated here in the + documentation. Don't worry, it's only the GNU public license, + and not anything nasty.

+
+ +

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 proceed. + This warning can be disabled in the INI file (see overview).

+
+ +
+ +

Back to index

+ +

$Id$

+ + diff --git a/doc/overview.htm b/doc/overview.htm new file mode 100644 index 0000000..aeec434 --- /dev/null +++ b/doc/overview.htm @@ -0,0 +1,1164 @@ + + + + +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 accommodate 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 +off chance 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)
  • +
+ +
+ +

Environment

+ +

If defined in the environment, the value of VIDOOM_DIR +will be made the current directory as soon as viDOOM starts. This +is important as the following initialisation files are expected +to be in the current directory when viDOOM starts.

+ +

Note:
+How this environment is set will differ from system. Basically +viDOOM just calls the C library getenv() function. So,. +for instance in a Unix type system this could be:

+ +
+

% setenv VIDOOM_DIR $HOME/viDOOM
+ or
+ % export VIDOOM_DIR=$HOME/viDOOM

+
+ +

Whereas in DOS/DJGPP version this could be:

+ +
+

C:\> set VIDOOM_DIR=C:\viDOOM

+
+ +
+ +

Initialisation File - 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 configuration

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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 unselected.
  • +
  • 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 + merging 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.

This has no effect when + editting HEXEN format maps.

+
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

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
auto_loadmapSet this to a list of levels to load on + startup. The format is to set it to a list of level names + seperated by commas. The first level that can be loaded + successfully is used. If this is set then initial_empty_map + is ignored.

If empty or not used then no map is auto + loaded, e.g.

+

# Load the first map, whether we're editing DOOM + or DOOM2
+ auto_loadmap=MAP01,E1M1

+

# Don't auto load any maps
+ auto_loadmap=

+
initial_empty_mapIf set to yes then on startup + viDOOM will have an empty map, either MAP01 or E1M1, + ready for editing. This is ignored if auto_loadmap + is set.
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 + efficient 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 + efficient 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 + efficient 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 definable +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 unnecessary then + it will be removed without asking. Likewise when asking + to add missing textures the texture picklist will appear + (with the linedef 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 merging + 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 occurrence 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 occurrence 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.
+ +
+ +

[ACS]

+ +

ACS compiler configuration - used to build BEHAVIOR lumps for +HEXEN format maps.

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

command=c:\doom\acc\acc.exe

+
dirDefines a working directory that will be + used for the compilation. This will generally be the same + place that the acs header files are stored and viDOOM + will change directory to this directory before + compilation. e.g.

dir=c:\doom\acc\

+
scriptviDOOM will write an acs script with + this name, into the directory defined by dir + before compilation. e.g.

script=vidoom.acs

+
objectviDOOM will assume that the acs object + created by the compiler will have this name. e.g.

script=vidoom.o

+
argsDefines the argument list to the ACC + compiler. The string %S will be replaced + by script, defined above. The string %O + will be replaced by object defined + above. e.g.

args=%S %O

+
+ +

 

+ +
+ +

[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 separated 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, linedefs, sectors and so + on.
+ viDOOM is currently supplied with doom.cfg, doom2.cfg + and zdoom.cfg.
mapinfo_lumpThis only applies to the section for [ZDoom] + .

If this is set to yes then on loading a + map from the loaded WAD files, the directory pointed to + by pwad_dir is searched for MAPINFO.WAD. + If found then the MAPINFO lump from the MAPINFO.WAD is + read in and can be edited within the editor. If + WADINFO.WAD does not exist then an empty MAPINFO lump is + created.

+

NOTE: On saving the level if there is anything + in the mapinfo entered in the editor the MAPINFO.WAD file + will be overwritten (or created if it does not exist). + This means that any infomation (apart from the edited + MAPINFO lump) that was in this WAD file will be lost. It + is suggested that nothing goes into MAPINFO.WAD except + for the MAPINFO lump.

+
create_hexenThis only applies to the section for [ZDoom] + .

If this is set to yes then on creating a + new map, it will be marked as being in the HEXEN format + (ie. having a BEHAVIOR lump and the HEXEN format of + THINGS and LINEDEFS). If set to no then the map + will be created as a DOOM map.

+

Setting to ask means that you will be asked + prior to creation which sort of map you want.

+
+ +
+ +

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 separate fields, e.g.

+ +

Field 1|Field 2

+ +

Blank lines and lines starting with a comment character (#) +are ignored. In addition to this blocks of lines can be forced to +be ignored by enclosing them with directives introduced with the +@ charcater. See the following +section for more details.

+ +

Note that some sections allow an edit mode to be defined, to +indicate whether this definition is for DOOM or HEXEN edit mode +(or both). The currently allowed edit modes are:

+ +
    +
  • Doom
  • +
  • Hexen
  • +
+ +

If what is being defined applies to more than one mode, these +can be seperated with commas.

+ +

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 in the + form "Edit mode|Class Name". e.g.

Doom,Hexen|Lighting

+
%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 setting a + THINGs flags. Each line is in the form "Edit + Mode|Group|Mask1|Mask2|Name|Single flag character". + e.g.

Doom,Hexen|0|0x01|0x01|Skill 1 and 2|E

+

The group number indicates masks that should be + mutually exclusive. Group zero means that the flag can be + toggled independently of any other. Other group numbers + mean that only one of that group should be set at a time.

+

The ways the masks work is:

+
+

To see if a flag is set the flags are ANDed with + mask1. If the result equals mask2 then the flag is + set.

+

When defining flags all the mask1 values are ORed + together and those bits cleared from the flags. Then + for any option that has been set mask2 is ORed onto + the flags.

+
+
%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). + Please feel free to change them to something more useful + if you prefer.

+
%LINEDEF_FLAGSDefines the flags used when setting a + LINEDEFs flags. The format for this section is identical + to THING_FLAGS.
%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 + "Edit Mode|Class|ID|Long name|Short name". e.g.

Doom|Lights|1|Light + random off|Random off

+
%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.

+
%LINEDEF_GEN_BITMASKSThis defines the bitmasks used to + represent generalised LINEDEF types (these were + introduced by BOOM).

This + section is a bit more complex than most of the others as + the format of the data is not fixed from line to line. + Each set starts with the class name for the bitmask. + Format for this line is:

+

class name|no of fields

+

After this follows no of fields repetitions + of the following:

+

field name|shorthand name|value

+

e.g.

+

%LINEDEF_GEN_BITMASKS
+ Speed|4
+ Slow|Slow|0
+ Normal|Norm|1
+ Fast|Fast|2
+ Turbo|Turb|3

+

Remember that value will be shifted left a specified + amount when used in the LINEDEF_GEN_TYPES + section and so they should be defined relative to bit 0. + Also note that inside the editor all the values + associated with a bitmask are ORed together to create a + mask that can extract that information from a generalised + linedef. Following all this can follow another class, and + so on. Also remember that blank lines and comments are + OK, so that sections can be readably split using white + space.

+
%LINEDEF_GEN_TYPESThis defines the groupings of + LINEDEF_GEN_BITMASKS to make up different generalised + LINEDEF types.

This section is a bit more complex than + most of the others as the format of
+ the data is not fixed from line to line. Each set starts + with the class name describing the name of this type of + generalised linedef, the number of different bit patterns + defined in the class, the low and high values that the + type occupies and a mask used when generating the value. + Format for this line is:

+

class name|low value|high value|mask|no of + bit-field classes

+

After this follows no of bit-fields repetitions + of the following:

+

bit-field name|shift

+

e.g.

+

Locked Door|0x3800|0x3bff|0x3800|5
+ Trigger|0
+ Speed|3
+ Locked door kind|5
+ Opens with|6
+ Number of keys|9

+

The shift defines how much the bitmask is shifted to + the left to generate the actual values stored in the + linedef type field. Note that along with these bitmask + values the mask field is also ORed onto the result to + create the entire linedef type value. Following all this + can follow another class, and so on. Also remember that + blank lines and comments are OK, so that sections can be + readably split using white space.

+
%SECTOR_GEN_BITMASKSThis works in exactly the same way as LINEDEF_GEN_BITMASKS, + but is used to define the generalised bitmasks used by a + SECTOR.
%SECTOR_GEN_TYPESThis works in exactly the same way as SECTOR_GEN_BITMASKS, but is + used to define the generalised types used by a SECTOR.
%HEXEN_ACTION_SPECIAL_CLASSESDefines the classes to group action + special types into in the editor picklists. Each line is + a class name.
%HEXEN_ACTION_SPECIALSDefines the HEXEN action specials. Each + line is of the form "Class + Name|Id|Name|arg0,arg1,arg2,arg3,arg4". Note that + not all the argument names need be filled in. e.g.

Normal|0|No + action|
+ Polyobject|1|Polyobj_StartLine|po,mirror,sound
+ Lighting|116|Light_Strobe|tag,upper,lower,u-tics,l-tics

+

Any arg name that is "tag" is used to work + out what sector the special is referring to. This is so + that tag highlighting (see editing + for details) still works in HEXEN mode.

+

Note that unfortunately this does not apply to THINGs + yet.

+
+ +
+ +

Config file directives

+ +

In the config files blocks of lines can be included or +excluded by surrounding them by enclosing them with directives +introduced with the @ charcater, e.g.:

+ +

@DOOM_LEVEL_STYLE
+%SECTOR_STYLES
+<data>
+@END DOOM_LEVEL_STYLE

+ +

As you can see a directive is terminated by putting the same +directive, beginning with END.

+ +

The main purporse of these is to stop SECTOR_STYLES and +LINEDEF_CHECK_DEFAULT being defined inappropriately (Doom and +Doom 2 have differing texture names, etc), and also to allow one +single ZDOOM configuration file to be defined, regardless of +whether you are using the Doom or Doom 2 IWAD files with it.

+ +

The following directives are currently supported:

+ + + + + + + + + + + + + + + + + + +
@DOOM_LEVEL_STYLEIncludes the lines up to the next @END + DOOM_LEVEL_STYLE if the level_style for this game is + defined as either Doom or Ultimate + Doom.
@DOOM_1_LEVEL_STYLEIncludes the lines up to the next @END + DOOM_1_LEVEL_STYLE if the level_style for this game is + defined as Doom.
@ULT_DOOM_LEVEL_STYLEIncludes the lines up to the next @END + ULT_DOOM_LEVEL_STYLE if the level_style for this game is + defined as Ultimate Doom.
@DOOM_2_LEVEL_STYLEIncludes the lines up to the next @END + DOOM_2_LEVEL_STYLE if the level_style for this game is + defined as Doom 2.
+ +
+ +

Back to index

+ +

$Id$

+ + diff --git a/doc/porting.htm b/doc/porting.htm new file mode 100644 index 0000000..fded757 --- /dev/null +++ b/doc/porting.htm @@ -0,0 +1,1452 @@ + + + + +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 +sub directory called OS.cfg. Also all the OS dependent C +source should go into a sub directory 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 D containing the OS + dependent C sources. The idea of defineing tdefining + 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 optimisation 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 library paths + required by this OS.
DIRSEPThe directory separator 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 executable. 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]
+degreelessness mode=off

+ +
+ +

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 + positive 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. + e.g.
      +
    • 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 palette 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 main 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 PLATMENU
+    {
+    char  *text;
+    int   client_index;
+    struct PLATMENU *child;
+    } 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. If the child field is not NULL, this + field is ignored.
child-If not NULL points to a further + array of PLAT_MENU objects defining a child menu.
+
typedef struct
+    {
+    char   *text;
+    int    group;
+    int    val;
+    } PLAT_MULTI;
+
+
This structure is used to entries for + the multi box call. A multi box is a dialog that holds a + mixture of radio buttons and check boxes.

The fields in + the structure are:

+ + + + + + + + + + + + + + + + +
text-This defines the text for the + multio box entry. NULL marks the end of the list + of entries.
group-The group this entry belongs to. + Group zero means that it is a check box and can + be checked/unchecked independently of other + entries. Entries in the same group should act as + radio buttons in that group.
val-The state of the check box/radio + button. TRUE means that it's set, FALSE means + it's clear. These fields are updated on exit once + the multo box is completed.
+
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
+    {
+    int     no;
+    int     current;
+    char    **text;
+    } PLAT_DIAL_PL;
+
typedef struct
+    {
+    char   *text;
+    int    type;
+    union  /* Data */
+        {
+        int          i;
+        char         s[PLAT_DIAL_MAXSTRLEN+1];
+        double       d;
+        PLAT_DIAL_PL pl;
+        } data;
+    } PLAT_DIALOG;
+
+
These structures are used to define + entries for a simple dialog.

The fields in the + PLAT_DIAL_PL structure are:

+ + + + + + + + + + + + + + + + +
no-The number of elements pointed + to by text.
current-The currently selected item in + the picklist. This is updated on exit if the + dialog is accepted.
text-The text for the picklist + entries. This is treated as an array of character + pointers.
+

The fields in the PLAT_DIALOG 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, PLAT_DIAL_DOUBLE and + PLAT_DIAL_PICKLIST.
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.
data.pl-This is the structure that + defines how a PLAT_DIAL_PICKLIST is displayed. + The current field in this is updated if the + selected picklist value changes.
+
+ +

Note that along with the types, the following predefined +values are set (these are read from the INI file). Note that they +should 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 destroy 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_yesno_all(char *question)

+ +
+

Works like GUI_yesno(), but displays to + extra options - "Yes to All" and "No to + All". If either of these options are selected then + further calls to this function should return TRUE/FALSE + accordingly, until GUI_start_yesno__all() is + called.

+
+ +

int GUI_start_yesno_all(void);

+ +
+

Resets GUI_yesno_all().

+
+ +

int GUI_alert(char *title, char *text, char +*button_text)

+ +
+

Display an alert with a title of title, + containing text as the message and with a single + button labelled button_text. Note that text is split + into multiple lines by the pipe (|) character.

+
+ +

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 + from the selected option in a child menu, 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 matches 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, PLAT_MULTI opts[])

+ +
+

Display a mutli-selection radio box. The items are + described opts. 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 + within the dial elements is undefined.

+
+ +

void GUI_file_view(char *title, char *file)

+ +
+

Displays the contents of a text file, allowing the user to + move around and view the file. What form this takes is no + concern at all to viDOOM.

+

If is assumed this can view both DOS format (lines + terminated with CR and LF) and UNIX format text files (lines + terminated with LF).

+
+ +

char *GUI_text_edit(char *title, char *text)

+ +
+

Allows simple text editting. The form this display takes + is of noconcern to viDOOM (if applicable it would be more + than OK to start an external text editor). text is a + pointer to the original text, which is one long string with + line breaks denoted by the '\n' character.

+

The return is a newly allocated copy of the edited text is + the text is OKed, or NULL if the text is cancelled. In either + case, the original string pointed to by text should be as it + was.

+
+ +
+ +

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 filename 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 separators 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. The 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 arguments, terminated with a + NULL pointer. Note that arguments may contain more than one + argument in each line - the actual command is described + simply by concatenating 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 command 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. While these can easily be portably written, +they are provided as functions in case local implementations +supply them (which will probably more effecient):

+ +

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 must 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 should be copied into the installation directory so + that binary distributions can be easily generated with + the license included and so that the LICENSE can be + viewed from viDOOM's main menu.

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

Note that, obviously, any OS specific files should also be +copied.

+ +
+ +

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. Also include a link to a system +specific HTML document detailing how the GUI works and any know +bugs, from doc/sys.htm.

+ +

For an example look at the DJGPP +documentation. As you can see, it doesn't have to be too big.

+ +
+ +

Back to index

+ +

$Id$

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

System Dependent

+ +

The following is a list of the pages provided for each port:

+ + + +
+ +

Back to index

+ +

$Id$

+ + diff --git a/doc/thanks.htm b/doc/thanks.htm new file mode 100644 index 0000000..edb3834 --- /dev/null +++ b/doc/thanks.htm @@ -0,0 +1,91 @@ + + + + +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 misinformed 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. +

+ +

BOOM - Team TNT
+One of the first newly extended versions of DOOM I saw after the +sources where released, and quite a revelation to see +transparencies, conveyer belts, water and all sorts making an +appearance. Still not to sure about the wind effect though :-)

+ +

ZDoom - Randy Heit
+My personal favourite out of the extended DOOMs. This took the +extensions added by BOOM, then went the whole hog and allowed +scripting and HEXEN style hub maps in DOOM. And made the editor +much harder to write :-)

+ +

Version 1.17b was used as the test for levels generated by +viDOOM during it's development.

+ +

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.

+ +

WARM - +Robert Frenske
+The HEXEN compatible node builder used when developing the HEXEN +editing mode.

+ +

Maths help - Mathew Wilson
+Someone who knows much more maths than I ever will and writer of +the LinesCross() algorithm - 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 - Bram Moolenaar et al +
+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.6 2000/08/18 23:24:35 dosuser Exp +dosuser $

+ + diff --git a/doom.cfg b/doom.cfg new file mode 100644 index 0000000..a43a671 --- /dev/null +++ b/doom.cfg @@ -0,0 +1,571 @@ +# 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.31 2000/11/13 16:16:38 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 +# +# +# The following sections are used to define generalised linedef and sector +# values. See zdoom.cfg for details: +# +# %LINEDEF_GEN_BITMASKS +# %LINEDEF_GEN_TYPES +# %SECTOR_GEN_BITMASKS +# %SECTOR_GEN_TYPES +# +# +# The following only need to appear in the config file for ZDoom if you are +# to be editing HEXEN format maps. See zdoom.cfg for examples: +# +# %HEXEN_ACTION_SPECIAL_CLASSES - action special classes +# %HEXEN_ACTION_SPECIALS - details action specials +# +# +# Note that some sections allow an edit mode to be defined, to indicate +# whether this definition is for DOOM or HEXEN edit mode (or both). The +# currently allowed edit modes are: +# +# Doom +# Hexen +# +# If what is being defined applies to more than one mode, these can be +# seperated with commas. +# + + +# 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 "edit mode|class name" +# +# +%SECTOR_CLASSES +Doom|Normal +Doom|Lights +Doom|Damage +Doom|Damage/Lights +Doom|Damage/Exit +Doom|Door +Doom|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 +# +# "edit mode|group|mask1|mask2|name|single flag char" +# +# Group indicates whether any flags are mutually exclusive. Group 0 is a +# special group that indicates that any combination of flags is allowed. +# Other positive groups indicate that only one from that group number can be +# selected. +# +# The way the masks work is that the flags are ANDed with mask1. The result is +# then compared for equality with mask2. If the result matches then the flag +# is set. +# +# If later config files define an identical masks, the later definition replaces +# the earlier one. +# +%THING_FLAGS +Doom|0|0x01|0x01|Skill 1 and 2|E +Doom|0|0x02|0x02|Skill 3|M +Doom|0|0x04|0x04|Skill 4 and 5|H +Doom|0|0x08|0x08|Deaf|D +Doom|0|0x10|0x10|Deathmatch only|X + + +# 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. Each line is +# +# "edit mode|group|mask1|mask2|name|single flag char" +# +# See the THING_FLAGS section for details of the fields. +# +# If later config files define an identical mask1, the later definition replaces +# the earlier one. +# +%LINEDEF_FLAGS +Doom|0|0x001|0x001|Impassible|I +Doom|0|0x002|0x002|Block monsters|M +Doom|0|0x004|0x004|Two-sided|2 +Doom|0|0x008|0x008|Upper unpegged|U +Doom|0|0x010|0x010|Lower unpegged|L +Doom|0|0x020|0x020|Secret|S +Doom|0|0x040|0x040|Blocks sound|B +Doom|0|0x080|0x080|Not on map|N +Doom|0|0x100|0x100|Already on map|A + + +# LINEDEF_FLAGS_EXTRA +# +# Simply defines which of the LINEDEF flag bits are the ones that indicates +# certain features. 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: +# Edit mode|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 +Doom|Normal|0|Normal|Normal +Doom|Lights|1|Light random off|Random off +Doom|Lights|2|Blink lights 0.5 second|0.5 blink +Doom|Lights|3|Blink lights 1.0 second|1.5 blink +Doom|Damage/Lights|4|Lose -10/20% health & blink lights 0.5 sec|-10/20% & 0.5 blink +Doom|Damage|5|Lose -5/10% health|-5/10% +Doom|Damage|7|Lose -2/5% health|-2/5% +Doom|Lights|8|Oscillating light|Oscillating light +Doom|Secret|9|Secret|Secret +Doom|Door|10|Door closes after 30 seconds|30 sec door +Doom|Damage/Exit|11|-10/20% health - end level if < 11%|Damage/end level +Doom|Lights|12|Blink lights synchronised 0.5 second|0.5 blink sync +Doom|Lights|13|Blink lights synchronised 1.0 second|1.5 blink sync +Doom|Door|14|Door opens after 300 seconds|300 sec door +Doom|Damage|16|Lose -10/20% health|-10/20% +Doom|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. +# +@DOOM_LEVEL_STYLE + +%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 + +@END DOOM_LEVEL_STYLE + + +# 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 +# +@DOOM_LEVEL_STYLE + +%LINEDEF_CHECK_DEFAULT +ASHWALL + +@END DOOM_LEVEL_STYLE diff --git a/doom2.cfg b/doom2.cfg new file mode 100644 index 0000000..14e7e52 --- /dev/null +++ b/doom2.cfg @@ -0,0 +1,77 @@ +# 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.15 2000/09/11 08:08:36 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 + +# LINEDEF_CHECK_DEFAULT +# +%LINEDEF_CHECK_DEFAULT +ASHWALL2 diff --git a/edit.c b/edit.c new file mode 100644 index 0000000..27c700d --- /dev/null +++ b/edit.c @@ -0,0 +1,751 @@ +/* + + 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) +{ + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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); + + mapinfo=map->mapinfo; + behavior=map->behavior; + behavior_size=map->behavior_size; + scripts=map->scripts; + scripts_size=map->scripts_size; + hexen_mode=map->hexen; + + 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); + + if (hexen_mode) + SetHexenLinedefTag(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; + + VIDOOM_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)); + } + + map->mapinfo=mapinfo; + map->behavior=behavior; + map->behavior_size=behavior_size; + map->scripts=scripts; + map->scripts_size=scripts_size; + map->hexen=hexen_mode; +} + + +void EditLoop(void) +{ + GFXEvent ev; + + VIDOOM_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; + + VIDOOM_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..20482ee --- /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 VIDOOM_EDIT_H +#define VIDOOM_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/edit3d.c b/edit3d.c new file mode 100644 index 0000000..a6eb88f --- /dev/null +++ b/edit3d.c @@ -0,0 +1,474 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + _Very_ basic 3D preview + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" +#include "map.h" +#include "gfx.h" + +#include +#include + + +/* ---------------------------------------- LOCAL DATA +*/ +#define POLY 0 +#define SPHERE 1 + +typedef struct + { + int type; + Point p[4]; + Point c; + int r; + int z; + int col; + void *next; + } Poly; + +static int draw_things=FALSE; +static int fade=0; +static int roll; +static int pitch; +static int px,py,pz; + +static Poly *plist=NULL; + + +/* ---------------------------------------- POLY LIST FUNCTIONS +*/ +static void NewPList(void) +{ + Poly *p; + + while (plist) + { + p=plist; + plist=plist->next; + Release(p); + } +} + + +static void AddPList(Poly *p) +{ + Poly *np; + Poly *l; + + if (p->col<0x101010) + return; + + np=Copy(p,sizeof(Poly)); + + if (!plist) + { + plist=np; + np->next=NULL; + return; + } + else + { + if (np->z>=plist->z) + { + np->next=plist; + plist=np; + return; + } + + l=plist; + + while(l) + { + if (np->zz) + { + if (!l->next) + { + l->next=np; + np->next=NULL; + return; + } + } + else + { + np->next=l->next; + l->next=np; + return; + } + + l=l->next; + } + } + + /* It shouldn't be possible to reach here!! + */ + Release(np); +} + + +/* ---------------------------------------- LOCAL FUNCTIONS +*/ +static void Transform (int x, int y, int z, int *rx, int *ry, int *rz) +{ + y=-y; + + *rx=x-px; + *ry=y-py; + *rz=z-pz; + + Rotate(0,0,rx,rz,roll); + Rotate(0,0,ry,rz,pitch); +} + + +static void Project (int x, int y, int z, int to_x, int to_z, Point *p) +{ + double dx,dy,sc; + + if ((z<1)&&(to_z<1)) + { + p->x=-1; + p->y=-1; + } + + if (z<1) + z=1; + + dx=(double)x; + dy=(double)y; + + sc=(double)z/400.0; + + p->x=(int)(dx/sc)+SCRW/2; + p->y=(int)(dy/sc)+SCRH/2; +} + +static int Fade(int col, int z) +{ + int r,g,b,f; + + f=z/(16/fade); + + r=(col&0xff0000)>>16; + g=(col&0xff00)>>8; + b=col&0xff; + + r=MAX(r-f,0); + g=MAX(g-f,0); + b=MAX(b-f,0); + + return(V_RGB(r,g,b)); +} + + +static void DoPoly(EditVert *v1, EditVert *v2, int low, int high) +{ + int x[4],y[4],z[4]; + int zt; + int f; + int ok; + Poly p; + + Transform(v1->v.x,low,v1->v.y,&x[0],&y[0],&z[0]); + Transform(v1->v.x,high,v1->v.y,&x[1],&y[1],&z[1]); + + Transform(v2->v.x,high,v2->v.y,&x[2],&y[2],&z[2]); + Transform(v2->v.x,low,v2->v.y,&x[3],&y[3],&z[3]); + + ok=FALSE; + + for(f=0;f<4;f++) + if (z[f]>0) + ok=TRUE; + + if (ok) + { + p.type=POLY; + + zt=0; + + p.z=999999; + + for(f=0;f<4;f++) + { + Project(x[f],y[f],z[f],x[(f+1)%4],z[(f+1)%4],&p.p[f]); + zt+=z[f]; + p.z=MIN(p.z,z[f]); + } + + if (fade) + p.col=Fade(WHITE,p.z); + else + p.col=WHITE; + + AddPList(&p); + } +} + + + +static void DoThing(EditThing *t,int tz) +{ + int x,y,z; + int r; + Poly p; + Point rp; + int col; + + Transform(t->t.x,tz,t->t.y,&x,&y,&z); + + if (z<1) + return; + + p.type=SPHERE; + + r=ThingRadius(t->t.type,&col); + + Project(x,y-r,z,x,z,&p.c); + Project(x+r,y-r,z,x+r,z,&rp); + + p.r=rp.x-p.c.x; + p.z=z; + + if (p.r<1) + p.r=1; + + if (fade) + p.col=Fade(RED,z); + else + p.col=col; + + AddPList(&p); +} + + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void EditPreview3D(void) +{ + int done; + int redraw; + GFXKey k; + int rd; + + px=0; + py=0; + pz=0; + roll=0; + pitch=0; + + done=FALSE; + redraw=TRUE; + rd=FALSE; + + while(!done) + { + if ((redraw)||(rd)) + { + EditThing *t; + EditLine *l; + EditSect *s,*sl; + int f; + int low,high; + int sn; + Poly *p; + + rd=FALSE; + + GFX_clear(BLACK); + + NewPList(); + + for(f=0;(fsr->sector))) + if ((l->sl)&&(sl=GETSECT(l->sl->sector))) + { + if (s->s.floor!=sl->s.floor) + { + low=MIN(s->s.floor,sl->s.floor); + high=MAX(s->s.floor,sl->s.floor); + DoPoly(l->v[0],l->v[1],low,high); + } + + if (s->s.ceiling!=sl->s.ceiling) + { + low=MIN(s->s.ceiling,sl->s.ceiling); + high=MAX(s->s.ceiling,sl->s.ceiling); + DoPoly(l->v[0],l->v[1],low,high); + } + } + else + DoPoly(l->v[0],l->v[1],s->s.floor,s->s.ceiling); + + rd=GFX_key(&k); + } + + if (draw_things) + for(f=0;(ft.x,t->t.y); + + if ((sn!=-1)&&(s=GETSECT(sn))) + high=s->s.floor; + else + high=0; + + if (hexen_mode) + high+=t->t.z; + + DoThing(t,high); + } + + rd=GFX_key(&k); + } + + p=plist; + + while((p)&&(!rd)) + { + switch(p->type) + { + case POLY: + for(f=0;f<4;f++) + GFX_line(p->p[f].x,p->p[f].y, + p->p[(f+1)%4].x,p->p[(f+1)%4].y,p->col); + break; + + case SPHERE: + GFX_fcircle(p->c.x,p->c.y,p->r,p->col); + break; + } + + p=p->next; + rd=GFX_key(&k); + } + + GFX_frect(0,0,SCRW,FH*2,BLUE); + + GFX_print(0,0,WHITE,"Pos: %d,%d,%d Roll: %d Pitch : %d %s", + px,py,pz,roll,pitch,rd ? "Draw interrupted" : "Draw done"); + + if (fade) + GFX_print(0,FH,WHITE,"Fade: Intensity %d",fade); + else + GFX_print(0,FH,WHITE,"Fade: off"); + + GFX_print(SCRW/2,FH,WHITE,"Things: %s",draw_things ? "On":"Off"); + + GFX_redraw(); + } + + if (!rd) + GFX_waitkey(&k); + + redraw=TRUE; + + if (k.code==GFX_ASCII) + switch(toupper(k.ascii)) + { + case 'T': + draw_things=!draw_things; + break; + + default: + redraw=FALSE; + break; + } + else + switch(k.code) + { + case GFX_ESC: + done=TRUE; + break; + + case GFX_LEFT: + if (k.alt) + { + pz+=(int)(cos(RAD(roll-90))*(k.shift ? 128 : 64)); + px+=(int)(sin(RAD(roll-90))*(k.shift ? 128 : 64)); + } + else + roll=(roll+360-(k.shift ? 15:5))%360; + break; + + case GFX_RIGHT: + if (k.alt) + { + pz+=(int)(cos(RAD(roll+90))*(k.shift ? 128 : 64)); + px+=(int)(sin(RAD(roll+90))*(k.shift ? 128 : 64)); + } + else + roll=(roll+(k.shift ? 15:5))%360; + break; + + case GFX_UP: + pz+=(int)(cos(RAD(roll))*(k.shift ? 128 : 64)); + px+=(int)(sin(RAD(roll))*(k.shift ? 128 : 64)); + break; + + case GFX_DOWN: + pz-=(int)(cos(RAD(roll))*(k.shift ? 128 : 64)); + px-=(int)(sin(RAD(roll))*(k.shift ? 128 : 64)); + break; + + case GFX_END: + pitch=0; + break; + + case GFX_PGDN: + if (k.shift) + pitch=MAX(pitch-5,-90); + else + py-=64; + break; + + case GFX_PGUP: + if (k.shift) + pitch=MIN(pitch+5,90); + else + py+=64; + break; + + case GFX_ENTER: + fade=(fade+1)%3; + break; + + default: + redraw=FALSE; + break; + } + } + + FullRedraw(); +} + + +/* END OF FILE */ diff --git a/editcord.c b/editcord.c new file mode 100644 index 0000000..6567be3 --- /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) +{ + VIDOOM_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) +{ + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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) +{ + VIDOOM_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) +{ + VIDOOM_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) +{ + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_TRACE; + + /* Check enough vertexes + */ + if (ListSize(in_v)<3) + { + GuiInfoBox("ERROR","Need 3 or more vertices|" + "to create a sector"); + 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..3d31f41 --- /dev/null +++ b/editdraw.c @@ -0,0 +1,349 @@ +/* + + 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; + + VIDOOM_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; + + VIDOOM_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 VIDOOM_DEBUG + static int chk=TRUE; + static int db=FALSE; +#endif + + VIDOOM_TRACE; + + if (hexen_mode) + GFX_frect(0,0,SCRW,FH*2,RED); + else + 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 VIDOOM_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) +{ + VIDOOM_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..c50c878 --- /dev/null +++ b/editevnt.c @@ -0,0 +1,1079 @@ +/* + + 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" +#include "platgui.h" +#include "mem.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; + + VIDOOM_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 + { + o=MapElem(map,current); + + /* Check for left click move mode + */ + if (o->select==SELECT_SELECTED && left_click_move) + MoveObject(); + 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) +{ + VIDOOM_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; + ObjectOverlaid=ObjectOverlaid_SECTOR; + 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; + ObjectOverlaid=ObjectOverlaid_LINEDEF; + 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; + ObjectOverlaid=ObjectOverlaid_VERTEX; + 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; + ObjectOverlaid=ObjectOverlaid_THING; + 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; + ObjectOverlaid=ObjectOverlaid_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; + + VIDOOM_TRACE; + + if (k.code!=GFX_ASCII) + switch(k.code) + { + case GFX_DOWN: + if (k.ctrl) + oy-=scale; + else + oy-=scale*(k.shift ? 60 : 20); + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + case GFX_UP: + if (k.ctrl) + oy+=scale; + else + oy+=scale*(k.shift ? 60 : 20); + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + case GFX_RIGHT: + if (k.ctrl) + ox+=scale; + else + ox+=scale*(k.shift ? 60 : 20); + + if (check_mouse) + GenericCheckMouse(); + + FullRedraw(); + break; + + case GFX_LEFT: + if (k.ctrl) + ox-=scale; + else + 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 VIDOOM_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; + + VIDOOM_TRACE; + + HandleMoveKey(k,TRUE); + ObjectKey(k); + + if (k.code!=GFX_ASCII) + switch(k.code) + { + case GFX_F1: + for(f=0;general_help_keys[f];f++) + { + char title[80]; + + sprintf(title,"HELP (Keys) Page %d",f+1); + GuiInfoBox(title,"%s",general_help_keys[f]); + } + + GuiInfoBox("HELP (Mouse)","%s",general_help_mouse); + break; + + case GFX_F2: + { + char s[128]; + + sprintf(s,"%s Mode Keys",typename); + GuiInfoBox(s,"%s",mode_help[edit_mode]); + 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_HOME: + if (game==ZDOOM) + EditLumpMenu(); + else + GuiInfoBox("NOTE","LUMP manipulation only|" + "applies to ZDoom mode"); + 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 if ((k.alt)||(k.ctrl)) + { + char title[128]; + char **pick; + ObjDesc *od; + int no,sel; + + od=ObjectOverlaid(XToMap(ms.x),YToMap(ms.y),&no); + + if (od) + { + pick=Grab(sizeof(char *)*(no+1)); + + 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"); + } + } + break; + + case GFX_ESC: + quit=TRUE; + break; + + default: + break; + } + else + switch(toupper(k.ascii)) + { + case '3': + EditPreview3D(); + break; + + 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) +{ + VIDOOM_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..c5f8e58 --- /dev/null +++ b/editgui.c @@ -0,0 +1,519 @@ +/* + + 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 "specials.h" + +#include + +#define TXTPMT(lr,ulm) "Pick " ulm " texture for " lr " sidedef" + + +/* ---------------------------------------- GUI FUNCTIONS +*/ +int GetTexture(char *t,DirName d) +{ + int f; + + VIDOOM_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; + + VIDOOM_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) + +{ + VIDOOM_TRACE; + + if (set_class) + { + if (hexen_mode) + { + if ((*type=SelectSpecial())==SPECIAL_NULLID) + return(FALSE); + } + else + { + 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) +{ + VIDOOM_TRACE; + + if (hexen_mode) + { + if ((*line_type=SelectSpecial())==SPECIAL_NULLID) + return(FALSE); + } + else + { + 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; + + VIDOOM_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; + GFX_bounce(); + } + + 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)); +} + + +int YesNoAll(char *fmt,...) +{ + static char s[512]; + va_list va; + + va_start(va,fmt); + vsprintf(s,fmt,va); + va_end(va); + + return(GUI_yesno_all(s)); +} + + +int GetNumber(char *prompt, int *val) +{ + PLAT_DIALOG d[1]; + int ret; + + d[0].text="Value (prefix with 0x for hex)"; + d[0].type=PLAT_DIAL_STRING; + sprintf(d[0].data.s,"%d",*val); + + if ((ret=GUI_dialog(prompt,1,d))) + *val=ATOI(d[0].data.s); + + return(ret); +} + + +/* 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..69d61a3 --- /dev/null +++ b/editline.c @@ -0,0 +1,3812 @@ +/* + + 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" +#include "genlines.h" +#include "specials.h" +#include "flags.h" +#include "util.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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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) +{ + VIDOOM_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) +{ + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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(hexen_mode))!=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[MAX_STEPS],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); + } + + /* While we're here, get all the containing sectors too + */ + in_sect[f]=SectorInBox(step.p[0][f],step.p[1][f+1]); + } + + /* 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++) + { + if (in_sect[f]!=-1) + s=GETSECT(in_sect[f]); + 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[f]==-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[f], + ((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) +{ + VIDOOM_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; + + VIDOOM_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,f; + + VIDOOM_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; + + for(f=0;f<5;f++) + l->l.args[f]=0; + + 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); +} + + +/* ---------------------------------------- HEXEN TAG RESOLVING +*/ +void SetHexenLinedefTag(EditLine *l) +{ + char *nm; + char *a[5]; + int f; + + l->l.tag=0; + + nm=SpecialName(l->l.type,a); + + if (!STREQ(nm,"UNKNOWN")) + for(f=0;f<5;f++) + if (STREQ(a[f],"tag")) + { + l->l.tag=l->l.args[f]; + f=6; + } +} + + +/* ---------------------------------------- GENERIC LINEDEF FUNCS +*/ +int PositionOnObject_LINEDEF(int x,int y,void *data) +{ + EditLine *l; + + VIDOOM_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; + + VIDOOM_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 (hexen_mode) + { + if ((id=SelectSpecial())==SPECIAL_NULLID) + id=LINEDEF_NULLID; + } + else + id=SelectLinedef(); + + + if (id!=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; + + VIDOOM_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; + char *p; + char *nm=NULL; + char *a[5]; + + VIDOOM_TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((l=GETLINE(current)))) + { + if (hexen_mode) + nm=SpecialName(l->l.type,a); + + if (show_full_linedef_info) + { + if (hexen_mode) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Special : %-35.35s|" + "%-10.10s : %-3d|" + "%-10.10s : %-3d|" + "%-10.10s : %-3d|" + "%-10.10s : %-3d|" + "%-10.10s : %-3d", + current, + FlagText(hexen_mode,LINEDEF_FLAGS, + l->l.flags), + nm, + (a[0] ? a[0] : "N/A"),l->l.args[0], + (a[1] ? a[1] : "N/A"),l->l.args[1], + (a[2] ? a[2] : "N/A"),l->l.args[2], + (a[3] ? a[3] : "N/A"),l->l.args[3], + (a[4] ? a[4] : "N/A"),l->l.args[4]); + else + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Type [%4.4x]: %-35.35s|" + "Tag : %-5d", + current, + FlagText(hexen_mode, + LINEDEF_FLAGS,l->l.flags), + l->l.type, + (p=GenLineName(hexen_mode,l->l.type, + LinedefName)) ? + p:LinedefName(l->l.type), + l->l.tag); + } + else + { + if (hexen_mode) + { + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Special : %-20.20s|" + "%-10.10s : %-3d|" + "%-10.10s : %-3d|" + "%-10.10s : %-3d|" + "%-10.10s : %-3d|" + "%-10.10s : %-3d", + current, + FlagText(hexen_mode,LINEDEF_FLAGS, + l->l.flags), + nm, + (a[0] ? a[0] : "N/A"),l->l.args[0], + (a[1] ? a[1] : "N/A"),l->l.args[1], + (a[2] ? a[2] : "N/A"),l->l.args[2], + (a[3] ? a[3] : "N/A"),l->l.args[3], + (a[4] ? a[4] : "N/A"),l->l.args[4]); + } + else + { + if (GenLineClass(hexen_mode,l->l.type,LinedefClass)) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Type [%4.4x]: %-14.14s [Gen]|" + "Tag : %-5d", + current, + FlagText(hexen_mode,LINEDEF_FLAGS, + l->l.flags), + l->l.type, + GenLineClass(hexen_mode, + l->l.type,LinedefClass), + 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, + FlagText(hexen_mode,LINEDEF_FLAGS, + 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) + if (hexen_mode) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Special : %35s|" + "- : -|" + "- : -|" + "- : -|" + "- : -|" + "- : -",""); + else + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Type : %35s|" + "Tag : -",""); + else + if (hexen_mode) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Special : %20s|" + "- : -|" + "- : -|" + "- : -|" + "- : -|" + "- : -",""); + 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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_TRACE; + + if (hexen_mode) + return; + + 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; + + VIDOOM_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; + + VIDOOM_TRACE; + + if (MapSize(vertex)<2) + GuiInfoBox("ERROR","Need more that 2 vertices|to make a line"); + 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); + ok=FALSE; + } + else if ((to>=MapSize(vertex))||(to<0)||(!GETVERT(to))) + { + GuiInfoBox("ERROR","%d (to) is an invalid vertex",to); + 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; + + VIDOOM_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; + + VIDOOM_TRACE; + + s=NULL; + cancel=FALSE; + GFX_redraw(); + + if (hexen_mode) + opt=GUI_menu("Linedef/sidedef",ms.x,ms.y, + linedef_popup_hexen,GUI_CANCEL); + else + opt=GUI_menu("Linedef/sidedef",ms.x,ms.y,linedef_popup,GUI_CANCEL); + + 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_SPECIAL: + { + Short id; + + id=(Short)SelectSpecial(); + + if (id!=SPECIAL_NULLID) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + l->l.type=id; + SetHexenLinedefTag(l); + i=IteratorNext(i); + } + + FullRedraw(); + } + break; + } + + case TM_GEN_TYPE: + if (GenLineNoClasses(hexen_mode)) + { + l=SelHead(); + f=SelectGenLine(hexen_mode,l->l.type); + + if (f!=GENLINE_NULLID) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + l->l.type=f; + i=IteratorNext(i); + } + + FullRedraw(); + } + } + else + GuiInfoBox("ERROR","No generalised linedefs defined|in config"); + break; + + case TM_VAL: + { + static int id; + + if (GetNumber("Enter LINEDEF type",&id)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + l->l.type=id; + i=IteratorNext(i); + } + + FullRedraw(); + } + } + break; + + case TM_FLAGS: + l=SelHead(); + f=l->l.flags; + + if (SelectFlags(hexen_mode,LINEDEF_FLAGS,&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); + GUI_start_yesno_all(); + + 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); + } + else if (YesNoAll("Swap one-sided linedefs?")) + { + 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); + + 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"); + 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_TEXTURES_R: + l=SelHead(); + + strcpy(textures_dialog[D_TEXTURE_U].data.s,l->sr->upper); + strcpy(textures_dialog[D_TEXTURE_M].data.s,l->sr->middle); + strcpy(textures_dialog[D_TEXTURE_L].data.s,l->sr->lower); + + if (GUI_dialog("Right textures",D_TEXTURES_NO,textures_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + strcpy(l->sr->upper,textures_dialog[D_TEXTURE_U].data.s); + strcpy(l->sr->middle,textures_dialog[D_TEXTURE_M].data.s); + strcpy(l->sr->lower,textures_dialog[D_TEXTURE_L].data.s); + + i=IteratorNext(i); + } + + i=IteratorClear(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; + } + else + { + offset_dialog[D_OFFSET_OFFX].data.i=0; + offset_dialog[D_OFFSET_OFFY].data.i=0; + } + + 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; + else + sectorn_dialog[D_SECTORN_SECNO].data.i=-1; + + 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"); + 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"); + 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_TEXTURES_L: + l=SelHead(); + + if (l->sl) + { + strcpy(textures_dialog[D_TEXTURE_U].data.s,l->sl->upper); + strcpy(textures_dialog[D_TEXTURE_M].data.s,l->sl->middle); + strcpy(textures_dialog[D_TEXTURE_L].data.s,l->sl->lower); + } + else + { + strcpy(textures_dialog[D_TEXTURE_U].data.s,""); + strcpy(textures_dialog[D_TEXTURE_M].data.s,""); + strcpy(textures_dialog[D_TEXTURE_L].data.s,""); + } + + if (GUI_dialog("Left textures",D_TEXTURES_NO,textures_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (l->sl) + { + strcpy(l->sl->upper, + textures_dialog[D_TEXTURE_U].data.s); + strcpy(l->sl->middle, + textures_dialog[D_TEXTURE_M].data.s); + strcpy(l->sl->lower, + textures_dialog[D_TEXTURE_L].data.s); + } + + i=IteratorNext(i); + } + + i=IteratorClear(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; + + case TM_ARGS: + { + int a[5]; + int id; + int diff; + + l=SelHead(); + + id=l->l.type; + + i=ListIterator(selected); + i=IteratorNext(i); + diff=FALSE; + + while((i)&&(!diff)) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (l->l.type!=id) + diff=TRUE; + + i=IteratorNext(i); + } + + if ((diff)&&(YesNo("Selected linedefs have|different types| |" + "Set individually?"))) + { + cancel=TRUE; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + id=l->l.type; + + for(f=0;f<5;f++) + a[f]=l->l.args[f]; + + if (SpecialArgDialog(NULL,id,a)) + { + for(f=0;f<5;f++) + l->l.args[f]=a[f]; + + SetHexenLinedefTag(l); + + cancel=FALSE; + } + + i=IteratorNext(i); + } + } + else + { + l=SelHead(); + + for(f=0;f<5;f++) + a[f]=l->l.args[f]; + + if (SpecialArgDialog(NULL,id,a)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + for(f=0;f<5;f++) + l->l.args[f]=a[f]; + + SetHexenLinedefTag(l); + + i=IteratorNext(i); + } + } + else + cancel=TRUE; + } + + FullRedraw(); + break; + } + + case TM_ZERO: + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + for(f=0;f<5;f++) + l->l.args[f]=0; + + l->l.tag=0; + + i=IteratorNext(i); + } + + FullRedraw(); + break; + + case TM_ARGS_RANGE: + { + int a[5]; + int d[5]; + int id; + int diff; + + l=SelHead(); + + id=l->l.type; + + i=ListIterator(selected); + i=IteratorNext(i); + diff=FALSE; + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (l->l.type!=id) + { + diff=TRUE; + i=IteratorClear(i); + } + else + i=IteratorNext(i); + } + + l=SelHead(); + + for(f=0;f<5;f++) + { + a[f]=l->l.args[f]; + d[f]=0; + } + + if ((!diff)||(YesNo("Selected linedefs have|different types| |" + "Continue?"))) + if ((SpecialArgDialog("Start values",id,a))&& + (SpecialArgDialog("Increments",id,d))) + + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + for(f=0;f<5;f++) + { + l->l.args[f]=(Byte)a[f]; + a[f]+=d[f]; + } + + SetHexenLinedefTag(l); + + i=IteratorNext(i); + } + + FullRedraw(); + } + 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; + + VIDOOM_TRACE; + + switch(k.code) + { + case GFX_F12: + li=ListNew(sizeof(int)); + + change=FALSE; + + if (ListSize(selected)==0) + { + GuiInfoBox("ERROR","No linedefs selected"); + return; + } + + i=ListIterator(selected); + + GUI_start_yesno_all(); + + while(i) + { + memcpy(&f,IteratorData(i),sizeof(f)); + + if ((l=GETLINE(f))) + { + VIDOOM_TRACE; + if (check_1side_lower) + if ((!l->sl)&&(strcmp(l->sr->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNoAll + ("LINEDEF %d is one-sided with a " + "lower texture. Remove?",f))) + { + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + + VIDOOM_TRACE; + if (check_1side_middle) + if ((!l->sl)&&(!strcmp(l->sr->middle,empty_texture))) + if ((check_line_assume_yes)|| + (YesNoAll + ("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); + } + } + + VIDOOM_TRACE; + if (check_1side_upper) + if ((!l->sl)&&(strcmp(l->sr->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNoAll + ("LINEDEF %d is one-sided with a " + "upper texture. Remove?",f))) + { + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + + VIDOOM_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)|| + (YesNoAll + ("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)|| + (YesNoAll + ("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)|| + (YesNoAll + ("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); + } + } + + VIDOOM_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)|| + (YesNoAll + ("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); + } + } + + VIDOOM_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)|| + (YesNoAll + ("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)|| + (YesNoAll + ("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)|| + (YesNoAll + ("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); + } + } + + VIDOOM_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)|| + (YesNoAll + ("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"); + + 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)); +} + + +ObjDesc *ObjectOverlaid_LINEDEF(int x, int y, int *no) +{ + int n; + EditLine *l; + ObjDesc *od; + int f; + + VIDOOM_TRACE; + + od=NULL; + + n=0; + + for(f=0;fl.type),60), + l->l.tag); + } + } + + *no=n; + return(od); +} + + +/* END OF FILE */ diff --git a/editlump.c b/editlump.c new file mode 100644 index 0000000..f55d269 --- /dev/null +++ b/editlump.c @@ -0,0 +1,330 @@ +/* + + 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 LUMP manipulations + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" +#include "platgui.h" +#include "runcmd.h" +#include "file.h" +#include "mem.h" +#include "util.h" + + +#define M_CANCEL -1 +#define M_SWITCH_DOOM 0 +#define M_SWITCH_HEXEN 1 +#define M_EDIT_MAPINFO 2 +#define M_EDIT_SCRIPTS 3 +#define M_MAKE_BEHAVIOR 4 + +static PLAT_MENU menu[6]; +static int no=0; + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static void NewMenu(void) +{ + int f; + + for(f=0;ft.z=0; + + for(r=0;r<5;r++) + t->t.args[r]=0; + } + + for(f=0;fl.tag=0; + + for(r=0;r<5;r++) + l->l.args[r]=0; + } + } + break; + + case M_EDIT_MAPINFO: + { + char *new; + + if (!mapinfo) + mapinfo=Strdup(""); + + if ((new=GUI_text_edit("MAPINFO lump",mapinfo))) + { + Release(mapinfo); + mapinfo=new; + } + break; + } + + case M_EDIT_SCRIPTS: + { + char *new; + + if (!scripts) + scripts=Strdup(""); + + if ((new=GUI_text_edit("SCRIPTS lump",scripts))) + { + Release(scripts); + scripts=new; + scripts_size=strlen(scripts); + } + break; + } + + case M_MAKE_BEHAVIOR: + if (!scripts) + GUI_alert("Error","Need to create a script by editing|" + "it before it can be compiled","OK"); + else + MakeBehavior(); + break; + } + + if (redraw) + FullRedraw(); +} + + +/* END OF FILE */ diff --git a/editmrg.c b/editmrg.c new file mode 100644 index 0000000..51197b1 --- /dev/null +++ b/editmrg.c @@ -0,0 +1,564 @@ +/* + + 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) +{ + VIDOOM_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) +{ + VIDOOM_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()); + 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()); + + 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); + + 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..c3165ca --- /dev/null +++ b/editmult.c @@ -0,0 +1,708 @@ +/* + + 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 "util.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; + + VIDOOM_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) +{ + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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) +{ + VIDOOM_TRACE; + return; +} + + +void DrawObject_MULTI(void *data, int selmode) +{ + MultiObj *m; + + VIDOOM_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; + + VIDOOM_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) +{ + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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) +{ + VIDOOM_TRACE; +} + + +void LocateObject_MULTI(void *obj) +{ + MultiObj *m; + + VIDOOM_TRACE; + + m=obj; + + ox=m->x-scale*SCRW/2; + oy=m->y+scale*SCRH/2; + +} + + +void ObjectInsert_MULTI(void) +{ + VIDOOM_TRACE; +} + + +void ObjectDelete_MULTI(void) +{ + VIDOOM_TRACE; +} + + +void ObjectMenu_MULTI(void) +{ + static double last_rot=0.0; + static double last_scale=0.0; + int cancel; + + VIDOOM_TRACE; + + cancel=FALSE; + + switch(GUI_menu("Mutlimode",ms.x,ms.y,multi_popup,GUI_CANCEL)) + { + case TM_SNAP: + { + Iterator i; + MultiObj *m; + int orig_lock; + int *s; + + orig_lock=grid_lock; + grid_lock=TRUE; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + m=GETMULTI(*s); + m->x=SnapX(m->x); + m->y=SnapX(m->y); + i=IteratorNext(i); + } + + grid_lock=orig_lock; + ApplySelectionCoords(); + FullRedraw(); + + break; + } + + case TM_MOVE: + MoveObject_MULTI(); + break; + + case TM_ROTATE: + rotate_dialog[D_ROTATE].data.d=last_rot; + + if (GUI_dialog("Rotate",D_ROTATE_NO,rotate_dialog)) + { + last_rot=rotate_dialog[D_ROTATE].data.d; + RotateObject_MULTI(-last_rot); + FullRedraw(); + } + else + cancel=TRUE; + + break; + + case TM_SCALE: + scale_dialog[D_SCALE].data.d=last_scale; + + if (GUI_dialog("Scale",D_SCALE_NO,scale_dialog)) + { + ScaleObject_MULTI(last_scale=scale_dialog[D_SCALE].data.d); + FullRedraw(); + } + else + cancel=TRUE; + + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } +} + + +void ObjectKey_MULTI(GFXKey k) +{ + VIDOOM_TRACE; +} + + +int ObjectHasTag_MULTI(void *obj, int tag) +{ + VIDOOM_TRACE; + return(FALSE); +} + + +void SetSelect_MULTI(int i, int mode) +{ + Object *o; + MultiObj *m; + Map om; + + VIDOOM_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; + } +} + + + +ObjDesc *ObjectOverlaid_MULTI(int x, int y, int *no) +{ + int n; + MultiObj *m; + EditThing *t; + EditVert *v; + ObjDesc *od; + int f; + + VIDOOM_TRACE; + + od=NULL; + + n=0; + + for(f=0;fv.x,v->v.y); + break; + + case THING: + sprintf(od[n-1].detail,"Thing %-5d - %s",f, + TrimStr(ThingName(t->t.type),29)); + break; + } + } + } + + *no=n; + return(od); +} + + + +/* END OF FILE */ diff --git a/editsect.c b/editsect.c new file mode 100644 index 0000000..3a13300 --- /dev/null +++ b/editsect.c @@ -0,0 +1,1735 @@ +/* + + 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 "gensect.h" +#include "util.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; + + VIDOOM_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) +{ + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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); +} + + +void SelectBox_SECTOR(int x1,int y1,int x2,int y2) +{ + Object *o; + EditSect *s; + int f; + + VIDOOM_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(hexen_mode))!=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; + + VIDOOM_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; + + VIDOOM_TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((s=GETSECT(current)))) + { + if (GenSectName(hexen_mode,s->s.special,SectorName)) + 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 : %-30.30s[Gen]|" + "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, + GenSectName(hexen_mode, + s->s. + special,SectorName), + s->s.tag); + else + 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 : %-35.35s|" + "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(hexen_mode,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 : %-35s|" + "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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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} + }; + + VIDOOM_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 editable.",sec); + 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"); + 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) +{ + VIDOOM_TRACE; + + GuiInfoBox("NOTICE","Sector cannot be deleted| |" + "Sectors are automatically deleted|" + "when saving the map if no LINEDEFs|" + "are bound to it."); +} + + +void ObjectMenu_SECTOR(void) +{ + Iterator i; + EditSect *s; + int *f; + int cancel; + + VIDOOM_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: + { + int sweep; + + s=SelHead(); + + if (ListSize(selected)<3) + sweep=FALSE; + else + sweep=YesNo("%d sectors selected. Do lighting sweep?", + ListSize(selected)); + + if (!sweep) + { + 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(); + } + } + else + { + static int min=0; + static int max=255; + static int bounce=FALSE; + int t_min=0,t_max=0; + int start; + int inc; + int ok; + int valid; + + start=s->s.light; + + l_range_dialog[D_L_RANGE_START].data.i=start; + l_range_dialog[D_L_RANGE_MIN].data.i=min; + l_range_dialog[D_L_RANGE_MAX].data.i=max; + + if (start<128) + { + inc=(int)((double)(max-start)/ + (double)(ListSize(selected)-2)+0.5); + + if (inc==0) + inc=SGN(max-start); + } + else + { + inc=(int)((double)(min-start)/ + (double)(ListSize(selected)-2)+0.5); + + if (inc==0) + inc=SGN(min-start); + } + + l_range_dialog[D_L_RANGE_INC].data.i=inc; + SET_YESNO_DIAL(l_range_dialog[D_L_RANGE_PULSE],bounce); + + do { + if ((ok=GUI_dialog("Lighting sweep", + D_L_RANGE_NO,l_range_dialog))) + { + inc=l_range_dialog[D_L_RANGE_INC].data.i; + start=l_range_dialog[D_L_RANGE_START].data.i; + t_min=l_range_dialog[D_L_RANGE_MIN].data.i; + t_max=l_range_dialog[D_L_RANGE_MAX].data.i; + + valid=FALSE; + + if ((t_min<0)||(t_min>255)||(t_max<0)|| + (t_max>255)||(start<0)||(start>255)) + GuiInfoBox("ERROR","Light levels must be|" + "in range 0 to 255"); + else if ((t_min>=t_max)||(t_max<=t_min)) + GuiInfoBox("ERROR","min and max make no sense"); + else if (ABS(inc)>(t_max-t_min)) + GuiInfoBox("ERROR", + "There must be enough inbetween|" + "min and max for the adjustment"); + else if ((startt_max)) + GuiInfoBox("ERROR", + "Start must inbetween min and max"); + else + valid=TRUE; + } + else + valid=TRUE; + + } while((ok)&&(!valid)); + + if (ok) + { + min=t_min; + max=t_max; + bounce=l_range_dialog[D_L_RANGE_PULSE].data.pl.current; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.light=start; + + start+=inc; + + start=MIN(start,max); + start=MAX(start,min); + + if (((start==min)||(start==max))&&(bounce)) + inc=-inc; + + 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(hexen_mode); + + 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_GEN_TYPE: + if (GenSectNoClasses(hexen_mode)) + { + int id; + + s=SelHead(); + id=SelectGenSect(hexen_mode,s->s.special); + + if (id!=GENSECT_NULLID) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.special=id; + i=IteratorNext(i); + } + + FullRedraw(); + } + } + else + GuiInfoBox("ERROR","No generalised sectors defined|in config"); + break; + + case TM_VAL: + { + static int id; + + if (GetNumber("Enter SECTOR type",&id)) + { + 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)); +} + + +ObjDesc *ObjectOverlaid_SECTOR(int x, int y, int *no) +{ + int n; + EditSect *s; + ObjDesc *od; + int f; + + VIDOOM_TRACE; + + od=NULL; + + n=0; + + for(f=0;fs.special),50), + s->s.tag); + } + } + + *no=n; + return(od); +} + + +/* END OF FILE */ diff --git a/editsel.c b/editsel.c new file mode 100644 index 0000000..2a02755 --- /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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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..c4f1bea --- /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; + + VIDOOM_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) +{ + VIDOOM_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..79d8130 --- /dev/null +++ b/editthng.c @@ -0,0 +1,1126 @@ +/* + + 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 "specials.h" +#include "flags.h" +#include "util.h" + +#include + +#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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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 ((hexen_mode)&&(YesNo("Select by special action|rather than type?"))) + { + if ((id=SelectSpecial())!=SPECIAL_NULLID) + { + ClearSelection(); + + for(f=0;fdata)&&(t->t.special==id)) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } + else + 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; + + VIDOOM_TRACE; + t=data; + + a=ANGLENUM(t->t.ang); + 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; + char *nm; + char *a[5]; + + VIDOOM_TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((ti=GETTHING(current)))) + { + if (hexen_mode) + { + nm=SpecialName(ti->t.special,a); + + GuiDrawInfoBox("THING",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Thing No : %d|" + "Thing ID : %d|" + "Z Pos : %-30d|" + "Angle : %s (%d)|" + "Flags : %s (0x%.2x)|" + "Type : %-30.30s", + current, + ti->t.id, + ti->t.z, + ANGLESTR(ti->t.ang),ti->t.ang, + FlagText(hexen_mode,THING_FLAGS, + (int)ti->t.flags),ti->t.flags, + ThingName(ti->t.type)); + + GuiDrawInfoBox("THING SPECIAL",GUI_FLUSH_RIGHT, + GUI_FLUSH_LOWER,FALSE, + "Special : %-20.20s|" + "%-10s : %-3d|" + "%-10s : %-3d|" + "%-10s : %-3d|" + "%-10s : %-3d|" + "%-10s : %-3d", + nm, + (a[0] ? a[0] : "N/A"),ti->t.args[0], + (a[1] ? a[1] : "N/A"),ti->t.args[1], + (a[2] ? a[2] : "N/A"),ti->t.args[2], + (a[3] ? a[3] : "N/A"),ti->t.args[3], + (a[4] ? a[4] : "N/A"),ti->t.args[4]); + } + else + GuiDrawInfoBox("THING",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Thing No : %d|" + "Angle : %s (%d)|" + "Flags : %s (0x%.2x)|" + "Type : %-60s", + current, + ANGLESTR(ti->t.ang),ti->t.ang, + FlagText(hexen_mode,THING_FLAGS, + (int)ti->t.flags),ti->t.flags, + ThingName(ti->t.type)); + } + else + if (hexen_mode) + { + GuiDrawInfoBox("THING",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Thing No : -|" + "Thing ID : -|" + "Z Pos : -|" + "Angle : -|" + "Flags : - (-)|" + "Type : %-30s",""); + + GuiDrawInfoBox("THING SPECIAL",GUI_FLUSH_RIGHT, + GUI_FLUSH_LOWER,FALSE, + "Special : %-20s|" + "- : -|" + "- : -|" + "- : -|" + "- : -|" + "- : -|",""); + } + else + GuiDrawInfoBox("THING",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Thing No : -|" + "Angle : -|" + "Flags : - (-)|" + "Type : %-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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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) +{ + VIDOOM_TRACE; +} + + +void LocateObject_THING(void *obj) +{ + EditThing *t; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_TRACE; + + cancel=FALSE; + GFX_redraw(); + + switch(GUI_menu("Thing",ms.x,ms.y, + (hexen_mode ? thing_popup_hexen: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_SPECIAL: + { + Short id; + + id=(Short)SelectSpecial(); + + if (id!=SPECIAL_NULLID) + { + ed_thing.special=id; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.special=id; + i=IteratorNext(i); + } + + redraw=TRUE; + } + break; + } + + case TM_THING_ID: + { + static int id; + + if (GetNumber("Enter THING ID",&id)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.id=id; + i=IteratorNext(i); + } + + redraw=TRUE; + } + break; + } + + case TM_VAL: + { + static int id; + + if (GetNumber("Enter 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_SPECIAL_VAL: + { + static int id; + + if (GetNumber("Enter THING special action",&id)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.special=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_ANGLE_VAL: + { + int a; + + t=SelHead(); + a=t->t.ang; + if (GetNumber("Enter angle value",&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.flags; + + if (SelectFlags(hexen_mode,THING_FLAGS,&f)) + { + ed_thing.flags=f; + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.flags=ed_thing.flags; + 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; + + case TM_Z_POS: + t=SelHead(); + zcoord_dialog[D_ZCOORD].data.i=t->t.z; + + if (GUI_dialog("Change Z co-ord",D_ZCOORD_NO,zcoord_dialog)) + { + ed_thing.z=zcoord_dialog[D_ZCOORD].data.i; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.z=ed_thing.z; + i=IteratorNext(i); + } + } + else + cancel=TRUE; + + redraw=TRUE; + break; + + case TM_ARGS: + { + int a[5]; + int id; + int diff; + + t=SelHead(); + + id=t->t.special; + + i=ListIterator(selected); + i=IteratorNext(i); + diff=FALSE; + + while((i)&&(!diff)) + { + s=IteratorData(i); + t=GETTHING(*s); + + if (t->t.special!=id) + diff=TRUE; + + i=IteratorNext(i); + } + + if ((diff)&&(YesNo("Selected things have|different types| |" + "Set individually?"))) + { + cancel=TRUE; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + id=t->t.special; + + for(f=0;f<5;f++) + a[f]=t->t.args[f]; + + if (SpecialArgDialog(NULL,id,a)) + { + for(f=0;f<5;f++) + t->t.args[f]=ed_thing.args[f]=a[f]; + + cancel=FALSE; + } + + i=IteratorNext(i); + } + } + else + { + t=SelHead(); + + for(f=0;f<5;f++) + a[f]=t->t.args[f]; + + if (SpecialArgDialog(NULL,id,a)) + { + for(f=0;f<5;f++) + ed_thing.args[f]=a[f]; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + + for(f=0;f<5;f++) + t->t.args[f]=ed_thing.args[f]; + + i=IteratorNext(i); + } + } + else + cancel=TRUE; + } + + redraw=TRUE; + break; + } + + case TM_ZERO: + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + + for(f=0;f<5;f++) + t->t.args[f]=0; + + i=IteratorNext(i); + } + + FullRedraw(); + break; + + case TM_ARGS_RANGE: + { + int a[5]; + int d[5]; + int id; + int diff; + + t=SelHead(); + + id=t->t.special; + + i=ListIterator(selected); + i=IteratorNext(i); + diff=FALSE; + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + + if (t->t.special!=id) + { + diff=TRUE; + i=IteratorClear(i); + } + else + i=IteratorNext(i); + } + + t=SelHead(); + + for(f=0;f<5;f++) + { + a[f]=t->t.args[f]; + d[f]=0; + } + + if ((!diff)||(YesNo("Selected things have|different types| |" + "Continue?"))) + if ((SpecialArgDialog("Start values",id,a))&& + (SpecialArgDialog("Increments",id,d))) + + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + + for(f=0;f<5;f++) + { + t->t.args[f]=(Byte)a[f]; + a[f]+=d[f]; + } + + i=IteratorNext(i); + } + + FullRedraw(); + } + break; + } + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } + else if (redraw) + FullRedraw(); +} + + +void ObjectKey_THING(GFXKey k) +{ + Iterator i; + EditThing *t; + int tmpsel; + int redraw; + int *f; + int a; + + tmpsel=TmpAddCurrent(); + redraw=FALSE; + + if (ListSize(selected)==0) + return; + + if (k.code!=GFX_ASCII) + switch(k.code) + { + default: + break; + } + else + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + + switch(toupper(k.ascii)) + { + case ',': + a=ANGLENUM(t->t.ang); + if (++a==8) + a=0; + t->t.ang=a*45; + redraw=TRUE; + break; + + case '.': + a=ANGLENUM(t->t.ang); + if (--a<0) + a=7; + t->t.ang=a*45; + redraw=TRUE; + break; + + case '<': + if (hexen_mode) + { + t->t.z--; + redraw=TRUE; + } + break; + + case '>': + if (hexen_mode) + { + t->t.z++; + redraw=TRUE; + } + break; + + default: + break; + } + + i=IteratorNext(i); + } + + } + + if (redraw) + FullRedraw(); + + if (tmpsel) + ListEmpty(selected); +} + + +int ObjectHasTag_THING(void *obj, int tag) +{ + return(FALSE); +} + + +ObjDesc *ObjectOverlaid_THING(int x, int y, int *no) +{ + int n; + EditThing *t; + ObjDesc *od; + int f; + + VIDOOM_TRACE; + + od=NULL; + + n=0; + + for(f=0;ft.type),29), + TrimStr(FlagText(hexen_mode,THING_FLAGS, + t->t.flags),19)); + } + } + + *no=n; + return(od); +} + + +/* END OF FILE */ diff --git a/editvar.c b/editvar.c new file mode 100644 index 0000000..7ed4cb9 --- /dev/null +++ b/editvar.c @@ -0,0 +1,492 @@ +/* + + 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; +char *mapinfo=NULL; +int hexen_mode=FALSE; + +char *behavior=NULL; +int behavior_size=0; +char *scripts=NULL; +int scripts_size=0; + +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; + +/* Hardcoded values!!! Remove sometime +*/ +Thing ed_thing={0,0,0,1,0x07,0,0,0,{0,0,0,0,0}}; + +/* 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); +ObjDesc *(*ObjectOverlaid)(int x,int y,int *no); + +char *typename; +Map map; + + +/* ---------------------------------------- MENUS AND DIALOGS +*/ +PLAT_MENU thing_popup[]={ + {"Change type",TM_TYPE,NULL}, + {"Set type to value",TM_VAL,NULL}, + {"Change flags",TM_FLAGS,NULL}, + {"Change angle",TM_ANGLE,NULL}, + {"Snap selected things",TM_SNAP,NULL}, + {"Move",TM_MOVE,NULL}, + {"Delete",TM_DELETE,NULL}, + {NULL,GUI_CANCEL,NULL} + }; + +PLAT_MENU thing_popup_hexen[]={ + {"Change type",TM_TYPE,NULL}, + {"Set type to value",TM_VAL,NULL}, + + {"Change special action",TM_SPECIAL,NULL}, + {"Set special action to value", + TM_SPECIAL_VAL,NULL}, + {"Change special action args",TM_ARGS,NULL}, + {"Clear special action args to zero", + TM_ZERO,NULL}, + {"Set ranged special args",TM_ARGS_RANGE,NULL}, + {"Change flags",TM_FLAGS,NULL}, + {"Change angle",TM_ANGLE,NULL}, + {"Change angle to value",TM_ANGLE_VAL,NULL}, + {"Set Z postion",TM_Z_POS,NULL}, + {"Set thing ID",TM_THING_ID,NULL}, + {"Snap",TM_SNAP,NULL}, + {"Move",TM_MOVE,NULL}, + {"Delete",TM_DELETE,NULL}, + {NULL,GUI_CANCEL,NULL} + }; + +PLAT_MENU vertex_popup[]={ + {"Chain selected vertices",TM_CHAIN,NULL}, + {"Chain selected vertices " + "into a sector",TM_CHAIN_SECTOR,NULL}, + {"Merge selected vertices",TM_MERGE,NULL}, + {"Snap",TM_SNAP,NULL}, + {"Move",TM_MOVE,NULL}, + {"Delete",TM_DELETE,NULL}, + {NULL,GUI_CANCEL,NULL} + }; + +PLAT_MENU right_popup[]= + { + {"Change upper texture",TM_UPPER_T_R,NULL}, + {"Change middle texture",TM_MIDDLE_T_R,NULL}, + {"Change lower texture",TM_LOWER_T_R,NULL}, + {"Change textures to any value",TM_TEXTURES_R}, + {"Change texture offset",TM_OFFSET_R,NULL}, + {"Adjust texture offset",TM_ADJUST_R,NULL}, + {"Change sector",TM_SECTOR_R,NULL}, + {"Align textures",TM_ALIGN_R,NULL}, + + {NULL,GUI_CANCEL,NULL} + }; + +PLAT_MENU left_popup[]= + { + {"Change upper texture",TM_UPPER_T_L,NULL}, + {"Change middle texture",TM_MIDDLE_T_L,NULL}, + {"Change lower texture",TM_LOWER_T_L,NULL}, + {"Change textures to any value",TM_TEXTURES_L}, + {"Change texture offset",TM_OFFSET_L,NULL}, + {"Adjust texture offset",TM_ADJUST_L,NULL}, + {"Change sector",TM_SECTOR_L,NULL}, + {"Align textures",TM_ALIGN_L,NULL}, + + {NULL,GUI_CANCEL,NULL} + }; + +PLAT_MENU linedef_popup[]= + { + {"Change linedef type",TM_TYPE,NULL}, + {"Set generalised linedef type",TM_GEN_TYPE,NULL}, + {"Set type to value",TM_VAL,NULL}, + {"Change linedef flags",TM_FLAGS,NULL}, + {"Swap sides",TM_SWAP_SIDES,NULL}, + {"Split line",TM_SPLIT_LINE,NULL}, + {"Select trail from this linedef",TM_TRACK_LINE,NULL}, + {"Join linedefs with steps",TM_STEPS,NULL}, + + {"Right sidedef",0,right_popup}, + {"Left sidedef",0,left_popup}, + + {"Change tag",TM_TAG,NULL}, + {"Move",TM_MOVE,NULL}, + {"Delete",TM_DELETE,NULL}, + {NULL,GUI_CANCEL,NULL} + }; + +PLAT_MENU linedef_popup_hexen[]= + { + {"Change special action",TM_SPECIAL,NULL}, + {"Set special action to value",TM_VAL,NULL}, + {"Change special action args",TM_ARGS,NULL}, + {"Clear special action args to zero",TM_ZERO,NULL}, + {"Set ranged special args",TM_ARGS_RANGE,NULL}, + {"Change linedef flags",TM_FLAGS,NULL}, + {"Swap sides",TM_SWAP_SIDES,NULL}, + {"Split line",TM_SPLIT_LINE,NULL}, + {"Select trail from this linedef",TM_TRACK_LINE,NULL}, + {"Join linedefs with steps",TM_STEPS,NULL}, + + {"Right sidedef",0,right_popup}, + {"Left sidedef",0,left_popup}, + + {"Move",TM_MOVE,NULL}, + {"Delete",TM_DELETE,NULL}, + {NULL,GUI_CANCEL,NULL} + }; + +PLAT_MENU sector_popup[]= + { + {"Change type",TM_TYPE,NULL}, + {"Change generalised type",TM_GEN_TYPE,NULL}, + {"Set type to value",TM_VAL,NULL}, + {"Change floor height",TM_FLOOR,NULL}, + {"Change ceiling height",TM_CEILING,NULL}, + {"Change light level",TM_LIGHT,NULL}, + {"Change tag",TM_TAG,NULL}, + {"Change floor",TM_FLOOR_T,NULL}, + {"Change ceiling",TM_CEILING_T,NULL}, + {"Paint sector in style",TM_STYLE,NULL}, + + {"Move",TM_MOVE,NULL}, + {"Delete",TM_DELETE,NULL}, + {NULL,GUI_CANCEL,NULL} + }; + +PLAT_MENU multi_popup[]= + { + {"Snap",TM_SNAP,NULL}, + {"Rotate",TM_ROTATE,NULL}, + {"Scale",TM_SCALE,NULL}, + {"Move",TM_MOVE,NULL}, + {NULL,GUI_CANCEL,NULL} + }; + + +PLAT_RADIO thing_angle[]={ + {"N",90}, + {"NE",45}, + {"E",0}, + {"SE",315}, + {"S",270}, + {"SW",225}, + {"W",180}, + {"NW",135}, + {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}}, + }; + +PLAT_DIALOG zcoord_dialog[D_COORD_NO]= + { + {"Z co-ord",PLAT_DIAL_INTEGER,{0}}, + }; + + +PLAT_DIALOG l_range_dialog[D_L_RANGE_NO]= + { + {"Starting light level", + PLAT_DIAL_INTEGER,{0}}, + {"Minimum light level", + PLAT_DIAL_INTEGER,{0}}, + {"Maximum light level", + PLAT_DIAL_INTEGER,{0}}, + {"Lighting adjustment", + PLAT_DIAL_INTEGER,{0}}, + {"Pulse",PLAT_DIAL_PICKLIST,{0}}, + }; + +PLAT_DIALOG textures_dialog[D_TEXTURES_NO]= + { + {"Upper",PLAT_DIAL_STRING,{0}}, + {"Middle",PLAT_DIAL_STRING,{0}}, + {"Lower",PLAT_DIAL_STRING,{0}}, + }; + + +/* Generic yes/no dialog picklist array +*/ +char *edit_dial_picklist_yes_no[2]={"No","Yes"}; + + + +/* ---------------------------------------- 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 |" + "Ctrl + Cursor keys - move by one scale position |" + "Page down/up - zoom in/out |" + "Q/W - decrease/increase grid scale |" + "G - grid 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) |" + "Ctrl + F10 - select one from a number of |" + " overlaid objects |" + "Alt + F10 - additionally select one |" + " overlaid object |" + "F11/Shift + F11 - locate next/previous selection ", + + "Insert - insert new object |" + "Delete - delete selected objects |" + "Home - LUMP menu (ZDoom only) |" + "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 by 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 ", + + NULL + }; + +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 + */ + ", - rotate THINGs angle anti-clockwise |" + ". - rotate THINGs angle clockwise |" + "< - decrement THING Z co-ord (Hexen only) |" + "> - increment THING Z co-ord (Hexen only) ", + + /* MULTI + */ + "No additional key functions" + }; + + +/* END OF FILE */ diff --git a/editvar.h b/editvar.h new file mode 100644 index 0000000..dfb1173 --- /dev/null +++ b/editvar.h @@ -0,0 +1,701 @@ +/* + + 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 VIDOOM_EDITVAR_H + +#define VIDOOM_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; + +typedef struct + { + int no; + char detail[128]; + } ObjDesc; + + +/* ---------------------------------------- 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 char *mapinfo; +extern int hexen_mode; + +extern char *behavior; +extern int behavior_size; +extern char *scripts; +extern int scripts_size; + +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 ObjDesc *(*ObjectOverlaid)(int x,int y,int *no); + +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 +#define TM_ROTATE 37 +#define TM_SCALE 38 +#define TM_Z_POS 39 +#define TM_ARGS 40 +#define TM_GEN_TYPE 41 +#define TM_VAL 42 +#define TM_TEXTURES_L 43 +#define TM_TEXTURES_R 44 +#define TM_ZERO 45 +#define TM_SPECIAL 46 +#define TM_SPECIAL_VAL 47 +#define TM_THING_ID 48 +#define TM_ANGLE_VAL 49 +#define TM_ARGS_RANGE 50 + + +extern PLAT_MENU thing_popup[]; +extern PLAT_MENU thing_popup_hexen[]; + +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 linedef_popup_hexen[]; + +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]; + + +#define D_ZCOORD_NO 1 +#define D_ZCOORD 0 +extern PLAT_DIALOG zcoord_dialog[D_COORD_NO]; + + +#define D_L_RANGE_NO 5 +#define D_L_RANGE_START 0 +#define D_L_RANGE_MIN 1 +#define D_L_RANGE_MAX 2 +#define D_L_RANGE_INC 3 +#define D_L_RANGE_PULSE 4 /* NOTE: This is a picklist */ +extern PLAT_DIALOG l_range_dialog[D_L_RANGE_NO]; + + +#define D_TEXTURES_NO 3 +#define D_TEXTURE_U 0 +#define D_TEXTURE_M 1 +#define D_TEXTURE_L 2 +extern PLAT_DIALOG textures_dialog[D_TEXTURES_NO]; + + + + +/* Use these macros to set yes/no dialog picklist entries up + d - dialog entry to set + s - TRUE == Yes, FALSE == No +*/ +extern char *edit_dial_picklist_yes_no[2]; + +#define SET_YESNO_DIAL(d,s) \ + do { \ + d.data.pl.no=2; \ + d.data.pl.current=(s ? 1:0); \ + d.data.pl.text=edit_dial_picklist_yes_no; \ + } while(0); + + + +/* ---------------------------------------- DRAWING TABLES +*/ +extern Point t_arrow[8]; + +extern char *angle_str[8]; + +/* #define ANGLENUM(a) ((((a)&0xff)+22)/45%8) */ +#define ANGLENUM(a) (((a)+22)/45%8) +#define ANGLESTR(a) (angle_str[ANGLENUM(a)]) + +/* ---------------------------------------- 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,...); +int YesNoAll(char *fmt,...); +int GetNumber(char *prompt, int *val); + +/* 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 EditPreview3D(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); +ObjDesc *ObjectOverlaid_VERTEX(int x,int y,int *no); + +void SetHexenLinedefTag(EditLine *l); +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); +ObjDesc *ObjectOverlaid_LINEDEF(int x,int y,int *no); + +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); +ObjDesc *ObjectOverlaid_THING(int x,int y,int *no); + +/* 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); +ObjDesc *ObjectOverlaid_SECTOR(int x,int y,int *no); + +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); +ObjDesc *ObjectOverlaid_MULTI(int x,int y,int *no); + + +void EditLumpMenu(void); + +#endif + +/* END OF FILE */ diff --git a/editvert.c b/editvert.c new file mode 100644 index 0000000..361aa00 --- /dev/null +++ b/editvert.c @@ -0,0 +1,834 @@ +/* + + 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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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) +{ + VIDOOM_TRACE; +} + + +void LocateObject_VERTEX(void *obj) +{ + EditVert *v; + + VIDOOM_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; + + VIDOOM_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; + + VIDOOM_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"); +} + + +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; + + VIDOOM_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"); + 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"); + 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++; + } + } + } + + FullRedraw(); + GFX_redraw(); + + GuiInfoBox("NOTICE","Deleted %d vertices",n); + + break; + + default: + break; + } +} + + +int ObjectHasTag_VERTEX(void *obj, int tag) +{ + return(FALSE); +} + + +ObjDesc *ObjectOverlaid_VERTEX(int x, int y, int *no) +{ + int n; + EditVert *v; + ObjDesc *od; + int f; + + VIDOOM_TRACE; + + od=NULL; + + n=0; + + for(f=0;fv.x,v->v.y); + } + } + + *no=n; + return(od); +} + + +/* END OF FILE */ diff --git a/file.h b/file.h new file mode 100644 index 0000000..10f87b0 --- /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 VIDOOM_FILE_H + +#define VIDOOM_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/flags.c b/flags.c new file mode 100644 index 0000000..08ed020 --- /dev/null +++ b/flags.c @@ -0,0 +1,203 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Generic flag handling. Used for THING and LINEDEF flags + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "platgui.h" +#include "flags.h" +#include "mem.h" +#include "list.h" + + +/* ---------------------------------------- TYPES AND VARS +*/ +typedef struct + { + int group; + int mask1; + int mask2; + char *name; + char flag[2]; + } Flag; + +static List list[2][2]; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static int Index(int hexen) +{ + if (hexen) + return(1); + else + return(0); +} + +static int IsSet(Flag *f,int v) +{ + v&=f->mask1; + return(v==f->mask2); +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +void FlagAdd(int hexen, int class, int group, + char *name, int mask1, int mask2, char flag) +{ + Flag f; + Iterator i; + Flag *pf; + + hexen=Index(hexen); + + if (!(list[hexen][class])) + list[hexen][class]=ListNew(sizeof(Flag)); + + f.name=Strdup(name); + f.mask1=mask1; + f.mask2=mask2; + f.flag[0]=flag; + f.flag[1]=0; + f.group=group; + + i=ListIterator(list[hexen][class]); + + while(i) + { + pf=IteratorData(i); + + if ((pf->mask1==mask1)&&(pf->mask2==mask2)) + { + Release(pf->name); + IteratorUpdate(i,&f); + IteratorClear(i); + return; + } + + i=IteratorNext(i); + } + + ListAppend(list[hexen][class],&f); +} + + +int SelectFlags(int hexen, int class, int *flags) +{ + static char *title[]={"THING FLAGS","LINEDEF FLAGS"}; + PLAT_MULTI *p; + Flag *pf; + int no; + int f; + Iterator i; + int res; + + hexen=Index(hexen); + + no=ListSize(list[hexen][class]); + p=Grab(sizeof(PLAT_MULTI)*(no+1)); + + i=ListIterator(list[hexen][class]); + + for(f=0;fname; + p[f].group=pf->group; + } + + p[f].text=NULL; + + if (GUI_multi_box(title[class],p)) + { + i=ListIterator(list[hexen][class]); + + for(f=0;fmask1); + } + + i=ListIterator(list[hexen][class]); + + for(f=0;fmask2; + } + + res=TRUE; + } + else + res=FALSE; + + Release(p); + return(res); +} + + +char *FlagText(int hexen, int class, int flags) +{ + static char s[128]; + Flag *pf; + Iterator i; + + hexen=Index(hexen); + + i=ListIterator(list[hexen][class]); + strcpy(s,""); + + while(i) + { + pf=IteratorData(i); + + if (IsSet(pf,flags)) + { + /* + if (s[0]) + strcat(s,","); + */ + + strcat(s,pf->flag); + } + + i=IteratorNext(i); + } + + return(s); +} + + +/* END OF FILE */ diff --git a/flags.h b/flags.h new file mode 100644 index 0000000..6db4f29 --- /dev/null +++ b/flags.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 + + ------------------------------------------------------------------------- + + Generic flag handling. Used for THING and LINEDEF flags + + $Id$ + +*/ + +#ifndef VIDOOM_FLAGS_H + +#define VIDOOM_FLAGS_H + +/* In all the following calls: + + - Set hexen to TRUE if editting or defining for HEXEN mode + - Set class to either THING_FLAGS or LINEDEF_FLAGS + +*/ + + +/* The different flag sets +*/ +#define THING_FLAGS 0 +#define LINEDEF_FLAGS 1 + + +/* Add a new flag +*/ +void FlagAdd(int hexen, int class, int group, + char *name, int mask1, int mask2, char flag); + + +/* Allows deinfition of flags. Returns TRUE if accepted, FALSE is cancelled. +*/ +int SelectFlags(int hexen, int class, int *flags); + + +/* Return a static string representing the meaning of the passed in flags +*/ +char *FlagText(int hexen, int class, int flags); + + +#endif + + +/* END OF FILE */ diff --git a/gdb.ini b/gdb.ini new file mode 100644 index 0000000..26f2e6b --- /dev/null +++ b/gdb.ini @@ -0,0 +1 @@ +dir djgpp diff --git a/genlines.c b/genlines.c new file mode 100644 index 0000000..98ca1dd --- /dev/null +++ b/genlines.c @@ -0,0 +1,460 @@ +/* + + 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 generalised LINEDEFs + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "platgui.h" +#include "gfx.h" +#include "platgui.h" +#include "genlines.h" +#include "mem.h" +#include "map.h" +#include "linedefs.h" + + +/* ---------------------------------------- TYPES AND VARS +*/ +typedef struct + { + char *name; + char *abbrev; + int val; + } gl_BitField; + +typedef struct + { + int i; + + char *name; + int no; + gl_BitField *bf; + } gl_BitMask; + +typedef struct + { + int mask; + int shift; + gl_BitMask *bm; + } gl_ClassBitMask; + +typedef struct + { + int i; + + char *name; + int hi; + int lo; + int no; + int mask; + gl_ClassBitMask *bm; + + PLAT_DIALOG *dial; + } gl_Class; + + +static Map mask_map=NULL; +static Map class_map[2]={NULL,NULL}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static int Index(int for_hexen) +{ + if (for_hexen) + return(1); + else + return(0); +} + + +static gl_BitMask *GetMask(char *class) +{ + gl_BitMask *m; + int f; + + for(f=0;fname))) + return(m); + } + + return(NULL); +} + + +static gl_Class *GetClass(int i,char *class) +{ + gl_Class *c; + int f; + + for(f=0;fname))) + return(c); + } + + return(NULL); +} + + +static gl_Class *ClassMenu(int i) +{ + static PLAT_MENU *menu[2]={NULL,NULL}; + gl_Class *cl; + int f,x,y; + + if (!menu[i]) + { + menu[i]=Grab(sizeof(PLAT_MENU)*(MapSize(class_map[i])+1)); + + for(f=0;fname; + menu[i][f].client_index=f; + menu[i][f].child=NULL; + } + + menu[i][f].text=NULL; + } + + GFX_mouse(&x,&y); + f=GUI_menu("Generalised LINEDEF type",x,y,menu[i],GENLINE_NULLID); + + if (f==GENLINE_NULLID) + return(NULL); + else + return(MapElem(class_map[i],f)); +} + + +static void InitDialog(gl_Class *cl, int type) +{ + int f,r; + int mask; + + /* Create the dialog if not already done so + */ + if (!cl->dial) + { + if (cl->i!=cl->no) + GFX_exit(EXIT_FAILURE, + "Not all bitfields defined for class:\n %s\n",cl->name); + + cl->dial=Grab(sizeof(PLAT_DIALOG)*cl->no); + + for(f=0;fno;f++) + { + cl->dial[f].text=cl->bm[f].bm->name; + cl->dial[f].type=PLAT_DIAL_PICKLIST; + + cl->dial[f].data.pl.no=cl->bm[f].bm->no; + cl->dial[f].data.pl.current=0; + cl->dial[f].data.pl.text=Grab(cl->bm[f].bm->no*sizeof(char *)); + + for(r=0;rbm[f].bm->no;r++) + cl->dial[f].data.pl.text[r]=Strdup(cl->bm[f].bm->bf[r].name); + } + } + + /* Set the flags from the current value + */ + for(f=0;fno;f++) + { + cl->dial[f].data.pl.current=0; + + mask=(type>>cl->bm[f].shift)&cl->bm[f].mask; + + for(r=0;rbm[f].bm->no;r++) + if (cl->bm[f].bm->bf[r].val==mask) + cl->dial[f].data.pl.current=r; + } +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +void GenLineNewBitClass(char *class, int no_fields) +{ + gl_BitMask *bm; + + bm=Grab(sizeof(gl_BitMask)); + + if (!mask_map) + mask_map=MapNew(sizeof(gl_BitMask)); + + bm->name=Strdup(class); + bm->no=no_fields; + bm->i=0; + bm->bf=Grab(sizeof(gl_BitField)*bm->no); + + MapAdd(mask_map,-1,bm); +} + + +void GenLineAddBitmask(char *class, char *name, char *abbrev, int mask) +{ + gl_BitField *bf; + gl_BitMask *bm; + + if (!(bm=GetMask(class))) + GFX_exit(EXIT_FAILURE,"Adding bit field:\n%s\n\nfailed as " + "there is no bitmask:\n%s\n",name,class); + + if (bm->i==bm->no) + GFX_exit(EXIT_FAILURE,"Adding bit field:\n%s\n\n " + "overflows bitmask:\n%s\n",name,class); + + bf=&(bm->bf[bm->i++]); + + bf->name=Strdup(name); + bf->abbrev=Strdup(abbrev); + bf->val=mask; +} + + +void GenLineNewClass(int for_hexen, char *class, + int lo, int hi, int mask, int no_bitmasks) +{ + gl_Class *cl; + int i; + + i=Index(for_hexen); + + cl=Grab(sizeof(gl_Class)); + + if (!class_map[i]) + class_map[i]=MapNew(sizeof(gl_Class)); + + cl->name=Strdup(class); + cl->hi=hi; + cl->lo=lo; + cl->mask=mask; + cl->no=no_bitmasks; + cl->i=0; + cl->bm=Grab(sizeof(gl_ClassBitMask)*cl->no); + cl->dial=NULL; + + MapAdd(class_map[i],-1,cl); +} + + +void GenLineAdd(int for_hexen, char *class, char *bitmask, int shift) +{ + gl_Class *cl; + gl_BitMask *bm; + int f; + int i; + + i=Index(for_hexen); + + if (!(bm=GetMask(bitmask))) + GFX_exit(EXIT_FAILURE,"Adding bitmask:\n%s\n\nto class:\n%s\n\n" + "failed as there is no such bitmask class\n\n", + bitmask,class); + + if (bm->i!=bm->no) + GFX_exit(EXIT_FAILURE,"Adding bitmask:\n%s\n\nto class:\n%s\n\n" + "failed as not all fields have been defined " + "in the bitmask\n\n", + bitmask,class); + + if (!(cl=GetClass(i,class))) + GFX_exit(EXIT_FAILURE,"Adding bitmask:\n%s\n\nto class:\n%s\n\n" + "failed as there is no such class\n\n", + bitmask,class); + + if (cl->i==cl->no) + GFX_exit(EXIT_FAILURE,"Adding bitmask:\n%s\n\nto class:\n%s\n\n" + "overflows class\n\n", + bitmask,class); + + cl->bm[cl->i].bm=bm; + cl->bm[cl->i].shift=shift; + cl->bm[cl->i].mask=0; + + for(f=0;fbm[cl->i].bm->no;f++) + cl->bm[cl->i].mask|=cl->bm[cl->i].bm->bf[f].val; + + cl->i++; +} + + +int SelectGenLine(int for_hexen, int current_type) +{ + gl_Class *cl; + int n; + int f; + int i; + + i=Index(for_hexen); + + if (MapSize(class_map[i])==0) + return(GENLINE_NULLID); + + if (MapSize(class_map[i])==1) + cl=MapElem(class_map[i],0); + else + if (!(cl=ClassMenu(i))) + return(GENLINE_NULLID); + + InitDialog(cl,current_type); + + if (GUI_dialog(cl->name,cl->no,cl->dial)) + { + if (cl->mask!=-1) + n=cl->mask; + else + { + n=current_type; + + for(f=0;fno;f++) + n&=~(cl->bm[f].mask<bm[f].shift); + } + + for(f=0;fno;f++) + n|=(cl->bm[f].bm->bf[cl->dial[f].data.pl.current].val) + <bm[f].shift; + } + else + n=GENLINE_NULLID; + + return(n); +} + + +char *GenLineName(int for_hexen, int id,char *(*GetName)(int id)) +{ + static char s[512]; + gl_Class *cl; + int f,r,i; + int got; + int mask; + int index; + + index=Index(for_hexen); + + for(f=0;f=cl->lo)&&(id<=cl->hi)) + { + s[0]=0; + + for(r=0;rno;r++) + { + if (r) + strcat(s,"/"); + + mask=(id>>cl->bm[r].shift)&cl->bm[r].mask; + + got=FALSE; + + for(i=0;(ibm[r].bm->no)&&(!got);i++) + if (mask==cl->bm[r].bm->bf[i].val) + { + strcat(s,cl->bm[r].bm->bf[i].abbrev); + got=TRUE; + } + + if (!got) + strcat(s,"???"); + } + + if (cl->mask==-1) + { + for(f=0;fno;f++) + id&=~(cl->bm[f].mask<bm[f].shift); + + if (GetName(id)) + { + strcat(s," & "); + strcat(s,GetName(id)); + } + } + + return(s); + } + } + + return(NULL); +} + + +char *GenLineClass(int for_hexen, int id,char *(*GetClass)(int id)) +{ + static char s[512]; + gl_Class *cl; + int f; + int i; + + i=Index(for_hexen); + + for(f=0;f=cl->lo)&&(id<=cl->hi)) + { + strcpy(s,cl->name); + + if (cl->mask==-1) + { + for(f=0;fno;f++) + id&=~(cl->bm[f].mask<bm[f].shift); + + if (GetClass(id)) + { + strcat(s," & "); + strcat(s,GetClass(id)); + } + } + + return(s); + } + } + + return(NULL); +} + + + +int GenLineNoClasses(int for_hexen) +{ + return(MapSize(class_map[Index(for_hexen)])); +} + + +/* END OF FILE */ diff --git a/genlines.h b/genlines.h new file mode 100644 index 0000000..1fc6bfb --- /dev/null +++ b/genlines.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 + + ------------------------------------------------------------------------- + + Handles definition and storage of the supported generalised LINEDEFs + + $Id$ + +*/ + +#ifndef VIDOOM_GENLINES_H + +#define VIDOOM_GENLINES_H + +/* This is not going to be an ID, so is used to detect whether LinedefSelect() + was cancelled. +*/ +#define GENLINE_NULLID -666 + + +/* Add a new class of bitmask +*/ +void GenLineNewBitClass(char *class, int no_fields); + +/* Add a bitmask to a defined class +*/ +void GenLineAddBitmask(char *class, char *name, char *abbrev, int mask); + + +/* Define a generalised linedef type class +*/ +void GenLineNewClass(int for_hexen,char *class, + int lo, int hi, int mask, int no_bitmasks); + +/* Add the named bitmask to the supplied class +*/ +void GenLineAdd(int for_hexen, char *class,char *bitmask, int shift); + + +/* Selects a generalised linedef type, returning the bit fields or + GENLINE_NULLID if cancelled +*/ +int SelectGenLine(int for_hexen, int current_type); + + +/* Returns the full name of a generalised linedef type. If the generalised + type is added to a normal linedef type the passed function GetName is + used to get the name for that part. +*/ +char *GenLineName(int for_hexen, int id,char *(*GetName)(int id)); + + +/* Returns the class name of a generalised linedef type. If the generalised + type is added to a normal linedef type the passed function GetClass is + used to get the class for that part. +*/ +char *GenLineClass(int for_hexen, int id,char *(*GetClass)(int id)); + + +/* Returns the number of classes defined +*/ +int GenLineNoClasses(int for_hexen); + + +#endif + + +/* END OF FILE */ diff --git a/gensect.c b/gensect.c new file mode 100644 index 0000000..74cbafa --- /dev/null +++ b/gensect.c @@ -0,0 +1,423 @@ +/* + + 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 generalised SECTOR types. + Basically a copy of genlines.c. + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "platgui.h" +#include "gfx.h" +#include "platgui.h" +#include "gensect.h" +#include "mem.h" +#include "map.h" + + +/* ---------------------------------------- TYPES AND VARS +*/ +typedef struct + { + char *name; + char *abbrev; + int val; + } gs_BitField; + +typedef struct + { + int i; + + char *name; + int no; + gs_BitField *bf; + } gs_BitMask; + +typedef struct + { + int mask; + int shift; + gs_BitMask *bm; + } gs_ClassBitMask; + +typedef struct + { + int i; + + char *name; + int hi; + int lo; + int mask; + int no; + gs_ClassBitMask *bm; + + PLAT_DIALOG *dial; + } gs_Class; + + +static Map mask_map=NULL; +static Map class_map[2]={NULL,NULL}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static int Index(int for_hexen) +{ + if (for_hexen) + return(1); + else + return(0); +} + + +static gs_BitMask *GetMask(char *class) +{ + gs_BitMask *m; + int f; + + for(f=0;fname))) + return(m); + } + + return(NULL); +} + + +static gs_Class *GetClass(int index, char *class) +{ + gs_Class *c; + int f; + + for(f=0;fname))) + return(c); + } + + return(NULL); +} + + +static gs_Class *ClassMenu(int index) +{ + static PLAT_MENU *menu[2]={NULL,NULL}; + gs_Class *cl; + int f,x,y; + + if (!menu[index]) + { + menu[index]=Grab(sizeof(PLAT_MENU)*(MapSize(class_map[index])+1)); + + for(f=0;fname; + menu[index][f].client_index=f; + menu[index][f].child=NULL; + } + + menu[index][f].text=NULL; + } + + GFX_mouse(&x,&y); + f=GUI_menu("Generalised SECTOR type",x,y,menu[index],GENSECT_NULLID); + + if (f==GENSECT_NULLID) + return(NULL); + else + return(MapElem(class_map[index],f)); +} + + +static void InitDialog(gs_Class *cl, int type) +{ + int f,r; + int mask; + + /* Create the dialog if not already done so + */ + if (!cl->dial) + { + if (cl->i!=cl->no) + GFX_exit(EXIT_FAILURE, + "Not all bitfields defined for class:\n %s\n",cl->name); + + cl->dial=Grab(sizeof(PLAT_DIALOG)*cl->no); + + for(f=0;fno;f++) + { + cl->dial[f].text=cl->bm[f].bm->name; + cl->dial[f].type=PLAT_DIAL_PICKLIST; + + cl->dial[f].data.pl.no=cl->bm[f].bm->no; + cl->dial[f].data.pl.current=0; + cl->dial[f].data.pl.text=Grab(cl->bm[f].bm->no*sizeof(char *)); + + for(r=0;rbm[f].bm->no;r++) + cl->dial[f].data.pl.text[r]=Strdup(cl->bm[f].bm->bf[r].name); + } + } + + /* Set the flags from the current value + */ + for(f=0;fno;f++) + { + cl->dial[f].data.pl.current=0; + + mask=(type>>cl->bm[f].shift)&cl->bm[f].mask; + + for(r=0;rbm[f].bm->no;r++) + if (cl->bm[f].bm->bf[r].val==mask) + cl->dial[f].data.pl.current=r; + } +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +void GenSectNewBitClass(char *class, int no_fields) +{ + gs_BitMask *bm; + + bm=Grab(sizeof(gs_BitMask)); + + if (!mask_map) + mask_map=MapNew(sizeof(gs_BitMask)); + + bm->name=Strdup(class); + bm->no=no_fields; + bm->i=0; + bm->bf=Grab(sizeof(gs_BitField)*bm->no); + + MapAdd(mask_map,-1,bm); +} + + +void GenSectAddBitmask(char *class, char *name, char *abbrev, int mask) +{ + gs_BitField *bf; + gs_BitMask *bm; + + if (!(bm=GetMask(class))) + GFX_exit(EXIT_FAILURE,"Adding bit field:\n%s\n\nfailed as " + "there is no bitmask:\n%s\n",name,class); + + if (bm->i==bm->no) + GFX_exit(EXIT_FAILURE,"Adding bit field:\n%s\n\n " + "overflows bitmask:\n%s\n",name,class); + + bf=&(bm->bf[bm->i++]); + + bf->name=Strdup(name); + bf->abbrev=Strdup(abbrev); + bf->val=mask; +} + + +void GenSectNewClass(int for_hexen, char *class, + int lo, int hi, int mask, int no_bitmasks) +{ + gs_Class *cl; + int i; + + i=Index(for_hexen); + + cl=Grab(sizeof(gs_Class)); + + if (!class_map[i]) + class_map[i]=MapNew(sizeof(gs_Class)); + + cl->name=Strdup(class); + cl->hi=hi; + cl->lo=lo; + cl->mask=mask; + cl->no=no_bitmasks; + cl->i=0; + cl->bm=Grab(sizeof(gs_ClassBitMask)*cl->no); + cl->dial=NULL; + + MapAdd(class_map[i],-1,cl); +} + + +void GenSectAdd(int for_hexen, char *class, char *bitmask, int shift) +{ + gs_Class *cl; + gs_BitMask *bm; + int f; + int i; + + i=Index(for_hexen); + + if (!(bm=GetMask(bitmask))) + GFX_exit(EXIT_FAILURE,"Adding bitmask:\n%s\n\nto class:\n%s\n\n" + "failed as there is no such bitmask class\n\n", + bitmask,class); + + if (bm->i!=bm->no) + GFX_exit(EXIT_FAILURE,"Adding bitmask:\n%s\n\nto class:\n%s\n\n" + "failed as not all fields have been defined " + "in the bitmask\n\n", + bitmask,class); + + if (!(cl=GetClass(i,class))) + GFX_exit(EXIT_FAILURE,"Adding bitmask:\n%s\n\nto class:\n%s\n\n" + "failed as there is no such class\n\n", + bitmask,class); + + if (cl->i==cl->no) + GFX_exit(EXIT_FAILURE,"Adding bitmask:\n%s\n\nto class:\n%s\n\n" + "overflows class\n\n", + bitmask,class); + + cl->bm[cl->i].bm=bm; + cl->bm[cl->i].shift=shift; + cl->bm[cl->i].mask=0; + + for(f=0;fbm[cl->i].bm->no;f++) + cl->bm[cl->i].mask|=cl->bm[cl->i].bm->bf[f].val; + + cl->i++; +} + + +int SelectGenSect(int for_hexen, int current_type) +{ + gs_Class *cl; + int n; + int f; + int i; + + i=Index(for_hexen); + + if (MapSize(class_map[i])==0) + return(GENSECT_NULLID); + + if (MapSize(class_map[i])==1) + cl=MapElem(class_map[i],0); + else + if (!(cl=ClassMenu(i))) + return(GENSECT_NULLID); + + InitDialog(cl,current_type); + + if (GUI_dialog(cl->name,cl->no,cl->dial)) + { + if (cl->mask!=-1) + n=cl->mask; + else + { + n=current_type; + + for(f=0;fno;f++) + n&=~(cl->bm[f].mask<bm[f].shift); + } + + for(f=0;fno;f++) + n|=(cl->bm[f].bm->bf[cl->dial[f].data.pl.current].val) + <bm[f].shift; + } + else + n=GENSECT_NULLID; + + return(n); +} + + +char *GenSectName(int for_hexen, int id,char *(*GetName)(int hexen, int id)) +{ + static char s[512]; + gs_Class *cl; + int f,r,i; + int got; + int mask; + int index; + + index=Index(for_hexen); + + for(f=0;f=cl->lo)&&(id<=cl->hi)) + { + s[0]=0; + + for(r=0;rno;r++) + { + if (r) + strcat(s,"/"); + + mask=(id>>cl->bm[r].shift)&cl->bm[r].mask; + + got=FALSE; + + for(i=0;(ibm[r].bm->no)&&(!got);i++) + if (mask==cl->bm[r].bm->bf[i].val) + { + strcat(s,cl->bm[r].bm->bf[i].abbrev); + got=TRUE; + } + + if (!got) + strcat(s,"???"); + } + + if (cl->mask==-1) + { + for(f=0;fno;f++) + id&=~(cl->bm[f].mask<bm[f].shift); + + if (GetName(for_hexen,id)) + { + strcat(s," & "); + strcat(s,GetName(for_hexen,id)); + } + } + + + return(s); + } + } + + return(NULL); +} + + +int GenSectNoClasses(int for_hexen) +{ + return(MapSize(class_map[Index(for_hexen)])); +} + + +/* END OF FILE */ diff --git a/gensect.h b/gensect.h new file mode 100644 index 0000000..deba763 --- /dev/null +++ b/gensect.h @@ -0,0 +1,80 @@ +/* + + 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 generalised SECTORs + + $Id$ + +*/ + +#ifndef VIDOOM_GENSECT_H + +#define VIDOOM_GENSECT_H + +/* This is not going to be an ID, so is used to detect whether SelectGenSect() + was cancelled. +*/ +#define GENSECT_NULLID -666 + + +/* Add a new class of bitmask +*/ +void GenSectNewBitClass(char *class, int no_fields); + +/* Add a bitmask to a defined class +*/ +void GenSectAddBitmask(char *class, char *name, char *abbrev, int mask); + + +/* Define a generalised linedef type class +*/ +void GenSectNewClass(int for_hexen, char *class, + int lo, int hi, int mask, int no_bitmasks); + +/* Add the named bitmask to the supplied class +*/ +void GenSectAdd(int for_hexen,char *class,char *bitmask, int shift); + + +/* Selects a generalised linedef type, returning the bit fields or + GENSECT_NULLID if cancelled +*/ +int SelectGenSect(int for_hexen,int current_type); + + +/* Returns the full name of a generalised sector type. If the generalised + type is added to a normal linedef type the passed function GetName is + used to get the name for that part. +*/ +char *GenSectName(int for_hexem, int id, + char *(*GetName)(int hexen, int id)); + + +/* Returns the number of classes defined +*/ +int GenSectNoClasses(int for_hexen); + + +#endif + + +/* END OF FILE */ diff --git a/gfx.h b/gfx.h new file mode 100644 index 0000000..790838d --- /dev/null +++ b/gfx.h @@ -0,0 +1,319 @@ +/* + + 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 VIDOOM_GFX_H + +#define VIDOOM_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 + +/* The following aren't required by viDOOM (but can be used) +*/ +#define GFX_MSWHEELUP 0x08 +#define GFX_MSWHEELDOWN 0x10 + + +/* 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..2392f90 --- /dev/null +++ b/gfxtest.c @@ -0,0 +1,862 @@ +/* + + 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 +#include "gfx.h" +#include "platgui.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 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); +} + + +void TestKey(void) +{ + GFXEvent e; + int q; + + q=FALSE; + + GFX_clear(BLACK); + + while(!q) + { + GFX_print(0,0,WHITE,"Press key or mouse button to quit"); + GFX_redraw(); + GFX_clear(BLACK); + GFX_await_input(&e); + + switch(e.type) + { + case GFX_KEY_EVENT: + GFX_print(0,100,WHITE,".code %d",e.key.code); + GFX_print(0,100+GFX_fh()*2,WHITE,".ascii %d (%c)",e.key.ascii, + isprint(e.key.ascii) ? e.key.ascii : '?'); + + GFX_print(0,100+GFX_fh()*4,WHITE,".modif %c%c%c", + e.key.shift ? 'S':' ', + e.key.ctrl ? 'C':' ', + e.key.alt ? 'A':' '); + break; + + case GFX_MOUSE_EVENT: + q=TRUE; + break; + } + } +} + + +void TestGui(void) +{ + static PLAT_PICKLIST cpl[]= + { + {"CPL 1",1}, + {"CPL 2",2}, + {"CPL 23",23}, + {"CPL 10",10}, + {"CPL 0",0}, + {NULL,0}, + }; + + static char *pl_short[]= + { + "Picklist entry 0", + "Picklist entry 1", "Picklist entry 2", "Picklist entry 3", + NULL + }; + + static char *pl_d_short[]= + { + "Picklist entry 0", "Picklist entry 1", + NULL + }; + + static char *pl[]= + { + "Picklist entry 0", + "Picklist entry 1", "Picklist entry 2", "Picklist entry 3", + "Picklist entry 4", "Picklist entry 5", "Picklist entry 6", + "Picklist entry 7", "Picklist entry 8", "Picklist entry 9", + "Picklist entry 10", "Picklist entry 11", "Picklist entry 12", + "Picklist entry 13", "Picklist entry 14", "Picklist entry 15", + "Picklist entry 16", "Picklist entry 17", "Picklist entry 18", + "Picklist entry 19", "Picklist entry 20", "Picklist entry 21", + "Picklist entry 22", "Picklist entry 23", "Picklist entry 24", + "Picklist entry 25", "Picklist entry 26", "Picklist entry 27", + "Picklist entry 28", "Picklist entry 29", "Picklist entry 30", + "Picklist entry 31", "Picklist entry 32", "Picklist entry 33", + "Picklist entry 34", "Picklist entry 35", "Picklist entry 36", + "Picklist entry 37", "Picklist entry 38", "Picklist entry 39", + "Picklist entry 40", "Picklist entry 41", "Picklist entry 42", + "Picklist entry 43", "Picklist entry 44", "Picklist entry 45", + "Picklist entry 46", "Picklist entry 47", "Picklist entry 48", + "Picklist entry 49", "Picklist entry 50", "Picklist entry 51", + "Picklist entry 52", "Picklist entry 53", "Picklist entry 54", + "Picklist entry 55", "Picklist entry 56", "Picklist entry 57", + "Picklist entry 58", "Picklist entry 59", "Picklist entry 60", + "Picklist entry 61", "Picklist entry 62", "Picklist entry 63", + "Picklist entry 64", "Picklist entry 65", "Picklist entry 66", + "Picklist entry 67", "Picklist entry 68", "Picklist entry 69", + "Picklist entry 70", "Picklist entry 71", "Picklist entry 72", + "Picklist entry 73", "Picklist entry 74", "Picklist entry 75", + "Picklist entry 76", "Picklist entry 77", "Picklist entry 78", + "Picklist entry 79", "Picklist entry 80", "Picklist entry 81", + "Picklist entry 82", "Picklist entry 83", "Picklist entry 84", + "Picklist entry 85", "Picklist entry 86", "Picklist entry 87", + "Picklist entry 88", "Picklist entry 89", "Picklist entry 90", + "Picklist entry 91", "Picklist entry 92", "Picklist entry 93", + "Picklist entry 94", "Picklist entry 95", "Picklist entry 96", + "Picklist entry 97", "Picklist entry 98", "Picklist entry 99", + NULL + }; + + static PLAT_IMG_PICKLIST ipl[]= + { + {"IPL 1 (BLUE)",NULL,1}, + {"IPL 2",NULL,2}, + {"IPL 23 (GREEN)",NULL,23}, + {"IPL 10",NULL,10}, + {"IPL 0 (RED)",NULL,0}, + {NULL,NULL,0}, + }; + + static PLAT_MENU ch2[]= { + {"Opt3",3,NULL}, + {"Opt4",4,NULL}, + {NULL,0,NULL}, + }; + + static PLAT_MENU ch1[]= { + {"Opt1",1,NULL}, + {"Opt2",2,NULL}, + {"Child 2",0,ch2}, + {NULL,0,NULL}, + }; + + static char *pl_text[17]={"Opt 1","Opt 2","Opt 3","Opt 4","Opt 5", + "Opt 6","Opt 7","Opt 8","Opt 9","Opt 10", + "Opt 11","Opt 12","Opt 13","Opt 14","Opt 15", + "Opt 16", + "A very very very very long option"}; + + static PLAT_DIALOG dialog[6]={ + {"String",PLAT_DIAL_STRING,{0}}, + {"Integer",PLAT_DIAL_INTEGER,{0}}, + {"Double",PLAT_DIAL_DOUBLE,{0}}, + {"Picklist 1",PLAT_DIAL_PICKLIST,{0}}, + {"Picklist 2",PLAT_DIAL_PICKLIST,{0}}, + {"Picklist 3",PLAT_DIAL_PICKLIST,{0}}, + }; + + static PLAT_RADIO radio[]= { + {"Radio 0",0}, + {"Radio 2",2}, + {"Radio 4",4}, + {"Radio 8",8}, + {"Radio -33",-33}, + {NULL,0} + }; + + int cur_radio=4; + + static PLAT_MULTI multi[]= { + {"Opt 1",0,TRUE}, + {"Opt 2",0,FALSE}, + {"Opt 3",0,FALSE}, + {"Group 1.1",1,TRUE}, + {"Group 1.2",1,FALSE}, + {"Group 1.3",1,FALSE}, + {"Opt 4",0,FALSE}, + {"Group 2.1",2,FALSE}, + {"Group 2.2",2,TRUE}, + {"Opt 5",0,FALSE}, + {NULL,0,0} + }; + + PLAT_DIALOG work_dial[6]; + + static PLAT_MENU menu[]={ + {"Recursive",0,menu}, + {"Child 1",0,ch1}, + {"Test fsel and file_view",100,NULL}, + {"Test text edit",101,NULL}, + {"Test picklist",102,NULL}, + {"Test client data picklist",103,NULL}, + {"Test client data image picklist",104,NULL}, + {"Test DIALOG",105,NULL}, + {"Test GUI_alert()",106,NULL}, + {"Test GUI_yesno()",107,NULL}, + {"Test GUI_yesno_all()",108,NULL}, + {"Test GUI_radio_box()",109,NULL}, + {"Test GUI_multi_box()",110,NULL}, + {"Quit",999,NULL}, + {NULL,0,NULL}, + }; + static char *text=NULL; + + int opt; + char s[80]; + char *path; + char *new; + int ret; + + strcpy(dialog[0].data.s,"String"); + dialog[1].data.i=123; + dialog[2].data.d=1.23; + + dialog[3].data.pl.no=17; + dialog[3].data.pl.current=0; + dialog[3].data.pl.text=pl_text; + + dialog[4].data.pl.no=2; + dialog[4].data.pl.current=0; + dialog[4].data.pl.text=pl_d_short; + + dialog[5].data.pl.no=100; + dialog[5].data.pl.current=0; + dialog[5].data.pl.text=pl; + + opt=0; + + if (!text) + { + GFX_BITMAP bm; + int c; + int f; + + text=Strdup("Test text\nof two lines follwed by\n" + "a big line (nnA - nnP):\n" + "123456790A 123456790B 123456790C 123456790D " + "123456790E 123456790F 123456790G 123456790H " + "123456790I 123456790J 123456790K 123456790L " + "123456790M 123456790N 123456790O 123456790P " + ); + bm.pal[0]=BLACK; + + c=0xff; + + for(f=0;f<3;f++) + { + int w,h; + + w=256-(f)*64; + h=256-(f)*64; + bm.w=w; + bm.h=h; + bm.pal[1]=c; + bm.data=Grab(w*h); + + memset(bm.data,1,w*h); + ipl[f*2].img=GFX_create_image(&bm); + Release(bm.data); + c=c<<8; + } + } + + while(opt!=999) + { + opt=GUI_menu("Menu",10,10,menu,-1); + + switch(opt) + { + case 100: + if (GUI_yesno("Use filter?")) + path=GUI_fsel("File selector","",".c"); + else + path=GUI_fsel("File selector","",NULL); + + if (path) + { + GUI_view_file(path,path); + Release(path); + } + + break; + + case 101: + new=GUI_text_edit("Test",text); + + if (new) + { + Release(text); + text=new; + } + break; + + case 102: + ret=GUI_picklist("Long Picklist",pl); + sprintf(s,"You chose option|%d",ret); + GUI_yesno(s); + + ret=GUI_picklist("Short Picklist",pl_short); + sprintf(s,"You chose option|%d",ret); + GUI_yesno(s); + break; + + case 103: + ret=GUI_client_picklist("Client Picklist",cpl,-1); + sprintf(s,"You chose option|%d",ret); + GUI_yesno(s); + break; + + case 104: + ret=GUI_image_picklist("Image Picklist",ipl,-1); + sprintf(s,"You chose option|%d",ret); + GUI_yesno(s); + break; + + case 105: + memcpy(&work_dial,&dialog,sizeof(dialog)); + + if (GUI_dialog("Dialog",6,work_dial)) + memcpy(&dialog,&work_dial,sizeof(dialog)); + break; + + case 106: + GUI_alert("This is a long title","Text1","OK"); + GUI_alert("T","Longer text 1|Longer text 2","OK"); + GUI_alert("T","Text1","Longer button text"); + break; + + case 107: + if (GUI_yesno("Pick")) + GUI_alert("Answer","YES","OK"); + else + GUI_alert("Answer","NO","OK"); + + if (GUI_yesno("With a much much much MUCH longer string|" + "and some multiple|lines")) + GUI_alert("Answer","YES","OK"); + else + GUI_alert("Answer","NO","OK"); + + break; + + case 108: + GUI_start_yesno_all(); + + if (GUI_yesno_all("Pick")) + GUI_alert("Pick","YES","OK"); + else + GUI_alert("Pick","NO","OK"); + + if (GUI_yesno_all("With a much much much MUCH longer string|" + "and some multiple|lines")) + GUI_alert("Long string","YES","OK"); + else + GUI_alert("Long string","NO","OK"); + + if (GUI_yesno_all("Pick 2")) + GUI_alert("Pick 2","YES","OK"); + else + GUI_alert("Pick 2","NO","OK"); + + if (GUI_yesno_all("Pick 3")) + GUI_alert("Pick 3","YES","OK"); + else + GUI_alert("Pick 3","NO","OK"); + + break; + + case 109: + ret=GUI_radio_box("Radio Box",radio,cur_radio,-666); + sprintf(s,"You chose option|%d",ret); + GUI_yesno(s); + cur_radio=ret; + break; + + case 110: + GUI_multi_box("Multi Box",multi); + break; + + case 999: + break; + + default: + sprintf(s,"You chose option|%d",opt); + GUI_alert("Other",s,"OK"); + break; + } + } +} + +#define PERF_COUNT 1000000 + +time_t PerfClr(time_t start) +{ + int f; + + for(f=0;f +#include +#include + +#include "ini.h" +#include "gfx.h" +#include "mem.h" +#include "texture.h" +#include "things.h" +#include "linedefs.h" +#include "sectors.h" +#include "genlines.h" +#include "gensect.h" +#include "specials.h" +#include "flags.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 +#define M_LINEDEF_GEN_BITMASKS 15 +#define M_LINEDEF_GEN_TYPES 16 +#define M_SECTOR_GEN_BITMASKS 17 +#define M_SECTOR_GEN_TYPES 18 +#define M_HEXEN_ACTION_CLASSES 19 +#define M_HEXEN_ACTION_SPECIALS 20 + +/* Masks for edit mode +*/ +#define DOOM_EDIT_MASK 0x01 +#define HEXEN_EDIT_MASK 0x02 + + +/* 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 ACC_INI "ACS" + +#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; + + +/* ------------------------------ 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 left_click_move=FALSE; +int linedef_select=2; +int tag_highlight=TRUE; +int show_full_linedef_info=FALSE; + + +/* ------------------------------ viDOOM configuration +*/ +char auto_loadmap[PATH_MAX+1]=""; +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 mapinfo_lump=FALSE; /* Only for ZDOOM/BOOM */ +GenericYNA create_hexen=GEN_NO; /* Only for ZDOOM/BOOM */ +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; + + +/* ------------------------------ ACC config +*/ +char acc_cmd[PATH_MAX+1]="acc.exe"; +char acc_dir[PATH_MAX+1]="."; +char acc_script[PATH_MAX+1]="vidoom.acc"; +char acc_object[PATH_MAX+1]="vidoom.o"; +char acc_args[PATH_MAX+1]="%S %O"; +int acc_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 TokenTable YNA_tok[]= + { + {"no",GEN_NO}, + {"yes",GEN_YES}, + {"ask",GEN_ASK}, + {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_TOK, EDITOR_INI, "left_click_move", + &left_click_move, ini_yesno + }, + { + 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 + }, + { + INI_STR, VIDOOM_INI, "auto_loadmap", + auto_loadmap, NULL + }, + + /* 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 + }, + + /* ACC + */ + { + INI_STR, ACC_INI, "command", + acc_cmd, NULL + }, + { + INI_STR, ACC_INI, "dir", + acc_dir, NULL + }, + { + INI_STR, ACC_INI, "script", + acc_script, NULL + }, + { + INI_STR, ACC_INI, "object", + acc_object, NULL + }, + { + INI_STR, ACC_INI, "args", + acc_args, NULL + }, + { + INI_TOK, ACC_INI, "always_view_output", + &acc_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), + { + INI_TOK, ZDOOM_INI, "mapinfo_lump", + &mapinfo_lump, ini_yesno + }, + { + INI_TOK, ZDOOM_INI, "create_hexen", + &create_hexen, YNA_tok + } + }; + + + +/* ------------------------------ 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 +#include +#include + +#include "gui.h" +#include "platgui.h" +#include "mem.h" +#include "ini.h" +#include "names.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}; + +static char **level_list=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 +#include +#include +#include "ini.h" +#include "mem.h" +#include "file.h" +#include "vstring.h" +#include "gfx.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); + } + else + GFX_exit(EXIT_FAILURE,"Couldn't open INI file. " + "Check doc/overview.htm for config details.\n"); +} + +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 AddLinedefType(char *name,int flags,int two_sided) +{ + LineDefault l; + + if (!line_def) + line_def=MapNew(sizeof(LineDefault)); + + l.name=Strdup(name); + l.id=flags; + l.two=two_sided; + + MapAdd(line_def,-1,&l); +} + + +int ChooseLinedefType(int *flag, int *two) +{ + LineDefault *l; + int f; + + if (!line_def_plist) + { + line_def_plist=Grab(sizeof(char *)*(MapSize(line_def)+1)); + + for(f=0;fname; + } + + 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..336525c --- /dev/null +++ b/linedefs.h @@ -0,0 +1,84 @@ +/* + + 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 VIDOOM_LINEDEFS_H + +#define VIDOOM_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); + + +/* 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/linux/file.c b/linux/file.c new file mode 100644 index 0000000..6094021 --- /dev/null +++ b/linux/file.c @@ -0,0 +1,103 @@ +/* + + 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 + + +/* ---------------------------------------- EXPORTED FUNCS +*/ +char *Pwd(void) +{ + static char s[PATH_MAX]; + + getcwd(s,PATH_MAX); + + 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+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=='/') + return p+1; + else + p--; + + return(s); +} + +int FileExists(char *path) +{ + FILE *fp; + + if ((fp=fopen(path,"r"))) + { + fclose(fp); + return TRUE; + } + else + return FALSE; +} + +int FilenamesEqual(char *path1, char *path2) +{ + return !strcasecmp(path1,path2); +} + + +/* END OF FILE */ diff --git a/linux/gfx.c b/linux/gfx.c new file mode 100644 index 0000000..01c7f4a --- /dev/null +++ b/linux/gfx.c @@ -0,0 +1,1013 @@ +/* + + 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 "gfx.h" +#include "mem.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* ---------------------------------------- VARS +*/ +static int init=FALSE; + +static Window win=None; +static Pixmap pix=None; +static Pixmap saved=None; +static GC gc=None; +static Display *disp=NULL; +static XVisualInfo visual; +static XFontStruct *font=NULL; +static int curr_func; + +#define FONTGAP 2 +#define FONTW (font->max_bounds.rbearing - \ + font->min_bounds.lbearing) +#define FONTH (font->max_bounds.descent + \ + font->max_bounds.ascent + FONTGAP) + +static int width=0; +static int height=0; + +static int fw=0; +static int fh=0; + +static int mbuttons=3; /* Assume 3 for X11 */ + +static int dirty_min_x=0; +static int dirty_max_x=0; +static int dirty_min_y=0; +static int dirty_max_y=0; + +static char *font_names[]= + { + "6x9", + NULL + }; + +#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) + + +/* Internal representation used for GFX_IMAGE +*/ +typedef struct + { + int w,h; + XImage *p; + } GfxImage; + +/* These are used to define the mappings between X11 scancodes and GFX keys. + Then the scancode can be used to directly index and array. +*/ +static struct + { + int is_special; + int key; + } keycode_map[sizeof(KeyCode)<< CHAR_BIT]; + +typedef struct KBuff + { + GFXKey k; + struct KBuff *next; + } KeyBuff; + +static KeyBuff *kb_head=NULL; +static KeyBuff *kb_tail=NULL; + +static struct + { + KeySym keysym; + int code; + } key_map[]= { + {XK_F1, GFX_F1}, + {XK_F2, GFX_F2}, + {XK_F3, GFX_F3}, + {XK_F4, GFX_F4}, + {XK_F5, GFX_F5}, + {XK_F6, GFX_F6}, + {XK_F7, GFX_F7}, + {XK_F8, GFX_F8}, + {XK_F9, GFX_F9}, + {XK_F10, GFX_F10}, + {XK_F11, GFX_F11}, + {XK_F12, GFX_F12}, + {XK_Escape, GFX_ESC}, + {XK_Insert, GFX_INSERT}, + {XK_Home, GFX_HOME}, + {XK_Page_Up, GFX_PGUP}, + {XK_Delete, GFX_DELETE}, + {XK_End, GFX_END}, + {XK_Page_Down, GFX_PGDN}, + {XK_Up, GFX_UP}, + {XK_Down, GFX_DOWN}, + {XK_Left, GFX_LEFT}, + {XK_Right, GFX_RIGHT}, + {XK_Return, GFX_ENTER}, + {XK_BackSpace, GFX_BACKSPACE}, + {XK_Tab, GFX_TAB}, + + {XK_VoidSymbol, -1}, + }; + +/* Types and vars for event handling +*/ +typedef enum + { + X11_GFXnone=0, + X11_GFXmouse=1, + X11_GFXmouseMove=2, + X11_GFXkey=4, + X11_GFXall=4|2|1 + } EventType; + +typedef enum + { + X11_GFXpress, X11_GFXrelease, X11_GFXmove + } MouseEventType; + +static int mouse_b=0; +static int mouse_x=0; +static int mouse_y=0; +static int is_shift=FALSE; +static int is_ctrl=FALSE; +static int is_alt=FALSE; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ + +static unsigned long getXCol(int col) +{ + XColor pix; + + pix.red=(col&0xff0000)>>8; + pix.green=(col&0xff00); + pix.blue=(col&0xff)<<8; + pix.flags=DoRed|DoBlue|DoGreen; + + XAllocColor(disp,DefaultColormap(disp,DefaultScreen(disp)),&pix); + + return pix.pixel; +} + + +static void setXCol(int col) +{ + static int last_col=-1; + + if (col==last_col) + return; + + last_col=col; + + XSetForeground(disp,gc,getXCol(col)); +} + + +static void KeyBuffAdd(int code, char ascii, int shift, int ctrl, int alt) +{ + KeyBuff *key; + + key=Grab(sizeof *key); + + key->k.code=code; + key->k.ascii=ascii; + key->k.shift=shift; + key->k.ctrl=ctrl; + key->k.alt=alt; + key->next=NULL; + + if (!kb_head) + kb_head=kb_tail=key; + else + { + kb_tail->next=key; + kb_tail=key; + } +} + + +static void GetKey(GFXKey *key) +{ + if (kb_head) + { + KeyBuff *k=kb_head; + + *key=k->k; + + if (!(kb_head=k->next)) + kb_tail=NULL; + + Release(k); + } +} + + +static int HandleKey(XKeyEvent *key) +{ + int code; + char ascii; + + if (keycode_map[key->keycode].is_special) + { + code=keycode_map[key->keycode].key; + ascii=0; + } + else + { + char buff[2]=""; + + code=GFX_ASCII; + + XLookupString(key,buff,2,NULL,NULL); + + if (!isprint(buff[0])) + return FALSE; + + ascii=buff[0]; + } + + KeyBuffAdd(code,ascii, + key->state&ShiftMask, + key->state&ControlMask, + key->state&Mod1Mask); + + return TRUE; +} + + +static void HandleMouse(int x, int y, int b, MouseEventType type, + unsigned int state) +{ + int mask; + + mouse_x=x; + mouse_y=y; + + if (type!=X11_GFXmove) + { + switch(b) + { + case Button1: + mask=GFX_BUTLEFT; + break; + case Button2: + mask=GFX_BUTMIDDLE; + break; + case Button3: + mask=GFX_BUTRIGHT; + break; + case Button4: + mask=GFX_MSWHEELUP; + break; + case Button5: + mask=GFX_MSWHEELDOWN; + break; + default: + mask=0; + break; + } + + if (type==X11_GFXpress) + mouse_b|=mask; + else + mouse_b&=~mask; + } + + is_shift=state&ShiftMask; + is_ctrl=state&ControlMask; + is_alt=state&Mod1Mask; +} + + +static EventType Wait(EventType etype, int wait) +{ + XEvent ev; + + while(wait || XPending(disp)) + { + XNextEvent(disp,&ev); + + switch(ev.type) + { + case KeyPress: + if (HandleKey(&ev.xkey) && (etype & X11_GFXkey)) + return X11_GFXkey; + + break; + + case ButtonPress: + HandleMouse(ev.xbutton.x,ev.xbutton.y,ev.xbutton.button, + X11_GFXpress,ev.xbutton.state); + + if (etype & X11_GFXmouse) + return X11_GFXmouse; + + break; + + case ButtonRelease: + HandleMouse(ev.xbutton.x,ev.xbutton.y,ev.xbutton.button, + X11_GFXrelease,ev.xbutton.state); + + if (etype & X11_GFXmouse) + return X11_GFXmouse; + + break; + + case MotionNotify: + HandleMouse(ev.xbutton.x,ev.xbutton.y,0, + X11_GFXmove,ev.xbutton.state); + + if (etype & X11_GFXmouseMove) + return X11_GFXmouseMove; + + break; + + case Expose: + DIRTY(ev.xexpose.x,ev.xexpose.y); + DIRTY(ev.xexpose.x+ev.xexpose.width, + ev.xexpose.y+ev.xexpose.height); + + if (ev.xexpose.count==0) + GFX_redraw(); + + break; + + default: + break; + } + } + + return X11_GFXnone; +} + + + +/* ---------------------------------------- 'PRIVATE' EXPORTED FUNCTIONS +*/ +void VIDOOM_GET_GFX_VARS(Display **ret_disp, Window *ret_win, Pixmap *ret_pix, + GC *ret_gc) +{ + *ret_disp=disp; + *ret_win=win; + *ret_pix=pix; + *ret_gc=gc; +} + + +void VIDOOM_GFX_FORCE_REDRAW(void) +{ + dirty_min_x=0; + dirty_max_x=width-1; + dirty_min_y=0; + dirty_max_y=width-1; + + GFX_redraw(); +} + + +void VIDOOM_GFX_SAVE_DISPLAY(void) +{ + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + XCopyArea(disp,pix,saved,gc,0,0,width,height,0,0); +} + + +void VIDOOM_GFX_RESTORE_DISPLAY(void) +{ + XCopyArea(disp,saved,pix,gc,0,0,width,height,0,0); + VIDOOM_GFX_FORCE_REDRAW(); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); +} + + +Pixmap VIDOOM_GFX_SAVE_UNDER(int x, int y, int w, int h) +{ + Pixmap p; + + p=XCreatePixmap(disp,win,w,h,visual.depth); + XCopyArea(disp,pix,p,gc,x,y,w,h,0,0); + + return p; +} + + +void VIDOOM_GFX_RESTORE_UNDER(Pixmap p, int x, int y, int w, int h) +{ + DIRTY(x,y); + DIRTY(x+w,y+h); + XCopyArea(disp,p,pix,gc,0,0,w,h,x,y); + XFreePixmap(disp,p); +} + + +/* This is done in a *very* bad fashion.... +*/ +void VIDOOM_GFX_WAIT_FOR(pid_t pid, int *status) +{ + XEvent ev; + + while(TRUE) + { + while (XPending(disp)) + { + XNextEvent(disp,&ev); + + if (ev.type==Expose) + { + DIRTY(ev.xexpose.x,ev.xexpose.y); + DIRTY(ev.xexpose.x+ev.xexpose.width, + ev.xexpose.y+ev.xexpose.height); + + if (ev.xexpose.count==0) + GFX_redraw(); + } + } + + if (waitpid(pid,status,WNOHANG)) + return; + + /* Now, this is nasty... + */ + usleep(10000); + } +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void GFX_init(void) +{ + if (!init) + { + int f; + + init=TRUE; + + /* Open display and find an appropriate visual + */ + if (!(disp=XOpenDisplay(NULL))) + GFX_exit(EXIT_FAILURE,"Couldn't open X display\n"); + + if (!XMatchVisualInfo(disp,DefaultScreen(disp),32,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),24,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),16,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),15,TrueColor,&visual)) + GFX_exit(EXIT_FAILURE,"Couldn't find a TrueColor visual\n"); + + f=0; + while(font_names[f] && !font) + font=XLoadQueryFont(disp,font_names[f++]); + + if (!font) + { + font=XLoadQueryFont(disp,"fixed"); + + if (!font) + GFX_exit(EXIT_FAILURE,"Couldn't even load font fixed\n"); + } + + fw=FONTW; + fh=FONTH; + + for(f=0;f<(sizeof(KeyCode)<< CHAR_BIT);f++) + keycode_map[f].is_special=FALSE; + + f=0; + + while(key_map[f].keysym!=XK_VoidSymbol) + { + KeyCode code; + + code=XKeysymToKeycode(disp,key_map[f].keysym); + + keycode_map[code].is_special=TRUE; + keycode_map[code].key=key_map[f].code; + + f++; + } + } +} + + +void GFX_close(void) +{ + if (gc!=None) + { + XFreeGC(disp,gc); + gc=None; + } + + if (pix!=None) + { + XFreePixmap(disp,pix); + pix=None; + } + + if (saved!=None) + { + XFreePixmap(disp,saved); + saved=None; + } + + if (win!=None) + { + XDestroyWindow(disp,win); + win=None; + } +} + + +void GFX_open(int w,int h) +{ + XGCValues gc_val; + XSizeHints hint; + + if (!init) + GFX_exit(EXIT_FAILURE,"GFX_Open() called before GFX_init()\n"); + + height=h; + width=w; + + win=XCreateWindow(disp,DefaultRootWindow(disp), + 0,0,width,height,0, + visual.depth, + InputOutput, + visual.visual, + 0,NULL); + + XSelectInput + (disp,win, + KeyPressMask|ButtonPressMask|ButtonReleaseMask| + PointerMotionMask|ExposureMask); + + XStoreName(disp,win,"viDOOM " VIDOOMVER VIDOOMRELEASE); + + hint.width=hint.min_width=hint.max_width=width; + hint.height=hint.min_height=hint.max_height=height; + hint.flags=PSize|PMinSize|PMaxSize; + + XSetWMNormalHints(disp,win,&hint); + + pix=XCreatePixmap(disp,win,width,height,visual.depth); + saved=XCreatePixmap(disp,win,width,height,visual.depth); + + curr_func=gc_val.function=GXcopy; + gc_val.plane_mask=AllPlanes; + gc_val.line_width=0; + gc_val.line_style=LineSolid; + gc_val.graphics_exposures=False; + gc_val.foreground=WhitePixel(disp,DefaultScreen(disp)); + gc_val.background=BlackPixel(disp,DefaultScreen(disp)); + + gc=XCreateGC(disp,pix, + GCFunction|GCPlaneMask|GCLineWidth|GCForeground|GCBackground| + GCLineStyle|GCGraphicsExposures, + &gc_val); + + GFX_clear(BLACK); + GFX_redraw(); + + XMapWindow(disp,win); +} + + +void GFX_clear(int col) +{ + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + setXCol(col); + XFillRectangle(disp,pix,gc,0,0,width,height); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); + + dirty_min_x=0; + dirty_max_x=width; + dirty_min_y=0; + dirty_max_y=height; +} + + +void GFX_redraw(void) +{ + if (dirty_max_xkey)); + ev->type=GFX_KEY_EVENT; + break; + + case X11_GFXmouse: + ev->type=GFX_MOUSE_EVENT; + ev->mouse.shift=is_shift; + ev->mouse.ctrl=is_ctrl; + ev->mouse.alt=is_alt; + ev->mouse.x=mouse_x; + ev->mouse.y=mouse_y; + ev->mouse.b=mouse_b; + break; + + default: + break; + } +} + + +void GFX_await_input_full(GFXEvent *ev) +{ + switch(Wait(X11_GFXall,TRUE)) + { + case X11_GFXkey: + GetKey(&(ev->key)); + ev->type=GFX_KEY_EVENT; + break; + + case X11_GFXmouse: + case X11_GFXmouseMove: + ev->type=GFX_MOUSE_EVENT; + ev->mouse.shift=is_shift; + ev->mouse.ctrl=is_ctrl; + ev->mouse.alt=is_alt; + ev->mouse.x=mouse_x; + ev->mouse.y=mouse_y; + ev->mouse.b=mouse_b; + break; + + default: + break; + } +} + + +void GFX_exit(int code,char *fmt,...) +{ + va_list va; + + va_start(va,fmt); + vfprintf(stderr,fmt,va); + va_end(va); + + /* Be lazy, and leave the might of Unix to clear up, though may as well + let X know. + */ + if (disp) + XCloseDisplay(disp); + + exit(code); +} + + +GFX_IMAGE GFX_create_image(GFX_BITMAP *bm) +{ + GfxImage i; + char *data; + int x,y; + unsigned long pal[256]; + + data=Grab(bm->w*bm->h*4); + + i.p=XCreateImage(disp,visual.visual,visual.depth, + ZPixmap,0,data,bm->w,bm->h,32,4*bm->w); + + if (!i.p) + { + Release(data); + return NULL; + } + + for(x=0;x<256;x++) + pal[x]=getXCol(bm->pal[x]); + + i.w=bm->w; + i.h=bm->h; + + for(x=0;xw;x++) + for(y=0;yh;y++) + XPutPixel(i.p,x,y,pal[*(bm->data+x+y*bm->w)]); + + return Copy(&i,sizeof i); +} + + +void GFX_destroy_image(GFX_IMAGE img) +{ + GfxImage *p=img; + + if (p) + { + XDestroyImage(p->p); + Release(p); + } +} + + +void GFX_draw_image(GFX_IMAGE i, int x, int y) +{ + GfxImage *p=i; + + if (p) + { + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + XPutImage(disp,pix,gc,p->p,0,0,x,y,p->w,p->h); + + DIRTY(x,y); + DIRTY(x+p->w,y+p->h); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); + } +} + + +void GFX_fill_screen(GFX_IMAGE i) +{ + GfxImage *p=i; + + if (p) + GFX_draw_image(i,(width-p->w)/2,(height-p->h)/2); +} + + +void GFX_save_screen(char *path) +{ +} + + +/* END OF FILE */ diff --git a/linux/main.c b/linux/main.c new file mode 100644 index 0000000..9cda67e --- /dev/null +++ b/linux/main.c @@ -0,0 +1,33 @@ +/* + + 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/linux/mem.c b/linux/mem.c new file mode 100644 index 0000000..a23b4ce --- /dev/null +++ b/linux/mem.c @@ -0,0 +1,107 @@ +/* + + 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" + +void *FGrab(char *fn, int line, int len) +{ + char *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; +} + + +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; +} + + +void FRelease(char *fn, int line, void *p) +{ + free(p); +} + + +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; +} + + +char *FStrdup(char *fn, int line, char *p) +{ + char n_fn[PATH_MAX]; + char *ptr; + + if (!p) + return NULL; + + if (!(ptr=strdup(p))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Stdup(%s)\n",fn,line,p); + + return ptr; +} + +/* END OF FILE */ diff --git a/linux/platgui.c b/linux/platgui.c new file mode 100644 index 0000000..5fd9c74 --- /dev/null +++ b/linux/platgui.c @@ -0,0 +1,3703 @@ +/* + + 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 "platgui.h" +#include "gui.h" +#include "gfx.h" +#include "mem.h" +#include "file.h" +#include "ini.h" +#include "util.h" + +#include "debug.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* ---------------------------------------- MACROS +*/ +#define CENTRE(x,y,c,t) GFX_print((x)-strlen(t)*FW/2,y,c,"%s",t) + +#define CENTREX(x,y,w,c,t) GFX_print(((x)+(w)/2)-strlen(t)*FW/2,y,c,"%s",t) +#define CENTREY(x,y,h,c,t) GFX_print((x),((y)+(h)/2)-FH/2,c,"%s",t) +#define CENTREXY(x,y,w,h,c,t) GFX_print(((x)+(w)/2)-strlen(t)*FW/2,\ + ((y)+(h)/2)-FH/2,c,"%s",t) +#define LENGTH(t) (strlen(t)*FW) + + +/* ---------------------------------------- CONFIG +*/ +static char GUI_EDITOR[PATH_MAX]=""; + + +static INI_Table ini_conf[]= + { + {INI_STR,"linux","edit",GUI_EDITOR,NULL}, + }; + +/* ---------------------------------------- VARS +*/ +static Display *disp=NULL; +static Window win=None; +static Pixmap pix=None; +static GC gc=None; + +static int SCRW,SCRH; +static int FW,FH; + +static unsigned long hi_col; +static unsigned long mid_col; +static unsigned long lo_col; +static unsigned long txt_col; +static unsigned long shadow_col; +static unsigned long bold_col; + +static const int BEVEL=2; +static const int SMALL_BEVEL=1; + +#define LIST_SCROLLSIZE 20 +#define LIST_TEXTHEIGHT (FH+(FH>>1)) + +/* Internal representation used for GFX_IMAGE + + IMPORTANT: This *MUST* match the definition in linux/gfx.c + +*/ +typedef struct + { + int w,h; + XImage *p; + } GfxImage; + + +/* Vars for GUI_yesno_all() +*/ +static int all_pressed=FALSE; +static int all_result=FALSE; + +/* Event Vars +*/ +static int mouse_x=0; +static int mouse_y=0; +static int mouse_b=0; +static int last_mouse_b=0; +static int is_key=FALSE; +static int key=0; +static int shift=0; +static int ctrl=0; +static char ascii=0; + +/* 'Hidden' interfaces to gfx.c +*/ +extern void VIDOOM_GET_GFX_VARS(Display **ret_disp, + Window *ret_win, + Pixmap *ret_pix, + GC *ret_gc); +extern void VIDOOM_GFX_FORCE_REDRAW(void); +extern void VIDOOM_GFX_SAVE_DISPLAY(void); +extern void VIDOOM_GFX_RESTORE_DISPLAY(void); +extern Pixmap VIDOOM_GFX_SAVE_UNDER(int x, int y, int w, int h); +extern void VIDOOM_GFX_RESTORE_UNDER(Pixmap p, int x, int y, int w, int h); +extern void VIDOOM_GFX_WAIT_FOR(pid_t pid, int *status); + + +/* Types to define GUI objects. Note picklist done as an image list with + no images. +*/ +typedef enum {GuiBox, + GuiLabel, + GuiButton, + GuiText, + GuiToggle, + GuiRadio, + GuiImageList, + GuiFileList, + GuiTextEdit} ObjType; + +typedef enum {GuiKeyPress, + GuiButtonPress, + GuiWheelUp, + GuiWheelDown, + GuiDraw, + GuiExit} ObjEvent; + +typedef enum {GuiOk, + GuiDone, + GuiRedraw} CallbackReturn; + +typedef enum {GuiTextString, + GuiTextInteger, + GuiTextDouble, + GuiTextReadOnly} GuiTextMode; + +typedef struct + { + int x,y,w,h; + } BoundBox; + +typedef struct + { + ObjType type; + BoundBox box; + int focus; + int take_focus; + } GuiObjCommon; + +typedef struct + { + GuiObjCommon common; + const char *title; + int invert; + GfxImage *img; + } GuiObjBox; + +typedef struct + { + GuiObjCommon common; + const char *text; + int col; + int centre; + } GuiObjLabel; + +typedef struct + { + GuiObjCommon common; + const char *text; + } GuiObjButton; + +typedef struct + { + GuiObjCommon common; + char text[PATH_MAX+1]; + GuiTextMode mode; + int len; + int no_chars; + int first; + int curs; + int allow_exit; + } GuiObjText; + +typedef struct + { + GuiObjCommon common; + const char *text; + int state; + } GuiObjToggle; + +typedef struct + { + GuiObjCommon common; + int state; + const char *text; + int group; + } GuiObjRadio; + +typedef struct + { + GuiObjCommon common; + int curr; + int img_box; + int no; + char **items; + GFX_IMAGE *img; + int no_lines; + int top; + double sbar_step; + int scrollbar; + BoundBox scroll; + BoundBox bar; + int double_click; + } GuiObjImageList; + +typedef struct + { + char name[PATH_MAX+1]; + int is_dir; + off_t size; + } FileEnt; + +typedef struct + { + GuiObjCommon common; + int curr; + int no; + FileEnt *ent; + char dir[PATH_MAX+1]; + char *filter; + int no_lines; + int top; + double sbar_step; + int scrollbar; + BoundBox scroll; + BoundBox bar; + int double_click; + int path_text; + int file_text; + int name_width; + int size_width; + } GuiObjFileList; + +#define TE_CHUNK 256 + +typedef struct + { + int len; + char *p; + } TextEditLine; + +typedef struct + { + GuiObjCommon common; + TextEditLine *tline; + int top; + int x,y; + int col; + int lines; + int width; + int height; + int info; + int read_only; + } GuiObjTextEdit; + +typedef union + { + GuiObjCommon common; + GuiObjBox box; + GuiObjLabel lbl; + GuiObjButton but; + GuiObjText txt; + GuiObjToggle tog; + GuiObjRadio rad; + GuiObjImageList pck; + GuiObjFileList fle; + GuiObjTextEdit edt; + } GuiObj; + +static int focus=-1; + +static int dialog_no; +static GuiObj *dialog=NULL; + + +/* Types to define menus +*/ +typedef enum {MENU_OK, + MENU_CANCEL_ESC, + MENU_CANCEL_CLICK, + MENU_CHILD_RETURN} MenuStatus; + +typedef struct + { + MenuStatus mode; + int ret; + } MenuControl; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void ExecProgram(char *prog_in, char *file) +{ + char prog[PATH_MAX]; + char *arg[PATH_MAX]; + int no; + int f; + + strcpy(prog,prog_in); + + no=0; + + arg[no]=strtok(prog," "); + + while (arg[no]) + arg[++no]=strtok(NULL," "); + + for(f=0;f>8)|((col&0xff0000)>>16); + pix.green=(col&0xff00)|((col&0xff00)>>8); + pix.blue=((col&0xff)<<8)|(col&0xff); + pix.flags=DoRed|DoBlue|DoGreen; + + XAllocColor(disp,DefaultColormap(disp,DefaultScreen(disp)),&pix); + + return pix.pixel; +} + + +static void DumpBox(const char *title, BoundBox b) +{ + Debug(("%s.x=%d\n",title,b.x)); + Debug(("%s.y=%d\n",title,b.y)); + Debug(("%s.w=%d\n",title,b.w)); + Debug(("%s.h=%d\n",title,b.h)); +} + + +static int MouseInBox(BoundBox *box, int no) +{ + int f; + + for(f=0;f=box[f].x)&&(mouse_x=box[f].y)&&(mouse_y=box->x)&&(mouse_xx+box->w))&& + ((mouse_y>=box->y)&&(mouse_yy+box->h))) + return TRUE; + + return FALSE; +} + + +static void Rect3D(int x,int y,int w,int h, int invert,int bevel) +{ + int f; + int mid,lo,hi; + + mid=GUI_MID; + + if (invert) + { + lo=GUI_HI; + hi=GUI_LO; + } + else + { + hi=GUI_HI; + lo=GUI_LO; + } + + GFX_frect(x,y,w,h,mid); + + for(f=0;fx,b->y,b->w,b->h,invert,bevel); +} + + +static void Tickbox(int x,int y,int w,int h, int pick) +{ + int f; + + if (pick) + GFX_frect(x,y,w,h,BLACK); + else + GFX_frect(x,y,w,h,WHITE); + + + for(f=0;fdialog[no].pck.no_lines) + dialog[no].pck.top=curr; + else + dialog[no].pck.top=0; + + dialog[no].pck.scroll.x=x+w-BEVEL-LIST_SCROLLSIZE; + dialog[no].pck.scroll.y=y+BEVEL; + dialog[no].pck.scroll.w=LIST_SCROLLSIZE; + dialog[no].pck.scroll.h=h-BEVEL*2+1; + + if (no_items>dialog[no].pck.no_lines) + { + dialog[no].pck.scrollbar=TRUE; + + dialog[no].pck.sbar_step=(double)h/(double)no_items; + dialog[no].pck.bar.x=dialog[no].pck.scroll.x; + dialog[no].pck.bar.y=dialog[no].pck.scroll.y; + dialog[no].pck.bar.w=dialog[no].pck.scroll.w; + dialog[no].pck.bar.h= + (dialog[no].pck.sbar_step*dialog[no].pck.no_lines+0.5); + } + else + { + dialog[no].pck.scrollbar=FALSE; + + dialog[no].pck.bar=dialog[no].pck.scroll; + } + + return no; +} + + +static int CreateFileList(int x, int y, int w, int h, + char *path, char *filter, + int path_text, int file_text, + int allow_double_click) +{ + int no=dialog_no++; + int charw; + + DialCommon(no,GuiFileList,x,y,w,h,TRUE); + + dialog[no].fle.ent=NULL; + strcpy(dialog[no].fle.dir,path); + dialog[no].fle.filter=filter; + dialog[no].fle.path_text=path_text; + dialog[no].fle.file_text=file_text; + dialog[no].fle.double_click=allow_double_click; + + dialog[no].fle.no_lines=h/LIST_TEXTHEIGHT; + + dialog[no].fle.scroll.x=x+w-BEVEL-LIST_SCROLLSIZE; + dialog[no].fle.scroll.y=y+BEVEL; + dialog[no].fle.scroll.w=LIST_SCROLLSIZE; + dialog[no].fle.scroll.h=h-BEVEL*2+1; + + charw=(w-BEVEL*2-LIST_SCROLLSIZE)/FW; + + dialog[no].fle.size_width=12; + dialog[no].fle.name_width=charw-dialog[no].fle.size_width; + + ResetText(path_text,path); + ResetText(file_text,""); + + chdir(path); + + return no; +} + +static int CreateTextEdit(int x, int y, int w, int h, + TextEditLine *lines, int no_lines, int info, + int read_only) +{ + static void TextEditInfo(GuiObjTextEdit *o); + int no=dialog_no++; + + DialCommon(no,GuiTextEdit,x,y,w,h,TRUE); + + dialog[no].edt.top=0; + dialog[no].edt.x=0; + dialog[no].edt.y=0; + dialog[no].edt.col=0; + + dialog[no].edt.tline=lines; + dialog[no].edt.lines=no_lines; + + dialog[no].edt.info=info; + dialog[no].edt.read_only=read_only; + + dialog[no].edt.width=w/FW; + dialog[no].edt.height=h/FH; + + TextEditInfo(&dialog[no].edt); + + return no; +} + + +/* ---------------------------------------- DIALOG CALLBACK FUNCTIONS +*/ +static CallbackReturn Callback(GuiObj *o, ObjEvent ev) +{ + static CallbackReturn BoxCallback(GuiObj *o ,ObjEvent ev); + static CallbackReturn LabelCallback(GuiObj *o,ObjEvent ev); + static CallbackReturn ButtonCallback(GuiObj *o,ObjEvent ev); + static CallbackReturn ToggleCallback(GuiObj *o,ObjEvent ev); + static CallbackReturn RadioCallback(GuiObj *o,ObjEvent ev); + static CallbackReturn ImageListCallback(GuiObj *o,ObjEvent ev); + static CallbackReturn TextCallback(GuiObj *o,ObjEvent ev); + static CallbackReturn FileListCallback(GuiObj *o,ObjEvent ev); + static CallbackReturn TextEditCallback(GuiObj *o,ObjEvent ev); + + switch(o->common.type) + { + case GuiBox: + return BoxCallback(o,ev); + case GuiLabel: + return LabelCallback(o,ev); + case GuiButton: + return ButtonCallback(o,ev); + case GuiToggle: + return ToggleCallback(o,ev); + case GuiRadio: + return RadioCallback(o,ev); + case GuiImageList: + return ImageListCallback(o,ev); + case GuiText: + return TextCallback(o,ev); + case GuiFileList: + return FileListCallback(o,ev); + case GuiTextEdit: + return TextEditCallback(o,ev); + default: + return GuiOk; + } +} + + +static CallbackReturn BoxCallback(GuiObj *o ,ObjEvent ev) +{ + GuiObjBox *b; + + b=&(o->box); + + switch (ev) + { + case GuiDraw: + if (!b->img) + { + Rect3DBox(&b->common.box,b->invert,BEVEL); + + if (b->title) + { + int x,y,w; + + x=b->common.box.x+BEVEL*2; + y=b->common.box.y+BEVEL; + w=b->common.box.w-BEVEL*4; + + CENTREX(x,y,w,GUI_TEXTBOLD,b->title); + + GFX_line(x,y+FH+FH/2,x+w,y+FH+FH/2,GUI_HI); + GFX_line(x,y+FH+FH/2+1,x+w,y+FH+FH/2+1,GUI_LO); + } + } + else + { + Rect3DBox(&b->common.box,b->invert,BEVEL); + + GFX_draw_image(b->img, + b->common.box.x+b->common.box.w/2-b->img->w/2, + b->common.box.y+b->common.box.h/2-b->img->h/2); + } + break; + + case GuiKeyPress: + break; + + case GuiButtonPress: + break; + + case GuiWheelUp: + break; + + case GuiWheelDown: + break; + + case GuiExit: + break; + } + return GuiOk; +} + + +static CallbackReturn LabelCallback(GuiObj *o ,ObjEvent ev) +{ + GuiObjLabel *l; + + l=&(o->lbl); + + switch (ev) + { + case GuiDraw: + GFX_frect(l->common.box.x,l->common.box.y, + l->common.box.w,l->common.box.h,GUI_MID); + + if (l->centre) + CENTREXY(l->common.box.x,l->common.box.y, + l->common.box.w,l->common.box.h,l->col,l->text); + else + CENTREY(l->common.box.x,l->common.box.y, + l->common.box.h,l->col,l->text); + break; + + case GuiKeyPress: + break; + + case GuiButtonPress: + break; + + case GuiWheelUp: + break; + + case GuiWheelDown: + break; + + case GuiExit: + break; + } + return GuiOk; +} + + +static CallbackReturn ButtonCallback(GuiObj *o ,ObjEvent ev) +{ + GuiObjButton *b; + + b=&(o->but); + + switch (ev) + { + case GuiDraw: + if (b->common.focus) + GFX_rect(b->common.box.x,b->common.box.y, + b->common.box.w,b->common.box.h,GUI_TEXTBOLD); + else + GFX_rect(b->common.box.x,b->common.box.y, + b->common.box.w,b->common.box.h,GUI_MID); + + Rect3D(b->common.box.x+1,b->common.box.y+1, + b->common.box.w-2,b->common.box.h-2, + FALSE,BEVEL); + + CENTREXY(b->common.box.x,b->common.box.y, + b->common.box.w,b->common.box.h,GUI_TEXTBOLD,b->text); + break; + + case GuiKeyPress: + if (key!=GFX_ENTER) + break; + + /* CAUTION: Case above runs into this + */ + case GuiButtonPress: + Rect3D(b->common.box.x+1,b->common.box.y+1, + b->common.box.w-2,b->common.box.h-2, + TRUE,BEVEL); + + CENTREXY(b->common.box.x,b->common.box.y, + b->common.box.w,b->common.box.h,GUI_TEXTBOLD,b->text); + + return GuiDone; + break; + + case GuiWheelUp: + break; + + case GuiWheelDown: + break; + + case GuiExit: + break; + } + + return GuiOk; +} + + +static CallbackReturn ToggleCallback(GuiObj *op ,ObjEvent ev) +{ + GuiObjToggle *o; + int x,y,w,h; + + o=&(op->tog); + + x=o->common.box.x; + y=o->common.box.y; + w=o->common.box.h; + h=o->common.box.h; + + switch (ev) + { + case GuiDraw: + if (o->common.focus) + GFX_rect(x,y,w,h,GUI_TEXTBOLD); + else + GFX_rect(x,y,w,h,GUI_MID); + + CENTREY(o->common.box.x+o->common.box.h+FW,o->common.box.y, + o->common.box.h,GUI_TEXT,o->text); + + Tickbox(x+1,y+1,w-2,h-2,o->state); + + break; + + case GuiKeyPress: + if (key!=GFX_ENTER && ascii!=' ') + break; + + /* CAUTION: Case above runs into this + */ + case GuiButtonPress: + o->state=!o->state; + return GuiRedraw; + break; + + case GuiWheelUp: + break; + + case GuiWheelDown: + break; + + case GuiExit: + break; + } + + return GuiOk; +} + + +static CallbackReturn RadioCallback(GuiObj *op ,ObjEvent ev) +{ + GuiObjRadio *o; + int x,y,w,h; + + o=&(op->rad); + + x=o->common.box.x; + y=o->common.box.y; + w=o->common.box.h; + h=o->common.box.h; + + switch (ev) + { + case GuiDraw: + if (o->common.focus) + GFX_rect(x,y,w,h,GUI_TEXTBOLD); + else + GFX_rect(x,y,w,h,GUI_MID); + + CENTREY(o->common.box.x+o->common.box.h+FW,o->common.box.y, + o->common.box.h,GUI_TEXT,o->text); + + Tickbox(x+1,y+1,w-2,h-2,o->state); + + break; + + case GuiKeyPress: + if (key!=GFX_ENTER && ascii!=' ') + break; + + /* CAUTION: Case above runs into this + */ + case GuiButtonPress: + if (!o->state) + { + int f; + + for(f=0;fgroup) + dialog[f].rad.state=FALSE; + + o->state=TRUE; + + return GuiRedraw; + } + break; + + case GuiWheelUp: + break; + + case GuiWheelDown: + break; + + case GuiExit: + break; + } + + return GuiOk; +} + + +static CallbackReturn HandleImageListPage(GuiObjImageList *o, int keycode) +{ + switch(keycode) + { + case GFX_UP: + case GFX_PGUP: + if (o->curr>0) + { + o->curr=MAX(0,o->curr-(key==GFX_UP ? 1:o->no_lines)); + + if (o->currtop) + o->top=o->curr; + + if ((o->top+o->no_lines)<=o->curr) + o->top=o->curr-o->no_lines+1; + + return GuiRedraw; + } + break; + + case GFX_DOWN: + case GFX_PGDN: + if (o->curr<(o->no-1)) + { + o->curr=MIN(o->no-1,o->curr+ + (key==GFX_DOWN ? 1:o->no_lines)); + + if (o->currtop) + o->top=o->curr; + + if ((o->top+o->no_lines)<=o->curr) + o->top=o->curr-o->no_lines+1; + + return GuiRedraw; + } + break; + + default: + break; + } + + return GuiOk; +} + + +static CallbackReturn ImageListCallback(GuiObj *op ,ObjEvent ev) +{ + static time_t last=0; + GuiObjImageList *o; + int x,y,w,h; + int sx,sy,sw,sh; + int f; + + o=&(op->pck); + + x=o->common.box.x+BEVEL; + y=o->common.box.y+BEVEL; + w=o->common.box.w-BEVEL*2; + h=o->common.box.h-BEVEL*2; + + sx=o->scroll.x; + sy=o->scroll.y; + sw=o->scroll.w; + sh=o->scroll.h; + + switch (ev) + { + case GuiDraw: + if (o->common.focus) + GFX_rect(x-BEVEL-1,y-BEVEL-1, + w+BEVEL*2+2,h+BEVEL*2+2,GUI_TEXTBOLD); + else + GFX_rect(x-BEVEL-1,y-BEVEL-1, + w+BEVEL*2+2,h+BEVEL*2+2,GUI_MID); + + Rect3DBox(&o->common.box,TRUE,BEVEL); + + GFX_frect(x,y,w,h,WHITE); + + GFX_frect(sx,sy,sw,sh,GUI_MID); + + o->bar.y=sy+o->sbar_step*o->top; + Rect3DBox(&o->bar,FALSE,SMALL_BEVEL); + + for(f=0;fno_lines;f++) + { + int col; + int p=f+o->top; + int tx=x; + int ty=y+(f*LIST_TEXTHEIGHT); + int tw=w-sw; + int th=LIST_TEXTHEIGHT; + + if (p==o->curr) + { + col=WHITE; + GFX_frect(tx,ty,tw,th,BLACK); + } + else + col=BLACK; + + if (pno) + CENTREY(tx,ty,th,col,o->items[p]); + } + + if (o->img) + { + dialog[o->img_box].box.img=o->img[o->curr]; + Callback(dialog+o->img_box,GuiDraw); + } + + break; + + case GuiKeyPress: + switch(key) + { + case GFX_UP: + case GFX_PGUP: + case GFX_DOWN: + case GFX_PGDN: + return HandleImageListPage(o,key); + break; + + case GFX_ENTER: + return GuiDone; + break; + + default: + break; + } + + break; + + case GuiButtonPress: + if (IsInBox(&o->scroll)) + { + if (!o->scrollbar) + return GuiOk; + + if (IsInBox(&o->bar)) + { + int orig; + int y; + double dtop; + + orig=mouse_y; + dtop=o->top; + + while (GFX_mouse(NULL,&y)==GFX_BUTLEFT) + { + int diff; + + diff=y-orig; + + dtop+=diff/o->sbar_step; + + o->top=(int)dtop; + + o->top=MAX(0,o->top); + o->top=MIN(o->no-o->no_lines,o->top); + + Callback(op,GuiDraw); + GFX_redraw(); + + orig=y; + } + } + else + { + if (mouse_ybar.y) + o->top=MAX(0,o->top-o->no_lines); + else + o->top=MIN(o->no-1-o->no_lines,o->top+o->no_lines); + + return GuiRedraw; + } + } + else + { + int my; + int pick; + + my=mouse_y-y; + + pick=o->top+my/LIST_TEXTHEIGHT; + + if (pickno) + { + if (pick==o->curr && (time(NULL)-last)<2 && + o->double_click) + return GuiDone; + + last=time(NULL); + + o->curr=pick; + return GuiRedraw; + } + } + break; + + case GuiWheelUp: + return HandleImageListPage(o,GFX_PGUP); + break; + + case GuiWheelDown: + return HandleImageListPage(o,GFX_PGDN); + break; + + case GuiExit: + break; + } + + return GuiOk; +} + + +static CallbackReturn TextCallback(GuiObj *op ,ObjEvent ev) +{ + int x,y,w,h; + GuiObjText *o; + int f; + int ok; + + o=&(op->txt); + + x=o->common.box.x+BEVEL; + y=o->common.box.y+BEVEL; + w=o->common.box.w-BEVEL*2; + h=o->common.box.h-BEVEL*2; + + switch (ev) + { + case GuiDraw: + if (o->common.focus) + GFX_rect(x-BEVEL-1,y-BEVEL-1, + w+BEVEL*2+2,h+BEVEL*2+2,GUI_TEXTBOLD); + else + GFX_rect(x-BEVEL-1,y-BEVEL-1, + w+BEVEL*2+2,h+BEVEL*2+2,GUI_MID); + + Rect3DBox(&o->common.box,TRUE,BEVEL); + + if (o->mode!=GuiTextReadOnly) + GFX_frect(x,y,w,h,WHITE); + + for(f=0;fno_chars;f++) + { + int col; + int pos; + int tx; + + tx=x+f*FW; + pos=o->first+f; + + if (o->common.focus) + { + if (pos==o->curs) + { + GFX_frect(tx,y,FW,FH,BLACK); + col=WHITE; + } + else + col=BLACK; + } + else + col=BLACK; + + if (poslen) + GFX_print(tx,y,col,"%c",o->text[pos]); + + tx+=FW; + } + + break; + + case GuiKeyPress: + switch(key) + { + case GFX_LEFT: + o->curs--; + o->curs=MAX(0,o->curs); + o->curs=MIN(o->len,o->curs); + + if (o->cursfirst) + o->first--; + + return GuiRedraw; + break; + + case GFX_RIGHT: + o->curs++; + o->curs=MIN(o->len,o->curs); + + if (o->curs>(o->first+o->no_chars-1)) + o->first++; + + return GuiRedraw; + break; + + case GFX_ENTER: + if (o->allow_exit) + return GuiDone; + break; + + case GFX_BACKSPACE: + case GFX_DELETE: + if (o->curs) + { + memmove(o->text+o->curs-1,o->text+o->curs, + o->len-o->curs+1); + + if (--o->cursfirst) + o->first--; + + o->len=strlen(o->text); + + return GuiRedraw; + } + break; + + case GFX_END: + o->curs=o->len; + o->first=MAX(0,o->len-o->no_chars-1); + return GuiRedraw; + break; + + case GFX_HOME: + o->curs=0; + o->first=0; + return GuiRedraw; + break; + + default: + switch(o->mode) + { + case GuiTextString: + ok=isprint(ascii); + break; + case GuiTextInteger: + if (strchr("-+0123456789",ascii)) + ok=TRUE; + else + ok=FALSE; + break; + case GuiTextDouble: + if (strchr(".-+0123456789",ascii)) + ok=TRUE; + else + ok=FALSE; + break; + case GuiTextReadOnly: + ok=FALSE; + break; + default: + ok=FALSE; + break; + } + + if (ok && o->lencurs==o->len) + { + o->text[o->curs++]=ascii; + o->text[o->curs]=0; + } + else + { + memmove(o->text+o->curs+1,o->text+o->curs, + o->len-o->curs+1); + o->text[o->curs++]=ascii; + } + + o->len=strlen(o->text); + + if (o->curs>(o->first+o->no_chars-1)) + o->first++; + + return GuiRedraw; + } + + break; + } + + break; + + case GuiButtonPress: + break; + + case GuiWheelUp: + break; + + case GuiWheelDown: + break; + + case GuiExit: + break; + } + + return GuiOk; +} + + +static CallbackReturn HandleFileListPage(GuiObjFileList *o, int keycode) +{ + switch(keycode) + { + case GFX_UP: + case GFX_PGUP: + if (o->curr>0) + { + o->curr=MAX(0,o->curr-(key==GFX_UP ? 1:o->no_lines)); + + if (o->currtop) + o->top=o->curr; + + if ((o->top+o->no_lines)<=o->curr) + o->top=o->curr-o->no_lines+1; + } + break; + + case GFX_DOWN: + case GFX_PGDN: + if (o->curr<(o->no-1)) + { + o->curr=MIN(o->no-1,o->curr+ + (key==GFX_DOWN ? 1:o->no_lines)); + + if (o->currtop) + o->top=o->curr; + + if ((o->top+o->no_lines)<=o->curr) + o->top=o->curr-o->no_lines+1; + } + break; + + default: + break; + } + + if (o->ent[o->curr].is_dir) + ResetText(o->file_text,""); + else + ResetText(o->file_text,o->ent[o->curr].name); + + return GuiRedraw; +} + + +static int SortFiles(const void *a, const void *b) +{ + const FileEnt *fa,*fb; + + fa=a; + fb=b; + + if (fa->is_dir && !fb->is_dir) + return -1; + else if (!fa->is_dir && fb->is_dir) + return 1; + else + return strcmp(fa->name,fb->name); +} + + +static int FilesMatch(const char *file, const char *filter) +{ + if (!filter) + return TRUE; + + if (strlen(file)ent) + Release(o->ent); + + o->ent=NULL; + o->no=0; + o->curr=0; + o->top=0; + + getcwd(o->dir,PATH_MAX); + + if (o->dir[l=(strlen(o->dir)-1)]!='/') + { + o->dir[++l]='/'; + o->dir[++l]=0; + } + + if ((d=opendir(o->dir))) + { + struct dirent *ent; + struct stat sbuf; + + while ((ent=readdir(d))) + { + if (!stat(ent->d_name,&sbuf)) + if (S_ISDIR(sbuf.st_mode) || FilesMatch(ent->d_name,o->filter)) + { + o->no++; + o->ent=ReGrab(o->ent,sizeof(FileEnt)*o->no); + + strcpy(o->ent[o->no-1].name,ent->d_name); + o->ent[o->no-1].is_dir=S_ISDIR(sbuf.st_mode); + o->ent[o->no-1].size=sbuf.st_size; + } + } + + closedir(d); + } + + ResetText(o->file_text,""); + ResetText(o->path_text,o->dir); + + qsort(o->ent,o->no,sizeof(FileEnt),SortFiles); + + if (o->no>o->no_lines) + { + o->scrollbar=TRUE; + + o->sbar_step=(double)o->common.box.h/(double)o->no; + o->bar.x=o->scroll.x; + o->bar.y=o->scroll.y; + o->bar.w=o->scroll.w; + o->bar.h=(o->sbar_step*o->no_lines+0.5); + } + else + { + o->scrollbar=FALSE; + o->bar=o->scroll; + } +} + + +static CallbackReturn FileListCallback(GuiObj *op ,ObjEvent ev) +{ + static time_t last=0; + static char buff[PATH_MAX+10]; + GuiObjFileList *o; + int x,y,w,h; + int sx,sy,sw,sh; + int f; + + o=&(op->fle); + + if (!o->ent) + GetFileList(o); + + x=o->common.box.x+BEVEL; + y=o->common.box.y+BEVEL; + w=o->common.box.w-BEVEL*2; + h=o->common.box.h-BEVEL*2; + + sx=o->scroll.x; + sy=o->scroll.y; + sw=o->scroll.w; + sh=o->scroll.h; + + switch (ev) + { + case GuiDraw: + if (o->common.focus) + GFX_rect(x-BEVEL-1,y-BEVEL-1, + w+BEVEL*2+2,h+BEVEL*2+2,GUI_TEXTBOLD); + else + GFX_rect(x-BEVEL-1,y-BEVEL-1, + w+BEVEL*2+2,h+BEVEL*2+2,GUI_MID); + + Rect3DBox(&o->common.box,TRUE,BEVEL); + + GFX_frect(x,y,w,h,WHITE); + + GFX_frect(sx,sy,sw,sh,GUI_MID); + + o->bar.y=sy+o->sbar_step*o->top; + Rect3DBox(&o->bar,FALSE,SMALL_BEVEL); + + for(f=0;fno_lines;f++) + { + int col; + int p=f+o->top; + int tx=x; + int ty=y+(f*LIST_TEXTHEIGHT); + int tw=w-sw; + int th=LIST_TEXTHEIGHT; + + if (p==o->curr) + { + col=WHITE; + GFX_frect(tx,ty,tw,th,BLACK); + } + else + col=BLACK; + + if (pno) + { + if (o->ent[p].is_dir) + sprintf(buff,"%-*.*s%*.*s", + o->name_width, + o->name_width, + o->ent[p].name, + o->size_width, + o->size_width, + ""); + else + sprintf(buff,"%-*.*s%*ld", + o->name_width, + o->name_width, + o->ent[p].name, + o->size_width, + o->ent[p].size); + + CENTREY(tx,ty,th,col,buff); + } + } + + break; + + case GuiKeyPress: + switch(key) + { + case GFX_UP: + case GFX_PGUP: + case GFX_DOWN: + case GFX_PGDN: + return HandleFileListPage(o,key); + break; + + case GFX_ENTER: + if (!o->ent[o->curr].is_dir) + return GuiDone; + break; + + default: + break; + } + + break; + + case GuiButtonPress: + if (IsInBox(&o->scroll)) + { + if (!o->scrollbar) + return GuiOk; + + if (IsInBox(&o->bar)) + { + int orig; + int y; + double dtop; + + orig=mouse_y; + dtop=o->top; + + while (GFX_mouse(NULL,&y)==GFX_BUTLEFT) + { + int diff; + + diff=y-orig; + + dtop+=diff/o->sbar_step; + + o->top=(int)dtop; + + o->top=MAX(0,o->top); + o->top=MIN(o->no-o->no_lines,o->top); + + Callback(op,GuiDraw); + GFX_redraw(); + + orig=y; + } + } + else + { + if (mouse_ybar.y) + o->top=MAX(0,o->top-o->no_lines); + else + o->top=MIN(o->no-1-o->no_lines,o->top+o->no_lines); + + return GuiRedraw; + } + } + else + { + int my; + int pick; + + my=mouse_y-y; + + pick=o->top+my/LIST_TEXTHEIGHT; + + if (pickno) + { + if (pick==o->curr && (time(NULL)-last)<2 && o->double_click) + { + if (o->ent[o->curr].is_dir) + { + chdir(o->ent[o->curr].name); + GetFileList(o); + last=0; + return GuiRedraw; + } + else + return GuiDone; + } + + last=time(NULL); + + o->curr=pick; + + if (!o->ent[o->curr].is_dir) + ResetText(o->file_text,o->ent[o->curr].name); + + return GuiRedraw; + } + } + break; + + case GuiWheelUp: + return HandleFileListPage(o,GFX_PGUP); + break; + + case GuiWheelDown: + return HandleFileListPage(o,GFX_PGDN); + break; + + case GuiExit: + if (o->ent) + Release(o->ent); + break; + } + + return GuiOk; +} + + +static void TextEditInfo(GuiObjTextEdit *o) +{ + char b1[128]; + char b2[128]; + char buff[128]; + + sprintf(b1,"Cursor: %d,%d",o->x+1,o->y+1); + sprintf(b2,"Lines: %d",o->lines); + sprintf(buff,"%-20.20s %s",b1,b2); + + ResetText(o->info,buff); +} + + +static CallbackReturn TextEditCallback(GuiObj *op ,ObjEvent ev) +{ + char out; + char *tmp; + GuiObjTextEdit *te; + TextEditLine *p; + int bx,by,bw,bh; + int x,y,sx,sy; + int f; + int mod; + + te=&op->edt; + p=te->tline; + + bx=te->common.box.x; + by=te->common.box.y; + bw=te->common.box.w; + bh=te->common.box.h; + + switch(ev) + { + case GuiDraw: + if (te->common.focus) + GFX_rect(bx-2,by-2,bw+4,bh+4,GUI_TEXTBOLD); + else + GFX_rect(bx-2,by-2,bw+4,bh+4,GUI_MID); + + GFX_frect(bx,by,bw,bh,WHITE); + + y=te->top; + + for(sy=0;syheight;sy++,y++) + if (ylines) + { + x=te->col; + + for(sx=0;sxwidth;sx++,x++) + { + if (xx && y==te->y) + { + GFX_frect(bx+(sx*FW),by+(sy*FH),FW,FH,BLACK); + GFX_print(bx+(sx*FW),by+(sy*FH),WHITE,"%c",out); + } + else + GFX_print(bx+(sx*FW),by+(sy*FH),BLACK,"%c",out); + } + } + + break; + + case GuiButtonPress: + te->y=(mouse_y-by)/FH; + te->x=te->col+(mouse_x-bx)/FW; + + if (te->y>=te->lines) + te->y=te->lines-1; + + if (te->x>p[te->y].len) + te->x=p[te->y].len; + + TextEditInfo(te); + return GuiRedraw; + break; + + case GuiKeyPress: + switch(key) + { + case GFX_HOME: + te->x=0; + te->col=0; + break; + + case GFX_END: + te->x=p[te->y].len; + te->col=MAX(0,te->x-te->width); + break; + + case GFX_LEFT: + mod=ctrl||shift; + + if (mod) + while((te->x)&&(isspace(p[te->y].p[te->x]))) + { + if (te->x) + te->x--; + else + mod=FALSE; + + if (te->xcol) + te->col--; + } + + do { + if (te->x) + te->x--; + else + mod=FALSE; + + if (te->xcol) + te->col--; + + if (isspace(p[te->y].p[te->x])) + mod=FALSE; + + } while(mod); + + break; + + case GFX_RIGHT: + mod=ctrl||shift; + + if (mod) + while((te->xy].len)&& + (isspace(p[te->y].p[te->x]))) + { + te->x++; + + if ((te->x-te->width)>te->col) + te->col++; + } + + do { + if (te->xy].len) + { + te->x++; + + if ((te->x-te->width)>te->col) + te->col++; + } + else + mod=FALSE; + + if (isspace(p[te->y].p[te->x])) + mod=FALSE; + + } while(mod); + + break; + + case GFX_UP: + if (te->y) + { + te->y--; + + if (te->ytop) + te->top--; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-te->width); + } + } + break; + + case GFX_PGUP: + if (te->y) + { + te->y-=te->height; + + if (te->y<0) + te->y=0; + + if (te->ytop) + te->top=te->y; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-te->width); + } + } + break; + + case GFX_DOWN: + if (p[te->y+1].p) + { + te->y++; + + if (te->y>=te->top+te->height) + te->top=te->y-te->height+1; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-te->width); + } + } + break; + + case GFX_PGDN: + te->y+=te->height; + + if (te->y>=te->lines) + te->y=te->lines-1; + + if (te->y>=te->top+te->height) + te->top=te->y-te->height+1; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-te->width); + } + + break; + + case GFX_DELETE: + if (te->read_only) + break; + + if (p[te->y].p[te->x]) + { + for(f=te->x;fy].len;f++) + p[te->y].p[f]=p[te->y].p[f+1]; + + p[te->y].len--; + p[te->y].p[p[te->y].len]=0; + } + else if (p[te->y+1].p) + { + p[te->y].len+=p[te->y+1].len; + + p[te->y].p=ReGrab(p[te->y].p, + (p[te->y].len/TE_CHUNK+1)*TE_CHUNK+1); + + strcat(p[te->y].p,p[te->y+1].p); + + Release(p[te->y+1].p); + + for(f=te->y+1;flines;f++) + p[f]=p[f+1]; + + te->lines--; + + p=te->tline=ReGrab(te->tline, + sizeof(TextEditLine)*(te->lines+1)); + p[te->lines].p=NULL; + } + break; + + case GFX_BACKSPACE: + if (te->read_only) + break; + + if (te->x) + { + for(f=te->x;fy].len;f++) + p[te->y].p[f-1]=p[te->y].p[f]; + + p[te->y].len--; + te->x--; + p[te->y].p[p[te->y].len]=0; + + if (te->xcol) + te->col--; + } + else if (te->y) + { + te->x=p[te->y-1].len; + te->col=MAX(0,te->x-te->width); + + p[te->y-1].len+=p[te->y].len; + + p[te->y-1].p=ReGrab(p[te->y-1].p, + (p[te->y-1].len/TE_CHUNK+1)*TE_CHUNK+1); + + strcat(p[te->y-1].p,p[te->y].p); + + Release(p[te->y].p); + + for(f=te->y;flines;f++) + p[f]=p[f+1]; + + if (--te->ytop) + te->top--; + + te->lines--; + p=te->tline=ReGrab(te->tline, + sizeof(TextEditLine)*(te->lines+1)); + p[te->lines].p=NULL; + } + break; + + case GFX_ENTER: + if (te->read_only) + break; + + te->lines++; + p=te->tline=ReGrab(te->tline, + sizeof(TextEditLine)*(te->lines+1)); + + for(f=te->lines;f>te->y;f--) + p[f]=p[f-1]; + + tmp=Strdup(p[te->y].p+te->x); + tmp=ReGrab(tmp,(strlen(tmp)/TE_CHUNK+1)*TE_CHUNK+1); + + p[te->y].p[te->x]=0; + p[te->y].len=strlen(p[te->y].p); + + te->y++; + te->x=0; + te->col=0; + + p[te->y].p=tmp; + p[te->y].len=strlen(tmp); + + if (te->y>=te->top+te->height) + te->top=te->y-te->height+1; + + break; + + default: + if (ascii && !te->read_only) + { + p[te->y].len++; + + if (!(p[te->y].len%TE_CHUNK)) + p[te->y].p=ReGrab(p[te->y].p, + (p[te->y].len/TE_CHUNK+1)* + TE_CHUNK+1); + + for(f=p[te->y].len;f>te->x;f--) + p[te->y].p[f]=p[te->y].p[f-1]; + + p[te->y].p[te->x]=ascii; + + te->x++; + + if ((te->x-te->width)>te->col) + te->col++; + } + break; + } + + TextEditInfo(te); + return GuiRedraw; + break; + + case GuiWheelUp: + if (te->y) + { + te->y-=te->height; + + if (te->y<0) + te->y=0; + + if (te->ytop) + te->top=te->y; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-te->width); + } + } + + TextEditInfo(te); + return GuiRedraw; + break; + + case GuiWheelDown: + te->y+=te->height; + + if (te->y>=te->lines) + te->y=te->lines-1; + + if (te->y>=te->top+te->height) + te->top=te->y-te->height+1; + + if (te->x>p[te->y].len) + { + te->x=p[te->y].len; + te->col=MAX(0,te->x-te->width); + } + + TextEditInfo(te); + return GuiRedraw; + break; + + case GuiExit: + break; + } + + return GuiOk; +} + + +/* ---------------------------------------- DIALOG MAIN LOOP +*/ +static int DoDial(void) +{ + Pixmap saved; + int done=FALSE; + int f; + + saved=VIDOOM_GFX_SAVE_UNDER(dialog[0].common.box.x, + dialog[0].common.box.y, + dialog[0].common.box.w, + dialog[0].common.box.h); + + for(f=0;(fx,b->y,b->w,b->h,GUI_MID); + + GFX_print(b->x+SMALL_BEVEL+2,b->y+b->h/2-FH/2,GUI_TEXT,txt); + + if (child) + { + h=b->h-(SMALL_BEVEL*2)-2; + hy=b->y+SMALL_BEVEL+1; + + GFX_line(b->x+b->w-SMALL_BEVEL-2-h/2,hy, + b->x+b->w-SMALL_BEVEL-2,hy+h/2,GUI_HI); + + GFX_line(b->x+b->w-SMALL_BEVEL-2-h/2,hy, + b->x+b->w-SMALL_BEVEL-2-h/2,hy+h,GUI_HI); + + GFX_line(b->x+b->w-SMALL_BEVEL-2-h/2,hy+h, + b->x+b->w-SMALL_BEVEL-2,hy+h/2,GUI_LO); + } +} + + +static MenuControl do_GUI_menu(char *title, int x, int y, + PLAT_MENU menu[],int defval,int is_child) +{ + Pixmap under; + MenuControl ret; + MenuControl cr; + int no; + int f; + int cur; + int last_cur; + int cx; + int by; + int done; + int quit; + int child_done; + BoundBox *box; + BoundBox menu_box; + int do_child; + + /* Calc dimensions + */ + no=0; + menu_box.x=x; + menu_box.y=y; + menu_box.w=LENGTH(title); + + while(menu[no].text) + { + int l; + + l=LENGTH(menu[no].text)+(menu[no].child ? 12 : 0); + menu_box.w=MAX(menu_box.w,l); + no++; + } + + menu_box.h=BEVEL*2+FH+4; + menu_box.h+=(FH+SMALL_BEVEL*2+2)*no; + menu_box.h+=2; + menu_box.w+=BEVEL+SMALL_BEVEL+4; + + box=Grab(sizeof(*box)*no); + + if ((menu_box.x+menu_box.w)>SCRW) + menu_box.x=SCRW-menu_box.w; + + if ((menu_box.y+menu_box.h)>SCRH) + menu_box.y=SCRH-menu_box.h; + + if ((menu_box.x<0)||(menu_box.y<0)) + { + fprintf(stderr, + "Cannot display menu:%s\nMenu is bigger than display!\n",title); + + ret.mode=MENU_CHILD_RETURN; + ret.ret=defval; + + return ret; + } + + under=VIDOOM_GFX_SAVE_UNDER(menu_box.x,menu_box.y,menu_box.w,menu_box.h); + + cx=menu_box.x+menu_box.w/2; + + /* Draw menu border and title + */ + Rect3DBox(&menu_box,FALSE,BEVEL); + CENTRE(cx,menu_box.y+BEVEL*2,GUI_TEXTBOLD,title); + + /* Draw menu items + */ + cur=0; + last_cur=0; + + by=menu_box.y+BEVEL*2+FH+4; + + for(f=0;fw); + max_imgh=MAX(max_imgh,i->h); + } + + no++; + } + + optset=Grab(sizeof(char *)*no); + imgset=Grab(sizeof(GFX_IMAGE)*no); + + for(f=0;f(SCRW-FW*5)) + width-=FW; + + while (height>(SCRH-FH*5)) + height-=FH; + + x=(SCRW-width)/2; + y=(SCRH-height)/2; + + info=CreateText(x,y-FH*2,width,FH*1.5,"",GuiTextReadOnly,FALSE); + edit=CreateTextEdit(x,y,width,height,line,no,info,TRUE); + + ok=CreateButton(x+10,y+height+FH*2,width-20,FH*2,"OK"); + + ResizeBox(box); + + DoDial(); + + for(f=0;f(SCRW-FW*5)) + width-=FW; + + while (height>(SCRH-FH*5)) + height-=FH; + + x=(SCRW-width)/2; + y=(SCRH-height)/2; + + info=CreateText(x,y-FH*2,width,FH*1.5,"",GuiTextReadOnly,FALSE); + edit=CreateTextEdit(x,y,width,height,line,no,info,FALSE); + + ok=CreateButton(x+10,y+height+FH*2,width/2-20,FH*2,"OK"); + cancel=CreateButton(SCRW/2+10,y+height+FH*2,width/2-20,FH*2,"Cancel"); + + ResizeBox(box); + + press=DoDial(); + + if (press==ok) + { + int tot; + + tot=0; + + for(f=0;f +#include + +#define MAX_CMDSIZE 8192 + +static void Write(int fd, char *p) +{ + /* Should really do a loopy proper one... + */ + write(fd,p,strlen(p)); +} + + +int RunCommand(char *argv[], char *path) +{ + FILE *fp; + int output; + int f; + char buff[MAX_CMDSIZE]; + + f=0; + buff[0]=0; + + while(argv[f]) + { + strcat(buff,argv[f++]); + strcat(buff," "); + } + + strcpy(path,"vidoomXXXXXX"); + + if ((output=mkstemp(path))==-1) + return FALSE; + + if (!(fp=popen(buff,"r"))) + return FALSE; + + fgets(buff,sizeof buff,fp); + + while(!feof(fp)) + { + Write(output,buff); + fgets(buff,sizeof buff,fp); + } + + /* Assume that non-zero is error + */ + return pclose(fp)==0; +} + + +/* END OF FILE */ diff --git a/linux/vstring.c b/linux/vstring.c new file mode 100644 index 0000000..947ca99 --- /dev/null +++ b/linux/vstring.c @@ -0,0 +1,48 @@ +/* + + 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) +{ + if (!a || !b) + return 0; + + return strcasecmp(a,b); +} + +int StrNCaseCmp(char *a, char *b, int n) +{ + if (!a || !b) + return 0; + + return strncasecmp(a,b,n); +} + + +/* END OF FILE */ diff --git a/list.c b/list.c new file mode 100644 index 0000000..7249db4 --- /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 VIDOOM_Elem + { + char *data; + struct VIDOOM_Elem *next; + struct VIDOOM_Elem *prev; + }; + +struct VIDOOM_List + { + int no; + int size; + struct VIDOOM_Elem *head; + struct VIDOOM_Elem *tail; + }; + +struct VIDOOM_Iterator + { + List l; + struct VIDOOM_Elem *e; + }; + +/* ---------------------------------------- +*/ +List ListNew(int type_size) +{ + List nl; + + nl=Grab(sizeof(struct VIDOOM_List)); + + nl->no=0; + nl->size=type_size; + nl->head=NULL; + nl->tail=NULL; + + return(nl); +} + +List ListClear(List l) +{ + struct VIDOOM_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 VIDOOM_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 VIDOOM_Iterator *i; + + if (!l->head) + return(NULL); + + i=Grab(sizeof(struct VIDOOM_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 VIDOOM_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 VIDOOM_Elem *e; + + e=Grab(sizeof(struct VIDOOM_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 VIDOOM_Elem *e; + + e=Grab(sizeof(struct VIDOOM_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 VIDOOM_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..f3c67ac --- /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 VIDOOM_LIST_H + +#define VIDOOM_LIST_H + +/* Opaque types for the list and iterator. NULL is the null list and iterator. +*/ +struct VIDOOM_List; +typedef struct VIDOOM_List *List; + +struct VIDOOM_Iterator; +typedef struct VIDOOM_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/cygwin-xfree.cfg b/make/cygwin-xfree.cfg new file mode 100644 index 0000000..64303af --- /dev/null +++ b/make/cygwin-xfree.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 CYGWIN (using X11) +# +# $Id: cygwin-xfree.cfg,v 1.1 2002/09/05 20:00:23 ianc Exp ianc $ +# +CC= gcc +LD= gcc +PLATFORM= linux +EXE_EXT= .exe +OBJ_EXT= .o +LIBS= -lX11 +EXTRACF= -g -O -Wall -I/usr/X11R6/include +EXTRALF= -L/usr/X11R6/lib +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 +RMCMD= rm -f diff --git a/make/djgpp.cfg b/make/djgpp.cfg new file mode 100644 index 0000000..637d07e --- /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.8 2001/12/25 09:34:38 ianc Exp ianc $ +# +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 +RMCMD= rm -f diff --git a/make/linux.cfg b/make/linux.cfg new file mode 100644 index 0000000..d6d22c9 --- /dev/null +++ b/make/linux.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 LINUX (using X11) +# +# $Id: linux.cfg,v 1.2 2002/09/05 19:59:11 ianc Exp ianc $ +# +CC= gcc +LD= gcc +PLATFORM= linux +EXE_EXT= +OBJ_EXT= .o +LIBS= -lX11 +EXTRACF= -g -O -Wall -I/usr/X11R6/include +EXTRALF= -L/usr/X11R6/lib +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 +RMCMD= rm -f diff --git a/map.c b/map.c new file mode 100644 index 0000000..bf02b07 --- /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 VIDOOM_Map + { + int top; + int alloc; + int size; + char *data; + }; + +/* ---------------------------------------- +*/ +Map MapNew(int type_size) +{ + Map nm; + + nm=Grab(sizeof(struct VIDOOM_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 VIDOOM_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..e8b8b65 --- /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 VIDOOM_MAP_H + +#define VIDOOM_MAP_H + +/* Opaque types for the map. NULL is the null map. +*/ +struct VIDOOM_Map; +typedef struct VIDOOM_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..2795af5 --- /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 VIDOOM_MEM_H + +#define VIDOOM_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/names.c b/names.c new file mode 100644 index 0000000..5db6102 --- /dev/null +++ b/names.c @@ -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 + + ------------------------------------------------------------------------- + + Returns the constant names for the game and the map names + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "names.h" +#include "globals.h" +#include "file.h" + +typedef struct + { + char *map; + char *name; + } MapNameList; + +static MapNameList doom_maps[]= + { + {"E1M1","Hangar"}, + {"E1M2","Nuclear Plant"}, + {"E1M3","Toxin Refinery"}, + {"E1M4","Command Control"}, + {"E1M5","Phobos Lab"}, + {"E1M6","Central Processing"}, + {"E1M7","Computer Station"}, + {"E1M8","Phobos Anomaly"}, + {"E1M9","Military Base"}, + {"E2M1","Deimos Anomaly"}, + {"E2M2","Containment Area"}, + {"E2M3","Refinery"}, + {"E2M4","Deimos Lab"}, + {"E2M5","Command Center"}, + {"E2M6","Halls of the Damned"}, + {"E2M7","Spawning Vats"}, + {"E2M8","Tower of Babel"}, + {"E2M9","Fortress of Mystery"}, + {"E3M1","Hell Keep"}, + {"E3M2","Slough of Despair"}, + {"E3M3","Pandemonium"}, + {"E3M4","House of Pain"}, + {"E3M5","Unholy Cathedral"}, + {"E3M6","Mt. Erebus"}, + {"E3M7","Limbo"}, + {"E3M8","Dis"}, + {"E3M9","Warrens"}, + {"E4M1","Hell Beneath"}, + {"E4M2","Perfect Hatred"}, + {"E4M3","Sever The Wicked"}, + {"E4M4","Unruly Evil"}, + {"E4M5","They Will Repent"}, + {"E4M6","Against Thee Wickedly"}, + {"E4M7","And Hell Followed"}, + {"E4M8","Unto The Cruel"}, + {"E4M9","Fear"}, + {NULL,NULL} + }; + +static MapNameList doom2_maps[]= + { + {"MAP01","Entryway"}, + {"MAP02","Underhalls"}, + {"MAP03","The Gantlet"}, + {"MAP04","The Focus"}, + {"MAP05","The Waste Tunnels"}, + {"MAP06","The Crusher"}, + {"MAP07","Dead Simple"}, + {"MAP08","Tricks and Traps"}, + {"MAP09","The Pit"}, + {"MAP10","Refueling Base"}, + {"MAP11","'O' of Destruction!"}, + {"MAP12","The Factory"}, + {"MAP13","Downtown"}, + {"MAP14","The Inmost Dens"}, + {"MAP15","Industrial Zone"}, + {"MAP16","Suburbs"}, + {"MAP17","Tenements"}, + {"MAP18","The Courtyard"}, + {"MAP19","The Citadel"}, + {"MAP20","Gotcha!"}, + {"MAP21","Nirvana"}, + {"MAP22","The catacombs"}, + {"MAP23","Barrels O' Fun"}, + {"MAP24","The Chasm"}, + {"MAP25","Bloodfalls"}, + {"MAP26","The Abandoned Mines"}, + {"MAP27","Monster Condo"}, + {"MAP28","The Spirit World"}, + {"MAP29","The Living End"}, + {"MAP30","Icon Of Sin"}, + {"MAP31","Wolfenstein"}, + {"MAP32","Grosse"}, + {NULL,NULL} + }; + +static MapNameList plut_maps[]= + { + {"MAP01","Congo"}, + {"MAP02","Well of Souls"}, + {"MAP03","Aztec"}, + {"MAP04","Caged"}, + {"MAP05","Ghost Town"}, + {"MAP06","Baron's Lair"}, + {"MAP07","Caughtyard"}, + {"MAP08","Realm"}, + {"MAP09","Abattoire"}, + {"MAP10","Onslaught"}, + {"MAP11","Hunted"}, + {"MAP12","Speed"}, + {"MAP13","The Crypt"}, + {"MAP14","Genesis"}, + {"MAP15","The Twilight"}, + {"MAP16","The Omen"}, + {"MAP17","Compound"}, + {"MAP18","Neurosphere"}, + {"MAP19","NME"}, + {"MAP20","The Death Domain"}, + {"MAP21","Slayer"}, + {"MAP22","Impossible Mission"}, + {"MAP23","Tombstone"}, + {"MAP24","The Final Frontier"}, + {"MAP25","The Temple of Darkness"}, + {"MAP26","Bunker"}, + {"MAP27","Anti-Christ"}, + {"MAP28","The Sewers"}, + {"MAP29","Odyssey of Noises"}, + {"MAP30","The Gateway of Hell"}, + {"MAP31","Cyberden"}, + {"MAP32","Go 2 It"}, + {NULL,NULL} + }; + +static MapNameList tnt_maps[]= + { + {"MAP01","System Control"}, + {"MAP02","Human BBQ"}, + {"MAP03","Power Control"}, + {"MAP04","Wormhole"}, + {"MAP05","Hanger"}, + {"MAP06","Open Season"}, + {"MAP07","Prison"}, + {"MAP08","Metal"}, + {"MAP09","Stronghold"}, + {"MAP10","Redemption"}, + {"MAP11","Storage Facility"}, + {"MAP12","Crater"}, + {"MAP13","Nukage Processing"}, + {"MAP14","Steel Works"}, + {"MAP15","Dead Zone"}, + {"MAP16","Deepest Reaches"}, + {"MAP17","Processing Area"}, + {"MAP18","Mill"}, + {"MAP19","Shipping/Respawning"}, + {"MAP20","Central Processing"}, + {"MAP21","Administration Center"}, + {"MAP22","Habitat"}, + {"MAP23","Lunar Mining Project"}, + {"MAP24","Quarry"}, + {"MAP25","Baron's Den"}, + {"MAP26","Ballistyx"}, + {"MAP27","Mount Pain"}, + {"MAP28","Heck"}, + {"MAP29","River Styx"}, + {"MAP30","Last Call"}, + {"MAP31","Pharaoh"}, + {"MAP32","Caribbean"}, + {NULL,NULL} + }; + +/* ---------------------------------------- +*/ +static char *FindName(MapNameList *nl, char *map) +{ + int f; + + f=0; + while(nl[f].map) + { + if (STREQ(map,nl[f].map)) + return(nl[f].name); + + f++; + } + + return ("Unknown map!"); +} + + +/* ---------------------------------------- +*/ + +char *GameName(void) +{ + switch(game) + { + case DOOM: + return ("Doom - Knee Deep in The Dead"); + break; + case ULTIMATE_DOOM: + return ("Ultimate Doom - Thy Flesh Consumed"); + break; + case DOOM_2: + return ("Doom 2 - Hell On Earth"); + break; + case FINAL_TNT: + return ("Final Doom - TNT:Evilution"); + break; + case FINAL_PLUTONIA: + return ("Final Doom - The Plutonia Experiment"); + break; + case ZDOOM: + return ("ZDoom/BOOM extensions to Doom"); + break; + } + + return ("Game type undefined!"); +} + + +char *MapName(char *map) +{ + if (STREQ(Basename(IWAD_path),"doom.wad")) + return (FindName(doom_maps,map)); + else if (STREQ(Basename(IWAD_path),"doom2.wad")) + return (FindName(doom2_maps,map)); + else if (STREQ(Basename(IWAD_path),"tnt.wad")) + return (FindName(tnt_maps,map)); + else if (STREQ(Basename(IWAD_path),"plutonia.wad")) + return (FindName(plut_maps,map)); + + return ("Unknown IWAD - no map names!"); +} + + +/* END OF FILE */ diff --git a/names.h b/names.h new file mode 100644 index 0000000..bd4bc11 --- /dev/null +++ b/names.h @@ -0,0 +1,43 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Returns the constant names for the game and the map names + + $Id$ + + +*/ + +#ifndef VIDOOM_NAMES_H + +#define VIDOOM_NAMES_H + +/* Return game name. Bases this on game from globals.o +*/ +char *GameName(void); + +/* Given a level name returns the map name. Bases this on the basename() of + IWAD_path from globals.o +*/ +char *MapName(char *map); + +#endif diff --git a/platgui.h b/platgui.h new file mode 100644 index 0000000..9a27994 --- /dev/null +++ b/platgui.h @@ -0,0 +1,258 @@ +/* + + 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 VIDOOM_PLATGUI_H +#define VIDOOM_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 PLATMENU + { + char *text; /* Text to display */ + int client_index; /* Value returned by GUI_menu() */ + struct PLATMENU *child; /* NULL if no child menu, else */ + /* pointer to other menu array. */ + } 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 multi flag box +*/ +typedef struct + { + char *text; /* Label. NULL = end */ + int group; /* To group flags (0 = don't group) */ + int val; /* TRUE = set, FALSE = flag clear */ + } PLAT_MULTI; + +/* 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 +#define PLAT_DIAL_PICKLIST 3 + +/* This is the picklist type that can be used inside a DIALOG. It matters + not how it's implemented, but it should be able to use large picklists + (eg. the amount of the list seen should be automatically limited). +*/ +typedef struct + { + int no; /* No of items */ + int current; /* Currently selected item */ + char **text; /* Text for items - used as *item[] */ + } PLAT_DIAL_PL; + +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; + PLAT_DIAL_PL pl; + } 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. The text + defined by question should be split over lines where a '|' character appears. +*/ +int GUI_yesno(char *question); + + +/* Starts a Yes/No/Yes to All/No to All cycle. After calling this + GUI_yesno_all() is reset to it's initial state. +*/ +void GUI_start_yesno_all(void); + + +/* Works like GUI_yesno(), but displays to extra options - "Yes to All" and + "No to All". If either of these options are selected then further calls + to this function should return TRUE/FALSE accordingly, until + GUI_start_yesno__all() is called. +*/ +int GUI_yesno_all(char *question); + + +/* Displays a dialog with the title and text supplied. This text should split + where a '|' character appears. A sole button containing the supplied + button_text should be displayed. +*/ +void GUI_alert(char *title, char *text, char *button_text); + + +/* 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 PLAT_MULTI passed in. + + Returns TRUE if dialog accepted, otherwise FALSE. +*/ +int GUI_multi_box(char *title,PLAT_MULTI p[]); + + +/* 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[]); + + +/* Displays the contents of a file. The form this display takes is not really + of any concern to viDOOM. + + Control codes should just be filtered out. Tabs should be converted to + spaces, or honoured. + + This interface is used for reading the license from the menu, and for + reading the results from running the node builder. +*/ +void GUI_view_file(char *title, char *path); + + +/* Allows simple text editting. The form this display takes is not really + of any concern to viDOOM (if applicable it would be more than OK to start + an external text editor). + + text is a pointer to the original text, which is one long string with line + breaks denoted by the '\n' character. Note that lines should _only_ be + terminated with the \n character (ie. MSDOS stlye \r\n need not be accepted + by this routine). + + The return is a newly allocated copy of the edited text is the text is OKed. + The return is NULL if the text is cancelled. + + In either case, the original string pointed to by text should be as it was. +*/ +char *GUI_text_edit(char *title, char *text); + + +#endif + + +/* END OF FILE */ diff --git a/runcmd.h b/runcmd.h new file mode 100644 index 0000000..06c341e --- /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 VIDOOM_RUNCMD_H + +#define VIDOOM_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..63331de --- /dev/null +++ b/sectors.c @@ -0,0 +1,319 @@ +/* + + 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[2]={0,0}; + +static Map sect_class[2]={NULL,NULL}; +static List sect_list[2]={NULL,NULL}; +static Map sect_style=NULL; + +static PLAT_MENU *menu[2]={NULL,NULL}; +static PLAT_PICKLIST **picklist[2]={NULL,NULL}; + +static char **sect_style_plist=NULL; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static int Index(int flag) +{ + if (flag) + return(1); + else + return(0); +} + + +static PLAT_PICKLIST *SectorPicklist(int index, int class) +{ + SectorInfo *si; + Iterator i; + int no; + int f; + + if (picklist[index][class]) + return(picklist[index][class]); + + no=0; + i=ListIterator(sect_list[index]); + + while(i) + { + si=IteratorData(i); + + if (si->class==class) + no++; + + i=IteratorNext(i); + } + + picklist[index][class]=Grab(sizeof(PLAT_PICKLIST)*(no+1)); + + i=ListIterator(sect_list[index]); + + f=0; + while(i) + { + si=IteratorData(i); + + if (si->class==class) + { + picklist[index][class][f].text=si->long_name; + picklist[index][class][f].client_index=si->id; + f++; + } + + i=IteratorNext(i); + } + + picklist[index][class][f].text=NULL; + + return(picklist[index][class]); +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void SectorNewClass(int hexen, char *class) +{ + SectorClass c; + + hexen=Index(hexen); + + if (!sect_class[hexen]) + sect_class[hexen]=MapNew(sizeof(SectorClass)); + + c.name=Strdup(class); + + MapAdd(sect_class[hexen],no_classes[hexen]++,&c); +} + + +void SectorAdd(int hexen, char *class,int id,char *long_name,char *short_name) +{ + SectorInfo *s; + int i_class; + int f; + + hexen=Index(hexen); + + if (!sect_list[hexen]) + sect_list[hexen]=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[hexen],s); +} + + +int SelectSector(int hexen) +{ + int class; + int f; + int x,y; + + hexen=Index(hexen); + + if (!menu[hexen]) + { + menu[hexen]=Grab(sizeof(PLAT_MENU)*(no_classes[hexen]+1)); + picklist[hexen]=Grab(sizeof(PLAT_IMG_PICKLIST *)*(no_classes[hexen]+1)); + + for(f=0;fname; + menu[hexen][f].client_index=f; + } + + for(f=0;fid==id) + { + IteratorClear(i); + return(si->short_name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +void AddSectorStyle(char *name, int flags, DirName upper, DirName middle, + DirName lower, DirName floor, DirName ceiling) +{ + SectorStyle s; + + if (!sect_style) + sect_style=MapNew(sizeof(SectorStyle)); + + 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..550fe88 --- /dev/null +++ b/sectors.h @@ -0,0 +1,95 @@ +/* + + 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 VIDOOM_SECTORS_H + +#define VIDOOM_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. Set hexen TRUE for a HEXEN sector. +*/ +void SectorNewClass(int hexen, char *class); + + +/* Add the named type to the supplied class with the ID. + Set hexen TRUE for a HEXEN sector. +*/ +void SectorAdd(int hexen,char *class,int id, + char *long_name, char *short_name); + + +/* Select the ID type for a sector. Returns SECTOR_NULLID if cancelled. + Set hexen TRUE for a HEXEN sector. +*/ +int SelectSector(int hexen); + + +/* Returns the short name of a sector type +*/ +char *SectorName(int hexen, int id); + + +/* 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/specials.c b/specials.c new file mode 100644 index 0000000..44bb5e7 --- /dev/null +++ b/specials.c @@ -0,0 +1,319 @@ +/* + + 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 ACTION SPECIALS + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "platgui.h" +#include "gui.h" +#include "gfx.h" +#include "specials.h" +#include "mem.h" +#include "list.h" +#include "map.h" + + +/* ---------------------------------------- TYPES AND VARS +*/ +typedef struct + { + char *name; + } SpecialClass; + +typedef struct + { + int class; + int id; + char *name; + int no_args; + char *arg[5]; + } SpecialInfo; + +static int no_classes=0; + +static Map special_class=NULL; +static List special_list=NULL; + +static PLAT_PICKLIST **picklist=NULL; + +static PLAT_MENU *special_menu=NULL; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static PLAT_PICKLIST *SpecialPicklist(int class) +{ + SpecialInfo *si; + Iterator i; + int no; + int f; + + if (picklist[class]) + return(picklist[class]); + else + { + no=0; + i=ListIterator(special_list); + + while(i) + { + si=IteratorData(i); + + if (si->class==class) + no++; + + i=IteratorNext(i); + } + + picklist[class]=Grab(sizeof(PLAT_PICKLIST)*(no+1)); + + i=ListIterator(special_list); + + f=0; + while(i) + { + si=IteratorData(i); + + if (si->class==class) + { + picklist[class][f].text=si->name; + picklist[class][f].client_index=si->id; + f++; + } + + i=IteratorNext(i); + } + + picklist[class][f].text=NULL; + + return(picklist[class]); + } +} + + + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void SpecialNewClass(char *class) +{ + SpecialClass c; + + if (!special_class) + special_class=MapNew(sizeof(SpecialClass)); + + c.name=Strdup(class); + + MapAdd(special_class,no_classes++,&c); +} + + +void SpecialAdd(char *class,char *name,int id, char *arg[5]) +{ + SpecialInfo *si; + int i_class; + int f; + + if (!special_list) + special_list=ListNew(sizeof(SpecialInfo)); + + i_class=-1; + + for(f=0;fname,class)) + i_class=f; + } + + if (i_class==-1) + i_class=0; + + si=Grab(sizeof(SpecialInfo)); + + si->class=i_class; + si->name=Strdup(name); + si->id=id; + si->no_args=0; + + for(f=0;(f<5)&&(arg[f]);f++) + { + si->arg[f]=Strdup(arg[f]); + si->no_args++; + } + + ListAppend(special_list,si); +} + + +int SelectSpecial(void) +{ + int class; + int f; + int x,y; + + if (!special_menu) + { + special_menu=Grab(sizeof(PLAT_MENU)*(no_classes+1)); + picklist=Grab(sizeof(PLAT_PICKLIST *)*(no_classes+1)); + + for(f=0;fname; + special_menu[f].client_index=f; + } + + for(f=0;fid==id) + { + IteratorClear(i); + + if (arg) + for(f=0;fno_args;f++) + arg[f]=si->arg[f]; + + return(si->name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +int SpecialArgDialog(char *prompt, int id, int arg[5]) +{ + PLAT_DIALOG d[5]; + SpecialInfo *si; + Iterator i; + char *pd; + int f; + + i=ListIterator(special_list); + + while(i) + { + si=IteratorData(i); + + if (si->id==id) + { + IteratorClear(i); + + if (si->no_args) + { + for(f=0;fno_args;f++) + { + d[f].text=si->arg[f]; + d[f].type=PLAT_DIAL_INTEGER; + d[f].data.i=arg[f]; + } + + if (!prompt) + pd=Strdup(si->name); + else + { + pd=Grab(strlen(si->name)+strlen(prompt)+4); + sprintf(pd,"%s - %s",si->name,prompt); + } + + if (GUI_dialog(pd,si->no_args,d)) + { + for(f=0;f<5;f++) + arg[f]=0; + + for(f=0;fno_args;f++) + arg[f]=d[f].data.i; + + Release(pd); + return(TRUE); + } + else + { + Release(pd); + return(FALSE); + } + } + else + { + GuiInfoBox("ACTION SPECIAL ARGUMENTS", + "Special '%s'|has no arguments",si->name); + return(FALSE); + } + } + + i=IteratorNext(i); + } + + GuiInfoBox("ACTION SPECIAL ARGUMENTS","Passed in type %s unknown",id); + return(FALSE); +} + + +/* END OF FILE */ diff --git a/specials.h b/specials.h new file mode 100644 index 0000000..a0b6e6b --- /dev/null +++ b/specials.h @@ -0,0 +1,74 @@ +/* + + 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 ACTION SPECIALS (Hexen) + + $Id$ + +*/ + +#ifndef VIDOOM_SPECIALS_H + +#define VIDOOM_SPECIALS_H + +/* This is not going to be an ID, so is used to detect whether LinedefSelect() + was cancelled. +*/ +#define SPECIAL_NULLID -666 + + +/* Add a new class of special +*/ +void SpecialNewClass(char *class); + + +/* Add the named type to the supplied class with the ID and 5 arguments. + Unused arguments can be NULL +*/ +void SpecialAdd(char *class,char *name,int id,char *arg[5]); + + +/* Selects a type of special, returning the ID or SPECIAL_NULLID if cancelled +*/ +int SelectSpecial(void); + + +/* Returns the name of a special action. If not NULL then the argument names + are placed in args. +*/ +char *SpecialName(int id,char *arg[5]); + + +/* Displays a dialog box to set arguments for the supplied ID. Returns + FALSE if the dialog is cancelled. If OKed then TRUE is returned and arg[] + will hold the new argument values. + + If prompt is not NULL it is displayed along with the special name in the + dialog where the arguments are entered. +*/ +int SpecialArgDialog(char *prompt,int id,int arg[5]); + + +#endif + + +/* END OF FILE */ diff --git a/texture.c b/texture.c new file mode 100644 index 0000000..1d109e4 --- /dev/null +++ b/texture.c @@ -0,0 +1,592 @@ +/* + + 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 *GetMemShort(Byte *p,Short *s) +{ + *s=(Short)(*p++); + *s|=((Short)(*p++))<<8; + return(p); +} + + +static Byte *GetMemLong(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=GetMemShort(lump,&lw); + lump=GetMemShort(lump,&lh); + lump=GetMemShort(lump,&lox); + lump=GetMemShort(lump,&loy); + + lox=MAX(lox,0); + loy=MAX(loy,0); + + for(x=0;xw=MIN(w,MAX_GFXBM_W); + + t_ent=GetMemShort(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=GetMemShort(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"); +} + + +/* END OF FILE */ diff --git a/things.h b/things.h new file mode 100644 index 0000000..49f03a5 --- /dev/null +++ b/things.h @@ -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 + + ------------------------------------------------------------------------- + + Handles definition and storage of the supported THINGS + + $Id$ + +*/ + +#ifndef VIDOOM_THINGS_H + +#define VIDOOM_THINGS_H + +#include "gfx.h" +#include "platgui.h" + + +/* This is not going to be an ID, so is used to detect whether ThingSelect() + was cancelled. +*/ +#define THING_NULLID -666 + + +/* Add a new class of things +*/ +void ThingNewClass(char *class, int col); + + +/* Add the named type to the supplied class with the ID and radius +*/ +void ThingAdd(char *class,char *name,int id,int rad,GFX_IMAGE sprite); + + +/* Selects a type of thing, returning the ID or THING_NULLID if cancelled +*/ +int SelectThing(void); + + +/* Given an ID returns the radius of the THING. If col is not NULL also + returns the colour of the thing. +*/ +int ThingRadius(int id,int *col); + + +/* Returns the name of a thing +*/ +char *ThingName(int id); + + +#endif + + +/* END OF FILE */ diff --git a/todo b/todo new file mode 100644 index 0000000..1c926c1 --- /dev/null +++ b/todo @@ -0,0 +1,4 @@ +* Update docs with DJGPP sys dependent part. Update docs for new editing + functions. + +* Add left_click_move option to docs diff --git a/util.c b/util.c new file mode 100644 index 0000000..f8837c4 --- /dev/null +++ b/util.c @@ -0,0 +1,253 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Utility functions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include +#include +#include "mem.h" +#include "util.h" + +#define TRIM_NO 10 +#define TRIM_MAX 80 + + +char *TrimStr(char *p, int n) +{ + static int i=0; + static char trim[TRIM_NO][TRIM_MAX+1]; + int l; + + i=(i+1)%TRIM_NO; + n=MIN(n,TRIM_MAX); + l=strlen(p); + + if (n>l) + strcpy(trim[i],p); + else + { + strncpy(trim[i],p,n); + trim[i][n-2]='.'; + trim[i][n-1]='.'; + trim[i][n]=0; + } + + return(trim[i]); +} + + +char *UnMSDOS(char *p) +{ + char *op; + + op=p; + + while(p && *p) + { + if ((*p=='\r')&&(*(p+1)=='\n')) + { + char *s1,*s2; + + s1=p; + s2=p+1; + + while((*s1++=*s2++)); + } + + p++; + } + + return(op); +} + + +char *ApplyMSDOS(char *p, int rel) +{ + char *ret; + char *t,*o; + int l; + + t=o=p; + + l=0; + + while(*t) + { + if (*t++=='\n') + l++; + + l++; + } + + ret=Grab(l+1); + t=ret; + + while(*p) + { + if (*p=='\n') + *t++='\r'; + + *t++=*p++; + } + + if (rel) + Release(o); + + return(ret); +} + + +void UCase(char *p) +{ + while(*p) + { + if (islower(*p)) + *p=toupper(*p); + p++; + } +} + + +void LCase(char *p) +{ + while(*p) + { + if (isupper(*p)) + *p=tolower(*p); + p++; + } +} + + +Byte GetByte(FILE *fp) +{ + return ((Byte)fgetc(fp)); +} + + +Word GetWord(FILE *fp) +{ + return ((Word)fgetc(fp)|((Word)fgetc(fp))<<8); +} + + +Long GetLong(FILE *fp) +{ + return ((Long)fgetc(fp)| + ((Long)fgetc(fp))<<8| + ((Long)fgetc(fp))<<16| + ((Long)fgetc(fp))<<24); +} + + +void PutByte(FILE *fp,Byte b) +{ + fputc(b,fp); +} + + +void PutShort(FILE *fp,Short s) +{ + fputc(s&0xff,fp); + fputc((s>>8)&0xff,fp); +} + + +void PutUShort(FILE *fp,UShort s) +{ + fputc(s&0xff,fp); + fputc((s>>8)&0xff,fp); +} + + +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); +} + + +int FRead(FILE *fp, void *buff, int size) +{ + char *p; + int tot,rd; + + tot=0; + p=buff; + + while(tot + +/* Returns a static copy of the string, which if it is over n characters long + will be trimmed to n-3 character and "..." appended. + + Note this function's return is static, but there can be 10 invocations + before the same memory is used (ie. it's safe to use more than once in + function calls). + + Note that string longer than a certain length will be trimmed regardless. +*/ +char *TrimStr(char *p, int n); + + +/* Alters the string so that all occurances of '\r\n' are converted to '\n'. + The return is the same pointer passed in p, after the conversion. + + NULL is returned unaltered. +*/ +char *UnMSDOS(char *p); + + +/* Alters the string so that all occurances of '\n' are converted to '\r\n'. + If rel is TRUE, the passed pointer p is released with Release() after + conversion. + + The return is a newly allocated copy of the converted string. +*/ +char *ApplyMSDOS(char *p, int rel); + + +/* Uppercase the supplied string +*/ +void UCase(char *p); + + +/* Lowercase the supplied string +*/ +void LCase(char *p); + + +/* Read a byte from a file +*/ +Byte GetByte(FILE *fp); + + +/* Read a word from a file, and macros to read Short and UShort +*/ +Word GetWord(FILE *fp); + +#define GetShort(fp) ((Short)GetWord(fp)) +#define GetUShort(fp) ((UShort)GetWord(fp)) + + +/* Read a long from a file +*/ +Long GetLong(FILE *fp); + + +/* Put a byte to a file +*/ +void PutByte(FILE *fp,Byte b); + + +/* Put a short to a file +*/ +void PutShort(FILE *fp,Short s); + + +/* Put an unsigned short to a file +*/ +void PutUShort(FILE *fp,UShort s); + + +/* Put a long to a file +*/ +void PutLong(FILE *fp,Long l); + + +/* A skin over fread(), that does any necessary looping. Returns 'size' on + sucess, -1 on failure. size is in bytes. +*/ +int FRead(FILE *fp, void *buff, int size); + + +/* A skin over fwrite(), that does any necessary looping. Returns 'size' on + sucess, -1 on failure. size is in bytes. +*/ +int FWrite(FILE *fp, void *buff, int size); + + +/* Returns the size of a file. Does this by seeking to end and getting the + position. Note that the original position is restored. +*/ +long FLen(FILE *fp); + + +#endif diff --git a/vidoom.c b/vidoom.c new file mode 100644 index 0000000..467912c --- /dev/null +++ b/vidoom.c @@ -0,0 +1,892 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Doom I/II editor + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include +#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" +#include "names.h" +#include "util.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); +static int CreateHexenMap(void); + + +/* ---------------------------------------- MAIN +*/ +int viDOOM(int argc,char *argv[]) +{ + char *load,*p; + int f; + + if (getenv("VIDOOM_DIR")) + Cd(getenv("VIDOOM_DIR")); + + GFX_init(); + + 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)); + + dir[f]=wd; + list[f]=Strdup(s); + + f++; + } + + list[f]=NULL; + + if ((opt=GUI_picklist + ("WAD DIR (Name, Offset, Size, WAD file)",list))!=-1) + { + char asc[9]; + unsigned char *lump; + Long len; + FILE *fp; + char *path; + int r; + + if ((lump=GetLumpFrom(dir[opt],&len))) + { + if (len) + { + path=tmpnam(NULL); + if ((fp=fopen(path,"w"))) + { + f=0; + + while(fname, + dir[opt]->off, + dir[opt]->size, + Basename(dir[opt]->wad)); + + GUI_view_file(s,path); + + remove(path); + } + } + else + GuiInfoBox("NOTICE", + "%s is a zero length lump",dir[opt]->name); + + Release(lump); + } + } + + f=0; + while(list[f]) + { + Release(list[f]); + f++; + } + + Release(list); + Release(dir); + + 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_LICENSE: + GUI_view_file("viDOOM " VIDOOMVER " " VIDOOMRELEASE, + "LICENSE"); + break; + + case MENU_QUIT: + if ((map_exit_warn)&&(edited)) + quit=GUI_yesno("Map may have been changed " + "- really quit?"); + else + quit=TRUE; + break; + +#ifdef VIDOOM_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..cf4178c --- /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_VIDOOM_H + +#define VIDOOM_VIDOOM_H + +/* Main viDOOM entry point +*/ +int viDOOM(int argc, char *argv[]); + +#endif + +/* END OF FILE */ + diff --git a/vidoom.ini b/vidoom.ini new file mode 100644 index 0000000..a657523 --- /dev/null +++ b/vidoom.ini @@ -0,0 +1,186 @@ +# 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 +# +# +# Development copy of BASE.INI +# + +[Game] +game=zdoom +ask=no + +[Editor] +ask_middle_on_2sided=no +auto_block_linedefs=yes +bright=1.50 +clear_on_menu=no +clear_on_move=yes +default_ceiling_height=256 +default_edit_mode=thing +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 +left_click_move=yes +linedef_select=2 +merge_linedef=ask +new_2sided_select=ask +sector_move=all +show_full_linedef_info=yes +tag_highlight=yes +vertex_radius=8 +width=800 +height=600 + +[Check LINEDEF] +assume_yes=yes +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] +auto_loadmap=MAP01,E1M1 +initial_empty_map=no +load_flats=yes +load_sprites=yes +load_textures=yes +map_clear_warning=no +map_exit_warning=no +overwrite_warning=no +show_titlepic=yes +sort_flat_names=yes +sort_texture_names=yes + +[ACS] +always_view_output=yes +command=acc +dir=/tmp +script=vidoom.acs +object=vidoom.o +args=%S %O + +[Node Builder] +always_view_output=yes +command=warm +ignore=str +in_before_out=yes +infile=% +outfile=% +use=yes + +[GUI] +high=0xd2d2d2 +mid=0xb4b4b4 +low=0x8c8c8c +text=0xffffff +shadow=0x000000 +bold=0x000000 + + +[Doom] +iwad=c:\ianc\doom\doom.wad +pwad_dir=c:\ianc\doom\ +preload= +level_style=doom +vidoom_config=doom.cfg + +[Ultimate Doom] +iwad=c:\ianc\doom\doom.wad +pwad_dir=c:\ianc\doom\ +preload= +level_style=ultimate doom +vidoom_config=doom.cfg + +[Doom 2] +iwad=D:\doom\doom2.wad +pwad_dir=e:\doom\mywads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +[TNT:Evilution] +iwad=D:\doom\tnt.wad +pwad_dir=e:\doom\mywads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +[Plutonia Experiment] +iwad=D:\games\doom95\plutonia.wad +pwad_dir=c:\games\teamtntwads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +# Home (dos) +# +[ZDoom] +iwad=D:/DOOM/DOOM2.WAD +mapinfo_lump=no +create_hexen=yes +pwad_dir=D:/DOOM/MYWAD +preload= +level_style=doom 2 +vidoom_config=zdoom.cfg + +# Home (linux) +# +[ZDoom] +iwad=/usr/games/wad/doom2.wad +mapinfo_lump=no +create_hexen=yes +pwad_dir=/home/ianc/wad +preload= +level_style=doom 2 +vidoom_config=zdoom.cfg + +# Laptop (cygwin) +# +#[ZDoom] +#iwad=f:\games\doom\doom2.wad +#mapinfo_lump=yes +#create_hexen=yes +#pwad_dir=f:\games\doom\mywads\ +#preload= +#level_style=doom 2 +#vidoom_config=zdoom.cfg + +# Work +# +#[ZDoom] +#iwad=c:\ianc\doom\doom.wad +#mapinfo_lump=yes +#create_hexen=yes +#pwad_dir=c:\ianc\doom\ +#preload= +#level_style=ultimate doom +#vidoom_config=zdoom.cfg + + +# Platform dependent info +# +[linux] +edit= diff --git a/vstring.h b/vstring.h new file mode 100644 index 0000000..5b101d6 --- /dev/null +++ b/vstring.h @@ -0,0 +1,48 @@ +/* + + 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 VIDOOM_VSTRING_H + +#define VIDOOM_VSTRING_H + +/* Does exactly the same as strcmp(), but ignores case. + The passed in strings should not be altered. + + Returns 0 if either argument is NULL +*/ +int StrCaseCmp(char *a, char *b); + +/* Does exactly the same as strncmp(), but ignores case. + The passed in strings should not be altered. + + Returns 0 if either argument is NULL +*/ +int StrNCaseCmp(char *a, char *b, int n); + +#endif diff --git a/wad.c b/wad.c new file mode 100644 index 0000000..fbd89e2 --- /dev/null +++ b/wad.c @@ -0,0 +1,1144 @@ +/* + + 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" +#include "util.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 NO_MAP_LUMPS 7 + +#define NOT_MAP_LUMP -2 +#define IGNORE_LUMP -1 +#define THING_LUMP 0 +#define VERTEX_LUMP 1 +#define LINEDEF_LUMP 2 +#define SIDEDEF_LUMP 3 +#define SECTOR_LUMP 4 +#define BEHAVIOR_LUMP 5 +#define SCRIPTS_LUMP 6 + + +#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", + "Could not create MAPINFO.WAD", + "MAP mangled - spread over more than one 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 char *GetName(FILE *fp) +{ + static DirName d; + + FRead(fp,d,8); + d[sizeof(d)-1]=0; + return(d); +} + + +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 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}, + {"BEHAVIOR",BEHAVIOR_LUMP}, + {"SCRIPTS",SCRIPTS_LUMP}, + {"SEGS",IGNORE_LUMP}, + {"SSECTORS",IGNORE_LUMP}, + {"NODES",IGNORE_LUMP}, + {"REJECT",IGNORE_LUMP}, + {"BLOCKMAP",IGNORE_LUMP}, + {NULL,NOT_MAP_LUMP}, + }; + + int f; + + f=0; + while(lump[f].name) + { + if (STREQ(lump[f].name,n)) + return(lump[f].lump); + + f++; + } + + return(NOT_MAP_LUMP); +} + + +static void GetMapLumps(Iterator i, WadDir *l[]) +{ + WadDir *dir; + int lc; + int f; + + for(f=0;fname); + + switch(lc) + { + case IGNORE_LUMP: + break; + + case NOT_MAP_LUMP: + i=IteratorClear(i); + break; + + default: + l[lc]=dir; + break; + } + + if (i) + i=IteratorNext(i); + } +} + + +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(wf->fp,ret,d->size); + + 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(fp,type,4); + + if (STRNEQ("IWAD",expect)&&(!STRNEQ("IWAD",type))) + { + fclose(fp); + ERR(WAD_NOT_IWAD,NULL); + } + else if (STRNEQ("PWAD",expect)&&(!STRNEQ("PWAD",type))) + { + ERR(WAD_NOT_PWAD,NULL); + fclose(fp); + } + + 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)); + } + + fclose(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 + { + if (!(wf.fp=fopen(wad,"rb"))) + GFX_exit(EXIT_FAILURE,"BIZARRE: WAD opening failed after " + "first open succeeded on\n\t%s\n",wad); + + strcpy(wf.path,wad); + wadname=Strdup(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); +} + + +/* ---------------------------------------- MAPINFO FUNCTIONS +*/ +static char *LoadMAPINFO(void) +{ + char path[PATH_MAX+1]; + char *lump; + Long size; + + strcpy(path,PWAD_dir); + strcat(path,"mapinfo.wad"); + + if (AddPWAD(path)!=WAD_OK) + return(NULL); + + lump=GetLump("MAPINFO",&size); + CloseWad(path); + + if (lump) + { + lump=ReGrab(lump,size+1); + lump[size]=0; + } + + return(lump); +} + + +int SaveMAPINFO(char *info) +{ + char path[PATH_MAX+1]; + FILE *fp; + Long off; + + strcpy(path,PWAD_dir); + strcat(path,"mapinfo.wad"); + + if (!(fp=fopen(path,"wb"))) + return(FALSE); + + off=strlen(info)+12; + + /* Put PWAD header + */ + fputs("PWAD",fp); + PutLong(fp,1); + PutLong(fp,off); + + /* Put MAPINFO + */ + fputs(info,fp); + + /* Create directory + */ + PutDirEnt(fp,12,strlen(info),"MAPINFO"); + fclose(fp); + + return(TRUE); +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +int AddIWAD(char *wad) +{ + return (AddWAD(wad,"IWAD")); +} + + +int AddPWAD(char *wad) +{ + return (AddWAD(wad,"PWAD")); +} + + +int CloseWad(char *wad) +{ + WadDir *w; + WadFile *wf; + Iterator i; + char *p=NULL; + + if (!(i=ListFindElem(wadlist,FindWAD,wad))) + ERR(WAD_FILE_NOT_FOUND,WAD_FILE_NOT_FOUND); + + wf=IteratorData(i); + + if (wf->fp) + fclose(wf->fp); + + i=IteratorDelete(i); + IteratorClear(i); + + i=ListIterator(waddir); + + while(i) + { + w=IteratorData(i); + + if (FilenamesEqual(w->wad,wad)) + { + p=w->wad; + i=IteratorDelete(i); + } + else + i=IteratorNext(i); + } + + if (p) + Release(p); + + 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); +} + + +void *GetLumpFrom(WadDir *d, Long *size) +{ + void *ret; + + if (size) + *size=0; + + 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; + int lc; + WadDir *lump[NO_MAP_LUMPS]; + + 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); + + GetMapLumps(i,lump); + + /* Check for a mangled map + */ + for(f=0;fpath,lump[f]->wad))) + ERR(WAD_MAP_MANGLED,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)); + + map->scripts=NULL; + map->behavior=NULL; + map->mapinfo=NULL; + + if (lump[BEHAVIOR_LUMP]) + map->hexen=TRUE; + else + map->hexen=FALSE; + + for(lc=0;lcfp,(long)dir->off,SEEK_SET); + + if (map->hexen) + for(f=0;fsize/THING_SIZE_HEXEN;f++) + { + int a; + + thing.id=GetUShort(wf->fp); + thing.x=GetShort(wf->fp); + thing.y=GetShort(wf->fp); + thing.z=GetShort(wf->fp); + thing.ang=GetShort(wf->fp); + thing.type=GetShort(wf->fp); + thing.flags=GetShort(wf->fp); + thing.special=GetByte(wf->fp); + + for(a=0;a<5;a++) + thing.args[a]=GetByte(wf->fp); + + MapAdd(map->thing,f,&thing); + } + else + 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.flags=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); + + if (map->hexen) + for(f=0;fsize/LINEDEF_SIZE_HEXEN;f++) + { + int a; + + linedef.from=GetShort(wf->fp); + linedef.to=GetShort(wf->fp); + linedef.flags=GetShort(wf->fp); + linedef.type=GetByte(wf->fp); + + for(a=0;a<5;a++) + linedef.args[a]=GetByte(wf->fp); + + linedef.right=GetShort(wf->fp); + linedef.left=GetShort(wf->fp); + MapAdd(map->linedef,f,&linedef); + } + else + 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; + + /* No action yet for these - will simply be written back + */ + case BEHAVIOR_LUMP: + map->behavior_size=dir->size; + map->behavior=Grab(dir->size); + fseek(wf->fp,(long)dir->off,SEEK_SET); + FRead(wf->fp,map->behavior,dir->size); + break; + + case SCRIPTS_LUMP: + map->scripts_size=dir->size; + map->scripts=Grab(dir->size+1); + fseek(wf->fp,(long)dir->off,SEEK_SET); + FRead(wf->fp,map->scripts,dir->size); + map->scripts[map->scripts_size]=0; + break; + + default: + break; + } + } + + /* Locate the MAPINFO lump if config says so + */ + if (mapinfo_lump) + map->mapinfo=UnMSDOS(LoadMAPINFO()); + + ERR(WAD_OK,map); +} + + +WadMap *NewMap(int hexen) +{ + WadMap *map; + + map=Grab(sizeof(WadMap)); + + map->hexen=hexen; + + 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)); + + if (mapinfo_lump) + map->mapinfo=UnMSDOS(LoadMAPINFO()); + else + map->mapinfo=NULL; + + map->behavior_size=0; + map->behavior=NULL; + map->scripts_size=0; + map->scripts=NULL; + + return(map); +} + + +WadMap *ClearMap(WadMap *map) +{ + MapClear(map->thing); + MapClear(map->vertex); + MapClear(map->sidedef); + MapClear(map->linedef); + MapClear(map->sector); + + if (map->mapinfo) + Release(map->mapinfo); + + if (map->behavior) + Release(map->behavior); + + if (map->scripts) + Release(map->scripts); + + Release(map); + return(NULL); +} + + +int SaveMap(WadMap *map, char *name, char *wad) +{ + FILE *fp; + Long off; + int f; + Long no; + + if (!(fp=fopen(wad,"wb"))) + ERR(WAD_COULD_NOT_CREATE,WAD_COULD_NOT_CREATE); + + /* Calc number of entries in MAP + */ + if (map->hexen) + no=13; + else + no=11; + + /* Calc offset for directory + */ + off=12; + + off+=MapSize(map->vertex)*VERTEX_SIZE+ + MapSize(map->sidedef)*SIDEDEF_SIZE+ + MapSize(map->sector)*SECTOR_SIZE; + + if (map->hexen) + { + off+=MapSize(map->linedef)*LINEDEF_SIZE_HEXEN+ + MapSize(map->thing)*THING_SIZE_HEXEN; + + off+=map->behavior_size+map->scripts_size; + } + else + { + off+=MapSize(map->linedef)*LINEDEF_SIZE+ + MapSize(map->thing)*THING_SIZE; + } + + /* Save MAPINFO.WAD + */ + if ((map->mapinfo)&&(strlen(map->mapinfo))) + { + char *info; + + info=ApplyMSDOS(map->mapinfo,FALSE); + + if (!SaveMAPINFO(info)) + { + Release(info); + ERR(WAD_MAPINFO_FAILED,WAD_MAPINFO_FAILED); + } + + Release(info); + } + + /* Put PWAD header + */ + fputs("PWAD",fp); + PutLong(fp,no); + PutLong(fp,off); + + /* Put THINGS + */ + for(f=0;fthing);f++) + { + Thing *t; + + t=MapElem(map->thing,f); + + if (map->hexen) + { + int i; + + PutUShort(fp,t->id); + PutShort(fp,t->x); + PutShort(fp,t->y); + PutShort(fp,t->z); + PutShort(fp,t->ang); + PutShort(fp,t->type); + PutShort(fp,t->flags); + PutByte(fp,t->special); + + for(i=0;i<5;i++) + PutByte(fp,t->args[i]); + } + else + { + PutShort(fp,t->x); + PutShort(fp,t->y); + PutShort(fp,t->ang); + PutShort(fp,t->type); + PutShort(fp,t->flags); + } + } + + /* Put LINEDEFS + */ + for(f=0;flinedef);f++) + { + Linedef *l; + + l=MapElem(map->linedef,f); + + if (map->hexen) + { + int i; + + PutShort(fp,l->from); + PutShort(fp,l->to); + PutShort(fp,l->flags); + PutByte(fp,(Byte)l->type); + + for(i=0;i<5;i++) + PutByte(fp,l->args[i]); + + PutShort(fp,l->right); + PutShort(fp,l->left); + } + else + { + 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 + */ + + /* Put BEHAVIOR and SCRIPTS + */ + if (map->hexen) + { + int f; + + if (map->behavior) + for(f=0;fbehavior_size;f++) + PutByte(fp,map->behavior[f]); + + if (map->scripts) + for(f=0;fscripts_size;f++) + PutByte(fp,map->scripts[f]); + } + + /* Create directory + */ + off=12; + PutDirEnt(fp,off,0,name); + + if (map->hexen) + { + PutDirEnt(fp,off,MapSize(map->thing)*THING_SIZE_HEXEN,"THINGS"); + off+=MapSize(map->thing)*THING_SIZE_HEXEN; + } + else + { + PutDirEnt(fp,off,MapSize(map->thing)*THING_SIZE,"THINGS"); + off+=MapSize(map->thing)*THING_SIZE; + } + + if (map->hexen) + { + PutDirEnt(fp,off,MapSize(map->linedef)*LINEDEF_SIZE_HEXEN,"LINEDEFS"); + off+=MapSize(map->linedef)*LINEDEF_SIZE_HEXEN; + } + else + { + 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"); + + if (map->hexen) + { + PutDirEnt(fp,off,map->behavior_size,"BEHAVIOR"); + off+=map->behavior_size; + + PutDirEnt(fp,off,map->scripts_size,"SCRIPTS"); + off+=map->scripts_size; + } + + fclose(fp); + + ERR(WAD_OK,WAD_OK); +} + + +int WadError(void) +{ + return(wad_err); +} + + +const char *WadErrorString(void) +{ + return(wad_errstr[wad_err]); +} + + +int WadFileType(char *wad) +{ + FILE *fp; + char type[4]; + + if (!(fp=fopen(wad,"rb"))) + return(FILE_IS_NOT_WAD); + + FRead(fp,type,4); + fclose(fp); + + if (STRNEQ("PWAD",type)) + return(FILE_IS_PWAD); + + if (STRNEQ("IWAD",type)) + return(FILE_IS_IWAD); + + return(FILE_IS_NOT_WAD); +} + +/* END OF FILE */ diff --git a/wad.h b/wad.h new file mode 100644 index 0000000..8174052 --- /dev/null +++ b/wad.h @@ -0,0 +1,294 @@ +/* + + 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 VIDOOM_WAD_H + +#define VIDOOM_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) +#define THING_SIZE_HEXEN (sizeof(Short)*6+sizeof(UShort)+6) + +/* Note that the fields are NOT in the order they appear in the WAD +*/ +typedef struct Thing + { + Short x; + Short y; + Short ang; + Short type; + Short flags; + + /* Extra fields for HEXEN things + */ + UShort id; + Byte special; + Short z; + Short args[5]; + } 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) +#define LINEDEF_SIZE_HEXEN (sizeof(Short)*5+6) + +/* Note that the fields are NOT in the order they appear in the WAD +*/ +typedef struct + { + Short from; + Short to; + Short flags; + Short type; /* In HEXEN mode this is a Byte */ + Short tag; + Short right; + Short left; + + /* Extra fields for HEXEN linedefs + */ + Byte args[5]; + } 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 + { + int hexen; /* TRUE if map in HEXEN/extended format */ + + Map thing; + Map vertex; + Map linedef; + Map sidedef; + Map sector; + + /* ZDOOM/HEXEN lumps and info + */ + int behavior_size; + char *behavior; + int scripts_size; + char *scripts; + char *mapinfo; + } 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_MAPINFO_FAILED 8 +#define WAD_MAP_MANGLED 9 +#define WAD_BROKEN 10 /* Must be last error code */ + +#define WAD_NOERROR (WAD_BROKEN+1) + + +/* Returns for WAD file type +*/ +#define FILE_IS_NOT_WAD 0 +#define FILE_IS_IWAD 1 +#define FILE_IS_PWAD 2 + + +/* 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); + + +/* Retrieves the lump pointed to by the WAD directory entry. + 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 WAD dir entry was invalid. +*/ +void *GetLumpFrom(WadDir *ent, 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. Creates a HEXEN map if hexen is TRUE. +*/ +WadMap *NewMap(int hexen); + + +/* 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); + + +/* Given a filename returns the type of WAD file it is. + Returns FILE_IS_NOT_WAD if file is not a WAD file, or doesn't exist. +*/ +int WadFileType(char *wad); + + +#endif + +/* END OF FILE */ diff --git a/waddir.c b/waddir.c new file mode 100644 index 0000000..1487f21 --- /dev/null +++ b/waddir.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 + + ------------------------------------------------------------------------- + + 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]); + + LoadGlobalsPart1(); + LoadGlobalsPart2(); + + 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%.8lx 0x%.8lx %s\n", + w->name,w->off,w->size,Basename(w->wad)); + + i=IteratorNext(i); + } + + return(0); +} + + +/* END OF FILE */ diff --git a/wadtest b/wadtest new file mode 100755 index 0000000..6c8742f Binary files /dev/null and b/wadtest differ diff --git a/wadtest.c b/wadtest.c new file mode 100644 index 0000000..1d1b586 --- /dev/null +++ b/wadtest.c @@ -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 + + ------------------------------------------------------------------------- + + Tester for routines in wad.c + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "wad.h" +#include "gfx.h" +#include "mem.h" + +#include + + +/* ---------------------------------------- MAIN +*/ +int viDOOM(int argc,char *argv[]) +{ + int c; + + if (argc<3) + GFX_exit(1,"usage:%s IWAD PWAD\n",argv[0]); + + LoadGlobalsPart1(); + LoadGlobalsPart2(); + + if (AddIWAD(argv[1])!=WAD_OK) + GFX_exit(1,"wadderr=%s\n",WadErrorString()); + + c=0; + + while(1) + { + void *lump; + + if (AddPWAD(argv[2])!=WAD_OK) + GFX_exit(1,"AddPWAD()=%s (cycles=%d)\n",WadErrorString(),c); + + if (CloseWad(argv[2])!=WAD_OK) + GFX_exit(1,"CloseWad()=%s (cycles=%d)\n",WadErrorString(),c); + + if (!(lump=GetLump("TITLEPIC",NULL))) + GFX_exit(1,"GetLump()=%s (cycles=%d)\n",WadErrorString(),c); + + Release(lump); + + c++; + + if ((c%1000)==0) + printf("%d cycles done\n",c); + } + + return(0); +} + + +/* END OF FILE */ diff --git a/zdoom.cfg b/zdoom.cfg new file mode 100644 index 0000000..8aeb27a --- /dev/null +++ b/zdoom.cfg @@ -0,0 +1,719 @@ +# 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: zdoom.cfg,v 1.8 2000/11/13 16:16:38 dosuser Exp dosuser $ +# +# ZDoom config file. See the heading of doom.cfg for details +# + +%INCLUDE_FILES +@DOOM_2_LEVEL_STYLE +doom2.cfg +@END DOOM_2_LEVEL_STYLE + +@DOOM_LEVEL_STYLE +doom.cfg +@END DOOM_LEVEL_STYLE + +# THING_CLASSES section +# +%THING_CLASSES +Sound|0x808080 +Stealth Monster|0xd01010 +Special ZDOOM/BOOM|0xff0000 + +# THING_TYPES section +# +%THING_TYPES +Stealth Monster|Stealth Former Human|9061|20|POSSA1 +Stealth Monster|Stealth Former Sergeant|9060|20|SPOSA1 +Stealth Monster|Stealth Imp|9057|20|TROOA1 +Stealth Monster|Stealth Demon|3002|30|SARGA1 +Stealth Monster|Stealth Cacodemon|9053|31|HEADA1 +Stealth Monster|Stealth Baron of Hell|9052|24|BOSSA1 +@DOOM_2_LEVEL_STYLE +Stealth Monster|Stealth Chaingunner|9060|20|CPOSA1 +Stealth Monster|Stealth Hell Knight|9056|24|BOS2A1C1 +Stealth Monster|Stealth Arachnotron|9050|64|BSPIA1D1 +Stealth Monster|Stealth Revenant|9059|20|SKELA1D1 +Stealth Monster|Stealth Mancubus|9058|48|FATTA1 +Stealth Monster|Stealth Arch Vile|9051|20|VILEA1D1 +@END DOOM_2_LEVEL_STYLE + +Scenery|Spark|9206|16|- +Scenery|Red fountain|9027|16|- +Scenery|Green fountain|9028|16|- +Scenery|Blue fountain|9029|16|- +Scenery|Yellow fountain|9030|16|- +Scenery|Purple fountain|9031|16|- +Scenery|Black fountain|9032|16|- +Scenery|White fountain|9033|16|- + +Player Start|Player 4 start|4001|16|PLAYA1 +Player Start|Player 5 start|4002|16|PLAYA1 +Player Start|Player 6 start|4003|16|PLAYA1 +Player Start|Player 7 start|4004|16|PLAYA1 + +Sound|Sector plays seq 0|1400|16|- +Sound|Sector plays seq 1|1401|16|- +Sound|Sector plays seq 2|1402|16|- +Sound|Sector plays seq 3|1403|16|- +Sound|Sector plays seq 4|1404|16|- +Sound|Sector plays seq 5|1405|16|- +Sound|Sector plays seq 6|1406|16|- +Sound|Sector plays seq 7|1407|16|- +Sound|Sector plays seq 8|1408|16|- +Sound|Sector plays seq 9|1409|16|- +Sound|Sector plays param|1411|16|- +Sound|Ambient sound 1|14001|16|- +Sound|Ambient sound 2|14002|16|- +Sound|Ambient sound 3|14003|16|- +Sound|Ambient sound 4|14004|16|- +Sound|Ambient sound 5|14005|16|- +Sound|Ambient sound 6|14006|16|- +Sound|Ambient sound 7|14007|16|- +Sound|Ambient sound 8|14008|16|- +Sound|Ambient sound 9|14009|16|- +Sound|Ambient sound 10|14010|16|- +Sound|Ambient sound 11|14011|16|- +Sound|Ambient sound 12|14012|16|- +Sound|Ambient sound 13|14013|16|- +Sound|Ambient sound 14|14014|16|- +Sound|Ambient sound 15|14015|16|- +Sound|Ambient sound 16|14016|16|- +Sound|Ambient sound 17|14017|16|- +Sound|Ambient sound 18|14018|16|- +Sound|Ambient sound 19|14019|16|- +Sound|Ambient sound 20|14020|16|- +Sound|Ambient sound 21|14021|16|- +Sound|Ambient sound 22|14022|16|- +Sound|Ambient sound 23|14023|16|- +Sound|Ambient sound 24|14024|16|- +Sound|Ambient sound 25|14025|16|- +Sound|Ambient sound 26|14026|16|- +Sound|Ambient sound 27|14027|16|- +Sound|Ambient sound 28|14028|16|- +Sound|Ambient sound 29|14029|16|- +Sound|Ambient sound 30|14030|16|- +Sound|Ambient sound 31|14031|16|- +Sound|Ambient sound 32|14032|16|- +Sound|Ambient sound 33|14033|16|- +Sound|Ambient sound 34|14034|16|- +Sound|Ambient sound 35|14035|16|- +Sound|Ambient sound 36|14036|16|- +Sound|Ambient sound 37|14037|16|- +Sound|Ambient sound 38|14038|16|- +Sound|Ambient sound 39|14039|16|- +Sound|Ambient sound 40|14040|16|- +Sound|Ambient sound 41|14041|16|- +Sound|Ambient sound 42|14042|16|- +Sound|Ambient sound 43|14043|16|- +Sound|Ambient sound 44|14044|16|- +Sound|Ambient sound 45|14045|16|- +Sound|Ambient sound 46|14046|16|- +Sound|Ambient sound 47|14047|16|- +Sound|Ambient sound 48|14048|16|- +Sound|Ambient sound 49|14049|16|- +Sound|Ambient sound 50|14050|16|- +Sound|Ambient sound 51|14051|16|- +Sound|Ambient sound 52|14052|16|- +Sound|Ambient sound 53|14053|16|- +Sound|Ambient sound 54|14054|16|- +Sound|Ambient sound 55|14055|16|- +Sound|Ambient sound 56|14056|16|- +Sound|Ambient sound 57|14057|16|- +Sound|Ambient sound 58|14058|16|- +Sound|Ambient sound 59|14059|16|- +Sound|Ambient sound 60|14060|16|- +Sound|Ambient sound 61|14061|16|- +Sound|Ambient sound 62|14062|16|- +Sound|Ambient sound 63|14063|16|- +Sound|Ambient sound 64|14064|16|- +Sound|Ambient sound 0-255 (Hexen)|14065|16|- + +Teleport|Teleport landing (remembers height)|9044|16|TFOGA0 + +Special ZDOOM/BOOM|BOOM Point pusher|5001|16|- +Special ZDOOM/BOOM|BOOM Point puller|5002|16|- +Special ZDOOM/BOOM|Map spot|9001|16|- +Special ZDOOM/BOOM|Map spot (with gravity)|9002|16|- +Special ZDOOM/BOOM|Path node|9024|16|- +Special ZDOOM/BOOM|Camera|9025|16|- +Special ZDOOM/BOOM|Water filled sector|9045|16|- +Special ZDOOM/BOOM|Secret|9046|16|- +Special ZDOOM/BOOM|Polyobject anchor|9300|16|- +Special ZDOOM/BOOM|Polyobject spawn spot|9301|16|- +Special ZDOOM/BOOM|Crushing polyobject spawn spot|9302|16|- + + +# LINEDEF_CLASSES +# +%LINEDEF_CLASSES +BOOM/ZDoom + +# LINEDEF_TYPES +# +%LINEDEF_TYPES +BOOM/ZDoom|333|Tagged sector gravity +BOOM/ZDoom|334|Tagged sector fog/light colour +BOOM/ZDoom|335|Tagged Sector damage + + +# SECTOR_CLASSES +# +%SECTOR_CLASSES +Doom|Hexen Lighting +Hexen|Normal +Hexen|Lights +Hexen|Stairs +Hexen|Damage +Hexen|Door +Hexen|Scroll Slow +Hexen|Scroll Medium +Hexen|Scroll Fast + +# SECTOR_TYPES +# +%SECTOR_TYPES +Doom|Hexen Lighting|21|Light Phased|Phase +Doom|Hexen Lighting|22|Light Seq Start|LSeq Start +Doom|Hexen Lighting|23|Light Seq Special 1|LSeq Spec1 +Doom|Hexen Lighting|24|Light Seq Special 2|LSeq Spec2 + +Hexen|Normal|0|Normal|Normal + +Hexen|Lights|1|Light Phased|Phase +Hexen|Lights|2|Light Seq Start|LSeq Start +Hexen|Lights|3|Light Seq Special 1|LSeq Spec1 +Hexen|Lights|4|Light Seq Special 2|LSeq Spec2 + +Hexen|Stairs|26|Stairs Special 1|StairSpec1 +Hexen|Stairs|27|Stairs Special 2|StairSpecb + +Hexen|Scroll Slow|201|Scroll North Slow|ScrollNorthSlow +Hexen|Scroll Medium|202|Scroll North Medium|ScrollNorthMedium +Hexen|Scroll Fast|203|Scroll North Fast|ScrollNorthFast +Hexen|Scroll Slow|204|Scroll East Slow|ScrollEastSlow +Hexen|Scroll Medium|205|Scroll East Medium|ScrollEastMedium +Hexen|Scroll Fast|206|Scroll East Fast|ScrollEastFast +Hexen|Scroll Slow|207|Scroll South Slow|ScrollSouthSlow +Hexen|Scroll Medium|208|Scroll South Medium|ScrollSouthMedium +Hexen|Scroll Fast|209|Scroll South Fast|ScrollSouthFast +Hexen|Scroll Slow|210|Scroll West Slow|ScrollWestSlow +Hexen|Scroll Medium|211|Scroll West Medium|ScrollWestMedium +Hexen|Scroll Fast|212|Scroll West Fast|ScrollWestFast +Hexen|Scroll Slow|213|Scroll NorthWest Slow|ScrollNorthWestSlow +Hexen|Scroll Medium|214|Scroll NorthWest Medium|ScrollNorthWestMedium +Hexen|Scroll Fast|215|Scroll NorthWest Fast|ScrollNorthWestFast +Hexen|Scroll Slow|216|Scroll NorthEast Slow|ScrollNorthEastSlow +Hexen|Scroll Medium|217|Scroll NorthEast Medium|ScrollNorthEastMedium +Hexen|Scroll Fast|218|Scroll NorthEast Fast|ScrollNorthEastFast +Hexen|Scroll Slow|219|Scroll SouthEast Slow|ScrollSouthEastSlow +Hexen|Scroll Medium|220|Scroll SouthEast Medium|ScrollSouthEastMedium +Hexen|Scroll Fast|221|Scroll SouthEast Fast|ScrollSouthEastFast +Hexen|Scroll Slow|222|Scroll SouthWest Slow|ScrollSouthWestSlow +Hexen|Scroll Medium|223|Scroll SouthWest Medium|ScrollSouthWestMedium +Hexen|Scroll Fast|224|Scroll SouthWest Fast|ScrollSouthWestFast + +# Doom sector types in their hexen numbers +# +Hexen|Lights|65|Light random off (Doom)|dLight_Flicker +Hexen|Lights|66|Blink lights 0.5 second (Doom)|dLight_StrobeFast +Hexen|Lights|67|Blink lights 1.0 second (Doom)|dLight_StrobeSlow +Hexen|Lights|68|Lose -10/20% health & blink lights 0.5 sec (Doom)|dLightStrobeHurt +Hexen|Damage|69|Lose -5/10% health (Doom)|dDamage_Hellslime +Hexen|Damage|71|Lose -2/5% health (Doom)|dDamage_Nukage +Hexen|Lights|72|Oscillating light (Doom)|dLightGlow +Hexen|Door|74|Door closes after 30 seconds (Doom)|dSector_DoorClose +Hexen|Damage|75|-10/20% health - end level if < 11% (Doom)|dDamageEnd +Hexen|Lights|76|Blink lights synchronised 0.5 second (Doom)|dLight_StrobeSlowSync +Hexen|Lights|77|Blink lights synchronised 1.0 second (Doom)|dLight_StrobeFastSync +Hexen|Door|78|Door opens after 300 seconds (Doom)|dSector_DoorRaiseIn5Min +Hexen|Damage|80|Lose -10/20% health (Doom)|dDamage_SuperHellslime +Hexen|Lights|81|Light random on/off (Doom)|dLight_FireFlicker + + +# THING_FLAGS section +# +%THING_FLAGS +Hexen|0|0x001|0x001|Skill 1 and 2|E +Hexen|0|0x002|0x002|Skill 3|M +Hexen|0|0x004|0x004|Skill 4 and 5|H +Hexen|0|0x008|0x008|Deaf|D +Hexen|0|0x010|0x010|Dormant|A +Hexen|0|0x100|0x100|Appears in 1 player|S +Hexen|0|0x200|0x200|Appears in Co-op|C +Hexen|0|0x400|0x400|Appears in Deathmatch|X + + +# LINEDEF_FLAGS section +# +%LINEDEF_FLAGS +Hexen|0|0x0001|0x0001|Impassible|I +Hexen|0|0x0002|0x0002|Block monsters|M +Hexen|0|0x0004|0x0004|Two-sided|2 +Hexen|0|0x0008|0x0008|Upper unpegged|U +Hexen|0|0x0010|0x0010|Lower unpegged|L +Hexen|0|0x0020|0x0020|Secret|S +Hexen|0|0x0040|0x0040|Blocks sound|B +Hexen|0|0x0080|0x0080|Not on map|N +Hexen|0|0x0100|0x0100|Already on map|A +Hexen|0|0x0200|0x0200|Repeatable|R +Hexen|1|0x1c00|0x0000|Activated by player crossing|C +Hexen|1|0x1c00|0x0400|Activated by player using|u +Hexen|1|0x1c00|0x0800|Activated by monster crossing|c +Hexen|1|0x1c00|0x0c00|Activated by projectile hitting|P +Hexen|1|0x1c00|0x1000|Activated by player bumping|B +Hexen|1|0x1c00|0x1400|Activated by projectile crossing|p +Hexen|1|0x1c00|0x1800|Activated by player crossing (passthru)|T +Hexen|0|0x2000|0x2000|Can be activated by monsters|a +Hexen|0|0x8000|0x8000|Blocks everything|! + + +# SECTOR_STYLES and LINEDEF_DEFAULT we will automatically inherit from the +# DOOM config or the DOOM 2 config +# + + +# LINEDEF_GEN_BITMASKS section. This defines the bitmasks that are used to +# build up generalised linedef types. +# +# This section is a bit more complex than most of the others as the format of +# the data is not fixed from line to line. +# +# Each set starts with the class name for the bitmask. Format for this line is: +# +# "class name|no of fields" +# +# After this follows repititions of the following: +# +# "field name|shorthand name|value" +# +# Remember that value will be shifted left a specified amount when used in the +# LINEDEF_GEN_TYPES section and so they should be defined relative to bit 0. +# +# Also note that inside the editor all the values associated with a bitmask +# are ORed together to create a mask that can extract that information from a +# generalised linedef to be displayed in the editor. +# +# Following all this can follow another class, and so on. Also remember that +# blank lines and comments are OK, so that sections can be readably split using +# white space. +# +%LINEDEF_GEN_BITMASKS +Trigger|8 +Walk over (once)|W1|0 +Walk over (multi)|WR|1 +Push (once)|P1|2 +Push (multi)|PR|3 +Switch (once)|S1|4 +Switch (multi)|SR|5 +Shoot (once)|G1|6 +Shoot (multi)|GR|7 + +Opens with|8 +Any|NK|0 +Red keycard|RC|1 +Blue keycard|BC|2 +Yellow keycard|YC|3 +Red skull|RS|4 +Blue skull|BS|5 +Yellow skull|YS|6 +All keys|AK|7 + +Speed|4 +Slow|Slow|0 +Normal|Norm|1 +Fast|Fast|2 +Turbo|Turb|3 + +Delay|4 +1s|1s|0 +4s|4s|1 +9s|9s|2 +30s|30s|3 + +Kind|4 +Open, Wait, Then Close|OWC|0 +Open and Stay Open|OSO|1 +Close and Stay Closed|CSC|2 +Close, Wait, Then Open|CWO|3 + +Locked door kind|2 +Open, close|OC|0 +Open|O|1 + +Number of Keys|2 +All 6 used|6|0 +3 used (skulls/cards same)|3|1 + +Floor Target|8 +Lowest Neighbor Floor|LnF|0 +Next Neighbor Floor|NnF|1 +Lowest Neighbor Ceiling|LnC|2 +Highest Neighbor Floor|HnF|3 +Ceiling|C|4 +24 Units|24u|5 +32 Units|32u|6 +Shortest Lower Texture|SLT|7 + +Monsters Can Use|2 +No|MoY|0 +Yes|MoN|1 + +Direction|2 +Down|Dn|0 +Up|Up|1 + +Crush|2 +No|CrN|0 +Yes|CrY|1 + +Floor Model|2 +Trigger|Trg|0 +Numeric|Num|1 + +Floor Change|4 +None|N|0 +Texture only|Tx|1 +Type zeroed|Tx0|2 +Texture and type changed|TxTy|3 + + +# LINEDEF_GEN_TYPES section. This defines the combinations of +# LINEDEF_GEN_BITMASKS that go to make up a generalised linedef type. +# +# This section is a bit more complex than most of the others as the format of +# the data is not fixed from line to line. +# +# Each set starts with the class name describing the type of generalised +# linedef, the edit mode this is for, the number of different bit patterns +# defined in the class and the low and high values that the type occupies. +# The edit mode is described in doom.cfg. Format for this line is: +# +# "edit mode|class name|low value|high value|mask|no of bit-field classes" +# +# After this follows repititions of the following: +# +# "bit-field name|shift" +# +# Note that different sets of bitmasks can have overlapping low/high values. +# When deciding which one to show in the editor display the first one defined +# will be used. +# +# The shift defines how much the bitmask is shifted to the left to generate +# the actual values stored in the linedef type field. +# +# If the mask is not -1 then in the editor it is ORed with the selected bit +# mask values to generate the linedef type value. +# +# If the mask is -1 then the original value of the linedef has the bits that +# would be occupied by the bitmasks cleared. The select bit mask values are +# then ORed with the ORIGINAL linedef value. +# +# Following all this can follow another class, and so on. Also remember that +# blank lines and comments are OK, so that sections can be readably split using +# white space. +# +# NB: HEXEN mode does not support generic linedef types anyhow... So, err, +# don't ask why the edit mode was added. Just seemed easy at the time as +# I was edit modeing generic sectors. +# +%LINEDEF_GEN_TYPES +Doom|Locked Door|0x3800|0x3bff|0x3800|5 +Trigger|0 +Speed|3 +Locked door kind|5 +Opens with|6 +Number of keys|9 + +Doom|Floor|0x6000|0x7fff|0x6000|7 +Trigger|0 +Speed|3 +Floor Model|5 +Direction|6 +Floor Target|7 +Floor Change|10 +Crush|12 + + +# SECTOR_GEN_BITMASKS section. This defines the bitmasks that are used to +# build up generalised sector types. This section works identically to the +# LINEDEF_GEN_BITMASKS section. +# +# +%SECTOR_GEN_BITMASKS +Lighting|9 +Normal|NL|0 +Random off|RO|1 +Blink 0.5 seconds|0.5|2 +Blink 1.0 seconds|1.0|3 +-10/20% health and blink 0.5 seconds|DmgL|4 +Oscillates|Osc|8 +Blink 0.5 seconds, synchronised|0.5s|12 +Blink 1.0 seconds, synchronised|1.0s|13 +Flickers on/off randomly|Rand|17 + +Damage|4 +None|D0|0 +5 units|D5|1 +10 units|D10|2 +20 units|D20|3 + +Secret|2 +No|NSec|0 +Yes|Sec|1 + +Friction|2 +Disabled|NFri|0 +Enabled|Fri|1 + +Wind|2 +Disabled|NWin|0 +Enabled|Win|1 + + +# SECTOR_GEN_TYPES section. This defines the combinations of +# SECTOR_GEN_BITMASKS that go to make up a generalised sector type. See +# LINEDEF_GEN_BITMASKS for details. +# +# +%SECTOR_GEN_TYPES +Doom|Generalised sector|0x20|0xffff|0|5 +Lighting|0 +Damage|5 +Secret|7 +Friction|8 +Wind|9 + +Hexen|Generalised Sector|0x100|0xffff|-1|4 +Damage|8 +Secret|10 +Friction|11 +Wind|12 + + +# HEXEN configuration +# +# ZDoom supports DOOM maps using the extended WAD format introduced by Raven +# for Hexen. As with ZDoom, viDOOM recognises HEXEN format maps by their +# inclusion of a BEHAVIOR lump. +# +# In the editor, these following definitions will be used only when a HEXEN +# format map is being edited, and can be left unset otherwise. +# + +# HEXEN_ACTION_SPECIAL_CLASSES +# +# Action special classes in HEXEN. Format is: +# "class name" +# +%HEXEN_ACTION_SPECIAL_CLASSES +Normal +Polyobject +Door +Floor +Ceiling +Floor and ceiling +Stairs +Platform +Teleport/exit +Lighting +Sector property +Things +ACS +Misc + + +# HEXEN_ACTION_SPECIALS +# +# The action specials themselves. Format is: +# "class name|id|name|[arg0[,arg1[,arg2[,arg3[,arg4]]]]]" +# +%HEXEN_ACTION_SPECIALS +Normal|0|No action| + +Polyobject|1|Polyobj_StartLine|po,mirror,sound +Polyobject|2|Polyobj_RotateLeft|po,speed,angle +Polyobject|3|Polyobj_RotateRight|po,speed,angle +Polyobject|4|Polyobj_Move|po|speed,angle,dist +Polyobject|5|Polyobj_ExplicitLine|po,order,mirror,sound +Polyobject|6|Polyobj_MoveTimes8|po,speed,angle,dist +Polyobject|7|Polyobj_DoorSwing|po,speed,angle,delay +Polyobject|8|Polyobj_DoorSlide|po,speed,angle,dist,delay +Polyobject|90|Polyobj_OR_RotateLeft|po,speed +Polyobject|91|Polyobj_OR_RotateRight|po,speed,angle +Polyobject|92|Polyobj_OR_Move|po|speed,angle,distance +Polyobject|93|Polyobj_OR_MoveTimes8|po,speed,angle,distance + +Door|10|Door_Close|tag,speed +Door|11|Door_Open|tag,speed +Door|12|Door_Raise|tag,speed,delay +Door|13|Door_LockedRaise|tag,speed,delay,lock +Door|249|Door_CloseWaitOpen|tag,speed,delay +Door|202|Generic_Door|tag,speed,kind,delay,lock + +Floor|20|Floor_LowerByValue|tag,speed,height +Floor|36|Floor_LowerByValueTimes8|tag,speed,height +Floor|66|Floor_LowerInstant|tag,arg1,height +Floor|21|Floor_LowerToLowest|tag,speed +Floor|241|Floor_LowerToLowestTxTy|tag,speed +Floor|242|Floor_LowerToHighest|tag,speed,adjust +Floor|22|Floor_LowerToNearest|tag,speed +Floor|23|Floor_RaiseByValue|tag,speed,height +Floor|35|Floor_RaiseByValueTimes8|tag,speed,height +Floor|67|Floor_RaiseInstant|tag,arg1,height +Floor|24|Floor_RaiseToHighest|tag,speed +Floor|25|Floor_RaiseToNearest|tag,speed +Floor|238|Floor_RaiseToLowestCeiling|tag,speed +Floor|239|Floor_RaiseByValueTxTy|tag,speed,height +Floor|240|Floor_RaiseByTexture|tag,speed +Floor|28|Floor_RaiseAndCrush|tag,speed,crush +Floor|46|Floor_CrushStop|tag +Floor|68|Floor_MoveToValueTimes8|tag,speed,height,neg +Floor|138|Floor_Waggle|tag,amp,freq,offset,time +Floor|250|Floor_Donut|ptag,pspeed,sspeed +Floor|235|Floor_TransferTrigger|tag +Floor|236|Floor_TransferNumeric|tag +Floor|200|Generic_Floor|tag,speed,height,target,flags + +Ceiling|40|Ceiling_LowerByValue|tag,speed,height +Ceiling|41|Ceiling_RaiseByValue|tag,speed,height +Ceiling|199|Ceiling_LowerByValueTimes8|tag,speed,height +Ceiling|198|Ceiling_RaiseByValueTimes8|tag,speed,height +Ceiling|193|Ceiling_LowerInstant|tag,arg1,height +Ceiling|194|Ceiling_RaiseInstant|tag,arg1,height +Ceiling|252|Ceiling_RaiseToNearest|tag,speed +Ceiling|192|Ceiling_LowerToHighestFloor|tag,speed +Ceiling|253|Ceiling_LowerToLowest|tag,speed +Ceiling|254|Ceiling_LowerToFloor|tag,speed +Ceiling|69|Ceiling_MoveToValueTimes8|tag,speed,height,neg +Ceiling|42|Ceiling_CrushAndRaise|tag,speed,crush +Ceiling|45|Ceiling_CrushRaiseAndStay|tag,speed,crush +Ceiling|43|Ceiling_LowerAndCrush|tag,speed,crush +Ceiling|195|Ceiling_CrushRaiseAndStayA|tag,dspeed,uspeed,crush +Ceiling|196|Ceiling_CrushAndRaiseA|tag,dspeed,uspeed,crush +Ceiling|197|Ceiling_CrushAndRaiseSilentA|tag,dspeed,uspeed,crush +Ceiling|255|Ceiling_CrushRaiseAndStaySilA|tag,dspeed,uspeed,crush +Ceiling|44|Ceiling_CrushStop|tag +Ceiling|201|Generic_Ceiling|tag,speed,height,target,flag +Ceiling|205|Generic_Crusher|tag,dspeed,uspeed,silent,crush + +Floor and ceiling|95|FloorAndCeiling_LowerByValue|tag,speed,height +Floor and ceiling|96|FloorAndCeiling_RaiseByValue|tag,speed,height +Floor and ceiling|251|FloorAndCeiling_LowerRaise|tag,fspeed,cspeed +Floor and ceiling|245|Elevator_RaiseToNearest|tag,speed +Floor and ceiling|246|Elevator_MoveToFloor|tag,speed +Floor and ceiling|247|Elevator_LowerToNearest|tag,speed +Floor and ceiling|29|Pillar_Build|tag,speed,height +Floor and ceiling|94|Pillar_BuildAndCrush|tag,speed,height,crush +Floor and ceiling|30|Pillar_Open|tag,speed,fdist,cdist + +Stairs|26|Stairs_BuildDown|tag,speed,height,delay,reset +Stairs|27|Stairs_BuildUp|tag,speed,height,delay,reset +Stairs|31|Stairs_BuildDownSync|tag,speed,height,reset +Stairs|32|Stairs_BuildUpSync|tag,speed,height,reset +Stairs|217|Stairs_BuildUpDoom|tag,speed,height,delay,reset +Stairs|204|Generic_Stairs|tag,speed,height,flags,reset + +Platform|60|Plat_PerpetualRaise|tag,speed,delay +Platform|207|Plat_PerpetualRaiseLip|tag,speed,delay,lip +Platform|61|Plat_Stop|tag +Platform|62|Plat_DownWaitUpStay|tag,speed,delay +Platform|206|Plat_DownWaitUpStayLip|tag,speed,delay,lip +Platform|63|Plat_DownByValue|tag,speed,delay,height +Platform|65|Plat_UpByValue|tag,speed,delay,height +Platform|64|Plat_UpWaitDownStay|tag,speed,delay +Platform|228|Plat_RaiseAndStayTx0|tag,speed +Platform|230|Plat_UpByValueStayTx|tag,speed,height +Platform|231|Plat_ToggleCeiling|tag +Platform|203|Generic_Lift|tag,speed,delay,type,height + +Teleport/exit|70|Teleport|tid +Teleport/exit|71|Teleport_NoFog|tid +Teleport/exit|215|Teleport_Line|thisid,destid,flip +Teleport/exit|74|Teleport_NewMap|map,pos +Teleport/exit|75|Teleport_EndGame +Teleport/exit|243|Exit_Normal|pos +Teleport/exit|244|Exit_Secret|pos + +Lighting|110|Light_RaiseByValue|tag,value +Lighting|111|Light_LowerByValue|tag,value +Lighting|112|Light_ChangeToValue|tag,value +Lighting|113|Light_Fade|tag,value,tics +Lighting|114|Light_Glow|tag,upper,lower,tics +Lighting|115|Light_Flicker|tag,upper,lower +Lighting|116|Light_Strobe|tag,upper,lower,u-tics,l-tics +Lighting|232|Light_StrobeDoom|tag,u-tics,l-tics +Lighting|233|Light_MinNeighbor|tag +Lighting|234|Light_MaxNeighbor|tag + +Sector property|212|Sector_SetColor|tag,r,g,b +Sector property|213|Sector_SetFade|tag,r,g,b +Sector property|214|Sector_SetDamage|tag,amount,mod +Sector property|216|Sector_SetGravity|tag,ipart,fpart +Sector property|219|Sector_SetFriction|tag,amount +Sector property|218|Sector_SetWind|tag,amount,angle,useline +Sector property|220|Sector_SetCurrent|tag,amount,angle,useline +Sector property|183|Line_AlignFloor|lineid,side +Sector property|184|Line_AlignCeiling|lineid,side +Sector property|185|Sector_SetRotation|tag,floor-angle,ceiling-angle +Sector property|186|Sector_SetCeilingPanning|tag,u-int,u-frac,v-int,v-frac +Sector property|187|Sector_SetFloorPanning|tag,u-int,u-frac,v-int,v-frac +Sector property|188|Sector_SetCeilingScale|tag,u-int,u-frac,v-int,v-frac +Sector property|189|Sector_SetFloorScale|tag,u-int,u-frac,v-int,v-frac + +Things|72|ThrustThing|angle,force +Things|73|DamageThing|amount +Things|248|HealThing|amount +Things|130|Thing_Activate|tid +Things|131|Thing_Deactivate|tid +Things|132|Thing_Remove|tid +Things|133|Thing_Destroy|tid +Things|134|Thing_Projectile|tid,type,angle,speed,vspeed +Things|136|Thing_ProjectileGravity|tid,type,angle,speed,vspeed +Things|135|Thing_Spawn|tid,type,angle +Things|137|Thing_SpawnNoFog|tid,type,angle +Things|229|Thing_SetGoal|tid,goal,delay + +ACS|80|ACS_Execute|script,map,s_arg1,s_arg2,s_arg3 +ACS|226|ACS_ExecuteAlways|script,map,s_arg1,s_arg2,s_arg3 +ACS|83|ACS_LockedExecute|script,map,s_arg1,s_arg2,lock +ACS|81|ACS_Suspend|script,map +ACS|82|ACS_Terminate|script,map + +Misc|121|Line_SetIdentification|lineid +Misc|208|TranslucentLine|lineid,amount +Misc|100|Scroll_Texture_Left|speed +Misc|101|Scroll_Texture_Right|speed +Misc|102|Scroll_Texture_Up|speed +Misc|103|Scroll_Texture_Down|speed +Misc|221|Scroll_Texture_Both|lineid,left,right,down,up +Misc|225|Scroll_Texture_Offsets +Misc|222|Scroll_Texture_Model|lineid,scrollbits +Misc|223|Scroll_Floor|tag,scrollbits,0=scroll:1=carry:2=both,x-move,y-move +Misc|224|Scroll_Ceiling|tag,scrollbits,0,x-move,y-move +Misc|209|Transfer_Heights|tag,when +Misc|210|Transfer_FloorLight|tag +Misc|211|Transfer_CeilingLight|tag +Misc|120|Radius_Quake|intensity,duration,damrad,tremrad,tid +Misc|227|PointPush_SetForce|tag,tid,amount,useline +Misc|237|ChangeCamera|tid,who,revert +Misc|191|SetPlayerProperty|who,set,which -- cgit v1.2.3