diff options
author | Ian C <ianc@noddybox.co.uk> | 2011-06-09 13:57:32 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2011-06-09 13:57:32 +0000 |
commit | ec32cf41f916fc34c03d2844684631bee39005ad (patch) | |
tree | 0ecd4b3a8602ba76df3b9395eb6c71c350d510df |
Added copies of old numbered releases.0.02
-rw-r--r-- | LICENSE | 341 | ||||
-rw-r--r-- | README | 33 | ||||
-rw-r--r-- | base.ini | 135 | ||||
-rw-r--r-- | config.h | 108 | ||||
-rw-r--r-- | debug.c | 212 | ||||
-rw-r--r-- | debug.h | 66 | ||||
-rw-r--r-- | djgpp/file.c | 126 | ||||
-rw-r--r-- | djgpp/gfx.c | 535 | ||||
-rw-r--r-- | djgpp/install | 31 | ||||
-rw-r--r-- | djgpp/install.c | 119 | ||||
-rw-r--r-- | djgpp/main.c | 34 | ||||
-rw-r--r-- | djgpp/mem.c | 325 | ||||
-rw-r--r-- | djgpp/platgui.c | 1976 | ||||
-rw-r--r-- | djgpp/runcmd.c | 61 | ||||
-rw-r--r-- | djgpp/vstring.c | 42 | ||||
-rw-r--r-- | doc/bugs.htm | 40 | ||||
-rw-r--r-- | doc/building.htm | 90 | ||||
-rw-r--r-- | doc/changelog.htm | 49 | ||||
-rw-r--r-- | doc/ed_ex1.png | bin | 0 -> 262 bytes | |||
-rw-r--r-- | doc/ed_ex2.png | bin | 0 -> 304 bytes | |||
-rw-r--r-- | doc/ed_ex3.png | bin | 0 -> 327 bytes | |||
-rw-r--r-- | doc/ed_line.png | bin | 0 -> 7837 bytes | |||
-rw-r--r-- | doc/ed_lninf.png | bin | 0 -> 1267 bytes | |||
-rw-r--r-- | doc/ed_merge.png | bin | 0 -> 10423 bytes | |||
-rw-r--r-- | doc/ed_multi.png | bin | 0 -> 11443 bytes | |||
-rw-r--r-- | doc/ed_sect.png | bin | 0 -> 10062 bytes | |||
-rw-r--r-- | doc/ed_step.png | bin | 0 -> 9039 bytes | |||
-rw-r--r-- | doc/ed_thing.png | bin | 0 -> 10467 bytes | |||
-rw-r--r-- | doc/ed_vert.png | bin | 0 -> 8125 bytes | |||
-rw-r--r-- | doc/editing.htm | 1295 | ||||
-rw-r--r-- | doc/glossary.htm | 127 | ||||
-rw-r--r-- | doc/index.htm | 47 | ||||
-rw-r--r-- | doc/license.htm | 362 | ||||
-rw-r--r-- | doc/mainmenu.htm | 111 | ||||
-rw-r--r-- | doc/overview.htm | 881 | ||||
-rw-r--r-- | doc/porting.htm | 1318 | ||||
-rw-r--r-- | doc/thanks.htm | 70 | ||||
-rw-r--r-- | doom.cfg | 527 | ||||
-rw-r--r-- | doom2.cfg | 72 | ||||
-rw-r--r-- | edit.c | 734 | ||||
-rw-r--r-- | edit.h | 70 | ||||
-rw-r--r-- | editcord.c | 225 | ||||
-rw-r--r-- | editcrse.c | 398 | ||||
-rw-r--r-- | editdraw.c | 346 | ||||
-rw-r--r-- | editevnt.c | 1058 | ||||
-rw-r--r-- | editgui.c | 470 | ||||
-rw-r--r-- | editilst.c | 106 | ||||
-rw-r--r-- | editline.c | 3361 | ||||
-rw-r--r-- | editmrg.c | 567 | ||||
-rw-r--r-- | editmult.c | 680 | ||||
-rw-r--r-- | editsect.c | 1612 | ||||
-rw-r--r-- | editsel.c | 133 | ||||
-rw-r--r-- | editsrot.c | 76 | ||||
-rw-r--r-- | editthng.c | 670 | ||||
-rw-r--r-- | editvar.c | 396 | ||||
-rw-r--r-- | editvar.h | 633 | ||||
-rw-r--r-- | editvert.c | 840 | ||||
-rw-r--r-- | file.h | 58 | ||||
-rw-r--r-- | gfx.h | 314 | ||||
-rw-r--r-- | gfxtest.c | 468 | ||||
-rw-r--r-- | globals.c | 983 | ||||
-rw-r--r-- | globals.h | 211 | ||||
-rw-r--r-- | gui.c | 391 | ||||
-rw-r--r-- | gui.h | 88 | ||||
-rw-r--r-- | ini.c | 532 | ||||
-rw-r--r-- | ini.h | 106 | ||||
-rw-r--r-- | linedefs.c | 371 | ||||
-rw-r--r-- | linedefs.h | 100 | ||||
-rw-r--r-- | list.c | 288 | ||||
-rw-r--r-- | list.h | 104 | ||||
-rw-r--r-- | make/djgpp.cfg | 41 | ||||
-rw-r--r-- | makefile | 259 | ||||
-rw-r--r-- | map.c | 162 | ||||
-rw-r--r-- | map.h | 86 | ||||
-rw-r--r-- | mem.h | 79 | ||||
-rw-r--r-- | platgui.h | 199 | ||||
-rw-r--r-- | runcmd.h | 57 | ||||
-rw-r--r-- | sectors.c | 318 | ||||
-rw-r--r-- | sectors.h | 96 | ||||
-rw-r--r-- | texture.c | 594 | ||||
-rw-r--r-- | texture.h | 69 | ||||
-rw-r--r-- | things.c | 331 | ||||
-rw-r--r-- | things.h | 88 | ||||
-rw-r--r-- | util.c | 61 | ||||
-rw-r--r-- | util.h | 45 | ||||
-rw-r--r-- | vidoom.c | 726 | ||||
-rw-r--r-- | vidoom.h | 44 | ||||
-rw-r--r-- | vstring.h | 44 | ||||
-rw-r--r-- | wad.c | 806 | ||||
-rw-r--r-- | wad.h | 242 | ||||
-rw-r--r-- | waddir.c | 75 |
91 files changed, 29944 insertions, 0 deletions
@@ -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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + + <signature of Ty Coon>, 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. + @@ -0,0 +1,33 @@ + viDOOM v0.00 + + +viDOOM is released as Free Software. Please see LICENSE for conditions. + + + +To build viDOOM: + +1. Edit makfile. Follow the instructions for configuration at the top + of the makefile. + +2. Type 'make'. + + + +To install viDOOM: + +1. Type 'make install'. + + If install fails, or you wish to do it manully, simply copy the viDOOM + executable and the files doom.cfg and doom2.cfg to a directory. + Copy base.ini to the directory and rename it as vidoom.ini. + +2. In the directory into which viDOOM has been installed, edit vidoom.ini + to set the paths to various IWAD files. + See doc/overview.htm for details. + + + +-------------------------------------------------------------------------- + +$Id: README,v 1.4 2000/07/21 16:23:57 dosuser Exp dosuser $ diff --git a/base.ini b/base.ini new file mode 100644 index 0000000..576c8fb --- /dev/null +++ b/base.ini @@ -0,0 +1,135 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# +# viDOOM INI file +# +# $Id: base.ini,v 1.33 2000/08/13 16:11:32 dosuser Exp dosuser $ +# + +[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 +linedef_select=2 +merge_linedef=ask +new_2sided_select=ask +sector_move=all +show_full_linedef_info=no +tag_highlight=yes +vertex_radius=8 +width=640 +height=480 + +[Check LINEDEF] +assume_yes=no +check_1side_lower=yes +check_1side_middle=yes +check_1side_upper=yes +check_2side_lower=yes +check_2side_middle=yes +check_2side_same_sector=yes +check_2side_upper=yes + +[viDOOM] +initial_empty_map=yes +load_flats=yes +load_sprites=yes +load_textures=yes +map_clear_warning=yes +map_exit_warning=yes +overwrite_warning=yes +show_titlepic=yes +sort_flat_names=yes +sort_texture_names=yes + +[Node Builder] +always_view_output=yes +command=bsp.exe +ignore=struct +in_before_out=yes +infile=% +outfile=-o % +use=no + +[GUI] +high=0xd2d2d2 +mid=0xb4b4b4 +low=0x8c8c8c +text=0xffffff +shadow=0x000000 +bold=0x000000 + + +[Doom] +iwad=c:\doom\doom.wad +pwad_dir=c:\wads\ +preload= +level_style=doom +vidoom_config=doom.cfg + +[Ultimate Doom] +iwad=c:\doom\ultdoom.wad +pwad_dir=c:\wads\ +preload= +level_style=ultimate doom +vidoom_config=doom.cfg + +[Doom 2] +iwad=c:\doom\doom2.wad +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +[TNT:Evilution] +iwad=c:\doom\tnt.wad +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +[Plutonia Experiment] +iwad=c:\doom\plutonia.wad +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg + +[ZDoom] +iwad=c:\doom\doom2.wad +pwad_dir=c:\wads\ +preload= +level_style=doom 2 +vidoom_config=doom2.cfg diff --git a/config.h b/config.h new file mode 100644 index 0000000..5bd38ef --- /dev/null +++ b/config.h @@ -0,0 +1,108 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Global config and macros + + $Id$ + +*/ + +#ifndef _CONFIG_H + +#define _CONFIG_H + +/* Usual constants +*/ +#include <stdlib.h> +#include <limits.h> +#include <string.h> + + +/* Global viDOOM includes +*/ +#include "debug.h" +#include "vstring.h" + + +/* Version +*/ +#define VIDOOMVER "0.02" +#define VIDOOMRELEASE "(Build 13/08/2000)" + + +/* Basic, global machine types +*/ +typedef unsigned char Byte; +typedef unsigned short Word; +typedef signed short Short; +typedef unsigned long Long; + + +/* True/False +*/ +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + + +/* MIN,MAX,ABS and SGN +*/ +#ifndef MIN +# define MIN(a,b) ((a)<(b) ? (a):(b)) +#endif + +#ifndef MAX +# define MAX(a,b) ((a)>(b) ? (a):(b)) +#endif + +#ifndef ABS +# define ABS(a) ((a)<0 ? -(a):(a)) +#endif + +#ifndef SGN +# define SGN(a) ((a)<0 ? -1:(a)>0 ? 1:0) +#endif + + +/* String equalities +*/ +#define STREQ(a,b) (!StrCaseCmp((a),(b))) +#define STRNEQ(a,b) (!StrNCaseCmp((a),(b),strlen(a))) + + +/* String to integer +*/ +#define ATOI(s) ((int)strtol((s),NULL,0)) + + +/* Max path length +*/ +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + + +#endif @@ -0,0 +1,212 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Debug output + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> + +#include "debug.h" + +static FILE *trace_fp=NULL; + +void _Debug(char *fmt,...) +{ + static char last[512]=""; + static char this[512]=""; + static int rep=0; + int f; + va_list va; + + if (!trace_fp) + { + trace_fp=fopen("trace.out","w"); + setbuf(trace_fp,NULL); + } + + if (trace_fp) + { + va_start(va,fmt); + vsprintf(this,fmt,va); + va_end(va); + + if (strcmp(last,this)==0) + { + rep++; + if (rep==3) + fprintf(trace_fp,"DEBUG: *** Repeating...\n"); + } + else + { + if (rep) + { + if (rep>2) + fprintf(trace_fp,"DEBUG: *** Repeated %d times\n",rep); + else + for(f=0;f<rep;f++) + fprintf(trace_fp,"DEBUG: %s",last); + rep=0; + } + + fprintf(trace_fp,"DEBUG: %s",this); + strcpy(last,this); + } + } +} + + +void _Trace(char *fmt,...) +{ +#ifdef DEBUG + static int ok=TRUE; + static int check=FALSE; + static char last[512]=""; + static char this[512]=""; + static int rep=0; + int f; + va_list va; + + if (!ok) + return; + + if (!check) + { + check=TRUE; + + if ((getenv("VIDOOM_TRACE"))&&(!strcmp(getenv("VIDOOM_TRACE"),"Y"))) + ok=TRUE; + else + { + ok=FALSE; + return; + } + } + + if (!trace_fp) + { + trace_fp=fopen("trace.out","w"); + setbuf(trace_fp,NULL); + } + + if (trace_fp) + { + va_start(va,fmt); + vsprintf(this,fmt,va); + va_end(va); + + if (strcmp(last,this)==0) + { + rep++; + if (rep==3) + fprintf(trace_fp,"*** Repeating...\n"); + else if ((rep%10)==0) + fprintf(trace_fp,"*** Still repeating - %d times\n",rep); + } + else + { + if (rep) + { + if (rep>2) + fprintf(trace_fp,"*** Repeated %d times\n",rep); + else + for(f=0;f<rep;f++) + fprintf(trace_fp,"%s",last); + rep=0; + } + + fprintf(trace_fp,"%s",this); + strcpy(last,this); + } + } +#endif +} + + +char *Binstr(int val, int width) +{ + static char s[48]; + char *p; + + p=s; + width--; + while(width>=0) + { + if (val&(1<<width)) + *p++='1'; + else + *p++='0'; + + width--; + } + + *p=0; + + return(s); +} + + +char *MemStr(char *addr,int size) +{ + static char s[1024]; + int i; + + i=0; + + while(size) + { + if (isprint(*addr)) + s[i++]=*addr; + else if (*addr=='\0') + s[i++]='@'; + else if (*addr=='\n') + { + strcpy(s+i,"\\n"); + i+=2; + } + else + { + sprintf(s+i,"\\%3.3o",(unsigned int)*addr); + i+=4; + } + + if (i>(sizeof(s)-10)) + { + sprintf(s+i,"<...>"); + return(s); + } + + size--; + addr++; + } + + s[i]=0; + return(s); +} + + +/* END OF FILE */ @@ -0,0 +1,66 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Debug output + + $Id$ + +*/ + +#ifndef _DEBUG_H + +#define _DEBUG_H + +#include <stdio.h> + +#ifdef DEBUG +# define Debug(x) _Debug x +#else +# define Debug(x) +#endif + +/* Macro for function tracing. Use as: + void func(void) + { + int a; + + TRACE; + ... + } +*/ +#define TRACE _Trace(TRACEFORM) + +void _Debug(char *fmt,...); +void _Trace(char *fmt,...); + +/* Utils for debug users. Converts val to a n-character binary string +*/ +char *Binstr(int val,int n); + +/* Prints out memory as a string +*/ +char *MemStr(char *addr,int size); + +#endif + + +/* END OF FILE */ diff --git a/djgpp/file.c b/djgpp/file.c new file mode 100644 index 0000000..49bdc72 --- /dev/null +++ b/djgpp/file.c @@ -0,0 +1,126 @@ +/* + + 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 <unistd.h> +#include <string.h> + + +/* ---------------------------------------- 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) +{ + FILE *fp; + + if ((fp=fopen(path,"rb"))) + { + fclose(fp); + return(TRUE); + } + else + return(FALSE); +} + +int FilenamesEqual(char *path1, char *path2) +{ + char p1[PATH_MAX],p2[PATH_MAX]; + + strcpy(p1,path1); + strcpy(p2,path2); + + ChangeDirsep(p1); + ChangeDirsep(p2); + + return(!strcasecmp(p1,p2)); +} + + +/* END OF FILE */ diff --git a/djgpp/gfx.c b/djgpp/gfx.c new file mode 100644 index 0000000..8d8e849 --- /dev/null +++ b/djgpp/gfx.c @@ -0,0 +1,535 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Graphics functions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include <stdio.h> +#include <allegro.h> +#include <stdarg.h> +#include <ctype.h> +#include <time.h> +#include "gfx.h" +#include "gui.h" +#include "debug.h" + + +/* ---------------------------------------- VARS +*/ +#define COLDEP 16 +#define ACOL(c) (makecol_depth(COLDEP,((c)&0xff0000)>>16, \ + ((c)&0xff00)>>8, \ + ((c)&0xff))) + +static int init=FALSE; + +static BITMAP *bm; +static int width; +static int height; + +static int mbuttons; + +static int dirty_min_x; +static int dirty_max_x; +static int dirty_min_y; +static int dirty_max_y; + +#define DIRTY(x,y) do { \ + dirty_min_x=MIN(x,dirty_min_x); \ + dirty_min_y=MIN(y,dirty_min_y); \ + dirty_max_x=MAX((x)+1,dirty_max_x); \ + dirty_max_y=MAX((y)+1,dirty_max_y); \ + } while(0) + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ + +static void GetKey(GFXKey *key) +{ + static struct + { + int alleg; + int code; + } keym[]= { + {KEY_F1,GFX_F1}, + {KEY_F2,GFX_F2}, + {KEY_F3,GFX_F3}, + {KEY_F4,GFX_F4}, + {KEY_F5,GFX_F5}, + {KEY_F6,GFX_F6}, + {KEY_F7,GFX_F7}, + {KEY_F8,GFX_F8}, + {KEY_F9,GFX_F9}, + {KEY_F10,GFX_F10}, + {KEY_F11,GFX_F11}, + {KEY_F12,GFX_F12}, + {KEY_ESC,GFX_ESC}, + {KEY_INSERT,GFX_INSERT}, + {KEY_HOME,GFX_HOME}, + {KEY_PGUP,GFX_PGUP}, + {KEY_DEL,GFX_DELETE}, + {KEY_END,GFX_END}, + {KEY_PGDN,GFX_PGDN}, + {KEY_UP,GFX_UP}, + {KEY_DOWN,GFX_DOWN}, + {KEY_LEFT,GFX_LEFT}, + {KEY_RIGHT,GFX_RIGHT}, + {KEY_ENTER,GFX_ENTER}, + {KEY_BACKSPACE,GFX_BACKSPACE}, + {KEY_TAB,GFX_TAB}, + {-1,-1}, + }; + int f; + int k; + + while(TRUE) + { + k=readkey(); + + key->shift=key_shifts&KB_SHIFT_FLAG; + key->ctrl=key_shifts&KB_CTRL_FLAG; + key->alt=key_shifts&KB_ALT_FLAG; + + f=0; + while(keym[f].code!=-1) + { + if (keym[f].alleg==k>>8) + { + key->ascii=0; + key->code=keym[f].code; + return; + } + + f++; + } + + if (isprint(k&0xff)) + { + key->ascii=(k&0xff); + key->code=GFX_ASCII; + return; + } + } +} + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void GFX_init(void) +{ + if (!init) + { + init=TRUE; + allegro_init(); + + install_keyboard(); + + install_timer(); + + if ((mbuttons=install_mouse())==-1) + GFX_exit(EXIT_FAILURE,"Failed to install mouse handler\n"); + + set_color_depth(COLDEP); + } +} + + +void GFX_close(void) +{ + if (init) + { + allegro_exit(); + init=FALSE; + } +} + + +void GFX_open(int w,int h) +{ + height=h; + width=w; + + if (set_gfx_mode(GFX_AUTODETECT,w,h,0,0)<0) + GFX_exit(EXIT_FAILURE,"Couldn't open screen of %dx%d\n",w,h); + + if (!(bm=create_bitmap(w,h))) + GFX_exit(EXIT_FAILURE,"Couldn't create bitmap of %dx%d\n",w,h); + + show_mouse(screen); +} + + +void GFX_clear(int col) +{ + clear_to_color(bm,ACOL(col)); + dirty_min_x=0; + dirty_max_x=width; + dirty_min_y=0; + dirty_max_y=width; +} + + +void GFX_redraw(void) +{ + if (dirty_max_x<dirty_min_x) + return; + + dirty_min_x=MAX(0,dirty_min_x); + dirty_min_y=MAX(0,dirty_min_y); + dirty_max_x=MIN(width,dirty_max_x); + dirty_max_y=MIN(height,dirty_max_y); + + show_mouse(NULL); + + blit(bm,screen,dirty_min_x,dirty_min_y, + dirty_min_x,dirty_min_y, + dirty_max_x-dirty_min_x+1,dirty_max_y-dirty_min_y+1); + + show_mouse(screen); + + dirty_max_x=0; + dirty_min_x=width-1; + dirty_max_y=0; + dirty_min_y=width-1; +} + + +void GFX_FORCE_REDRAW(void) +{ + show_mouse(NULL); + blit(bm,screen,0,0,0,0,width,height); + show_mouse(screen); + dirty_max_x=0; + dirty_min_x=width-1; + dirty_max_y=0; + dirty_min_y=width-1; +} + + +void GFX_line(int x1,int y1,int x2,int y2,int col) +{ + DIRTY(x1,y1); + DIRTY(x2,y2); + line(bm,x1,y1,x2,y2,ACOL(col)); +} + + +void GFX_plot(int x,int y,int col) +{ + DIRTY(x,y); + putpixel(bm,x,y,ACOL(col)); +} + + +void GFX_circle(int x,int y,int r,int col) +{ + DIRTY(x-r-1,y-r-1); + DIRTY(x+r+1,y+r+1); + circle(bm,x,y,r,ACOL(col)); +} + + +void GFX_fcircle(int x,int y,int r,int col) +{ + DIRTY(x-r-1,y-r-1); + DIRTY(x+r+1,y+r+1); + circlefill(bm,x,y,r,ACOL(col)); +} + + +void GFX_rect(int x,int y,int w,int h,int col) +{ + DIRTY(x,y); + DIRTY(x+w,y+h); + + w-=SGN(w); + h-=SGN(h); + + rect(bm,x,y,x+w,y+h,ACOL(col)); +} + + +void GFX_frect(int x,int y,int w,int h,int col) +{ + DIRTY(x,y); + DIRTY(x+w,y+h); + + w-=SGN(w); + h-=SGN(h); + + rectfill(bm,x,y,x+w,y+h,ACOL(col)); +} + + +void GFX_set_XOR_mode(void) +{ + drawing_mode(DRAW_MODE_XOR,NULL,0,0); +} + + +void GFX_clear_XOR_mode(void) +{ + drawing_mode(DRAW_MODE_SOLID,NULL,0,0); +} + + +void GFX_print(int x,int y,int col,char *fmt,...) +{ + char s[512]; + va_list va; + + va_start(va,fmt); + vsprintf(s,fmt,va); + va_end(va); + + DIRTY(x,y); + DIRTY(x+text_length(font,s),y+text_height(font)); + + text_mode(-1); + textout(bm,font,s,x,y,ACOL(col)); +} + + +int GFX_fh(void) +{ + return(text_height(font)); +} + + +int GFX_fw(void) +{ + return(text_length(font," ")); +} + + +int GFX_mouse_buttons(void) +{ + return(mbuttons); +} + + +int GFX_mouse(int *x,int *y) +{ + if (x) + *x=mouse_x; + + if (y) + *y=mouse_y; + + return(mouse_b); +} + + +void GFX_waitkey(GFXKey *key) +{ + GFXKey dummy; + + while(!keypressed()); + if (key) + GetKey(key); + else + GetKey(&dummy); +} + + +int GFX_key(GFXKey *key) +{ + if(!keypressed()) + return(FALSE); + else + { + GetKey(key); + return(TRUE); + } +} + + +void GFX_bounce(void) +{ + while((keypressed())||(mouse_b)) + if (keypressed()) + readkey(); +} + + +void GFX_await_input(GFXEvent *ev) +{ + static time_t last_time=0; + static int mb; + + /* Assume that a gap of 1-2 seconds means that this is a new await + input loop + */ + if (time(NULL)-last_time>1) + 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;x<bm->w;x++) + for(y=0;y<bm->h;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 <stdio.h> +#include <unistd.h> +#include <stdarg.h> + +/* 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..b0de233 --- /dev/null +++ b/djgpp/mem.c @@ -0,0 +1,325 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Memory allocation code + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include <stdio.h> +#include <string.h> + +#include "mem.h" +#include "gfx.h" + +#include "debug.h" + +/* Comment out this define to switch off memory stats in the working version +#define MEMSTAT +*/ + +#ifdef MEMSTAT + +typedef struct + { + Long size; + Long realloc; + Long free; + char file[32]; + Long line; + } MemInfo; + +static Long grab_call=0; +static Long regrab_call=0; +static Long release_call=0; +static Long copy_call=0; +static Long strdup_call=0; +static Long total=0; +static Long total_grab=0; +static Long total_regrab=0; +static Long total_copy=0; +static Long total_free=0; +static Long total_strdup=0; + +static void status(void) +{ + Debug(("Total calls to Grab() : %lu\n",grab_call)); + Debug(("Total calls to Regrab() : %lu\n",regrab_call)); + Debug(("Total calls to Release() : %lu\n",release_call)); + Debug(("Total calls to Copy() : %lu\n",copy_call)); + Debug(("Total calls to Strdup() : %lu\n",strdup_call)); + Debug(("Total bytes allocated : %lu\n",total)); + Debug(("Total bytes allocated over life : %lu\n",total_grab)); + Debug(("Total bytes regrabbed over life : %lu\n",total_regrab)); + Debug(("Total bytes copied over life : %lu\n",total_copy)); + Debug(("Total bytes released over life : %lu\n",total_free)); + Debug(("Total bytes strdupped over life : %lu\n\n",total_strdup)); +} + +#endif + + +#ifdef MEMSTAT + +void *FGrab(char *fn, int line, int len) +{ + char *ptr; + MemInfo *mi; + + if (len==0) + len=1; + + if (!(ptr=malloc(len+sizeof(MemInfo)))) + { + status(); + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Grab(%d)\n",fn,line,len); + } + + mi=(MemInfo *)ptr; + mi->size=len; + mi->realloc=0; + mi->free=0; + ptr+=sizeof(MemInfo); + + grab_call++; + total_grab+=len; + total+=len; + + memset(ptr,0,len); + + return(ptr); +} + +#else + +void *FGrab(char *fn, int line, int len) +{ + void *ptr; + + if (len==0) + len=1; + + if (!(ptr=malloc(len))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Grab(%d)\n",fn,line,len); + + memset(ptr,0,len); + + return(ptr); +} + +#endif + + +#ifdef MEMSTAT + +void *FReGrab(char *fn, int line, void *ptr, int len) +{ + Long old; + MemInfo *mi; + char *p; + + if (len==0) + len=1; + + p=ptr; + + if (p) + p-=sizeof(MemInfo); + + if (!(p=realloc(p,len+sizeof(MemInfo)))) + { + status(); + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d ReGrab(%d)\n",fn,line,len); + } + + regrab_call++; + total_regrab+=len; + + mi=(MemInfo *)p; + old=mi->size; + mi->size=len; + mi->realloc++; + total-=old; + total+=len; + + p+=sizeof(MemInfo); + + return(p); +} + +#else + +void *FReGrab(char *fn, int line, void *ptr, int len) +{ + if (len==0) + len=1; + + if (!(ptr=realloc(ptr,len))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d ReGrab(%d)\n",fn,line,len); + + return(ptr); +} + +#endif + + +#ifdef MEMSTAT + +void FRelease(char *fn, int line, void *p) +{ + char *cp; + MemInfo *mi; + + if (!p) + return; + + cp=p; + cp-=sizeof(MemInfo); + mi=(MemInfo *)cp; + + if (mi->free==1) + Debug(("%p already freed!!! Current=%s:%d, previous=%s:%d\n", + p,fn,line,mi->file,mi->line)); + + release_call++; + + total_free+=mi->size; + total-=mi->size; + + strcpy(mi->file,fn); + mi->line=line; + mi->free=1; + + free(cp); +} + +#else + +void FRelease(char *fn, int line, void *p) +{ + free(p); +} + +#endif + + +#ifdef MEMSTAT + +void *FCopy(char *fn, int line, void *p,int len) +{ + char s[128]; + void *ptr; + + strcpy(s,fn); + strcat(s," [FCopy()]"); + + if (len==0) + ptr=FGrab(s,line,1); + else + ptr=FGrab(s,line,len); + + copy_call++; + total_copy+=len; + + if (len) + memcpy(ptr,p,len); + + return(ptr); +} + +#else + +void *FCopy(char *fn, int line, void *p,int len) +{ + void *ptr; + + if (len==0) + ptr=malloc(1); + else + ptr=malloc(len); + + if (!ptr) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Copy(%p,%d)\n",fn,line,p,len); + + if (len) + memcpy(ptr,p,len); + + return(ptr); +} + +#endif + + +#ifdef MEMSTAT + +char *FStrdup(char *fn, int line, char *p) +{ + char s[128]; + char *ptr; + + strcpy(s,fn); + strcat(s," [Strdup()]"); + + if (p) + { + ptr=FGrab(s,line,strlen(p)+1); + + strdup_call++; + total_strdup+=strlen(p)+1; + + strcpy(ptr,p); + return(ptr); + } + else + return(NULL); +} + +#else + +char *FStrdup(char *fn, int line, char *p) +{ + char *ptr; + + if (p) + { + if (!(ptr=malloc(strlen(p)+1))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Stdup(%s)\n",fn,line,p); + + strcpy(ptr,p); + return(ptr); + } + else + return(NULL); +} + +#endif + + +/* END OF FILE */ diff --git a/djgpp/platgui.c b/djgpp/platgui.c new file mode 100644 index 0000000..c17985c --- /dev/null +++ b/djgpp/platgui.c @@ -0,0 +1,1976 @@ +/* + + 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 <stdio.h> +#include <allegro.h> +#include <string.h> + +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <dir.h> +#include <limits.h> +#include <ctype.h> +#include <fcntl.h> + +#include "platgui.h" +#include "gfx.h" +#include "gui.h" +#include "mem.h" + +#include "debug.h" + +#define COLDEP 16 +#define ACOL(c) (makecol_depth(COLDEP,((c)&0xff0000)>>16, \ + ((c)&0xff00)>>8, \ + ((c)&0xff))) + +#define DIALOG_STRLEN 16 + +#define SMALL_BEVEL 1 /* Bevels on radio and flag boxes */ +#define BEVEL 2 /* All other bevels */ +#define TICK 2 + +/* ---------------------------------------- VARS +*/ +static int SCRW,SCRH; + +/* Global picklist data and the picklist dialog +*/ +#define PL_BORDER 0 +#define PL_TITLE 1 +#define PL_PICKLIST 2 +#define PL_END 3 + +static DIALOG picklist[PL_END+1]; +static int pick_no; +static char **pick_data; + + +/* Global image picklist data and the image picklist dialog +*/ +#define IPL_BORDER 0 +#define IPL_TITLE 1 +#define IPL_PICKLIST 2 +#define IPL_IMG_BORDER 3 +#define IPL_IMAGE 4 +#define IPL_END 5 + +static DIALOG img_picklist[IPL_END+1]; +static int img_pick_no; +static PLAT_IMG_PICKLIST + *img_pick_data; + + +typedef struct + { + int x; + int y; + int w; + int h; + } BoundBox; + + +/* ---------------------------------------- GUI OBJECT PROCS SUPPORT FUNCS +*/ +static void Rect3D(int x,int y,int w,int h, int invert,int bevel) +{ + int f; + int mid,lo,hi; + + mid=ACOL(GUI_MID); + + if (invert) + { + lo=ACOL(GUI_HI); + hi=ACOL(GUI_LO); + } + else + { + hi=ACOL(GUI_HI); + lo=ACOL(GUI_LO); + } + + rectfill(screen,x,y,x+w-1,y+h-1,mid); + + for(f=0;f<bevel;f++) + { + vline(screen,x+f,y+f,y+h-1-f,hi); + vline(screen,x+w-1-f,y+f,y+h-1-f,lo); + + hline(screen,x+f,y+f,x+w-1-f,hi); + hline(screen,x+f,y+h-1-f,x+w-1-f,lo); + } +} + + +static void DrawTick(int x,int y,int w,int h) +{ + int ox,oy,x2,y2,x3,y3; + int f; + + x2=x+(w/4); + y2=y+h-1; + + x3=x2; + y3=y2; + + while(x3<(x+w-1)) + { + x3++; + y3--; + } + + ox=x; + oy=y; + + x=x2; + y=y2; + + while(x>ox) + { + x--; + y--; + } + + for(f=0;f<TICK;f++) + { + line(screen,x,y,x2,y2,ACOL(BLACK)); + line(screen,x2,y2,x3,y3,ACOL(BLACK)); + + y--; + y2--; + y3--; + } +} + + +/* This code is based on _draw_scrollable_frame() from guiproc.c in Allegro +*/ +static void DrawScrollableFrame(DIALOG *d, int listsize, int offset, + int height, int fg_color, int bg) +{ + BITMAP *pattern; + int i, len; + int xx, yy; + + /* draw frame + */ + rect(screen, d->x, 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; i<height; i++) + { + if (d->d2+i < listsize) + { + if (d->d2+i == d->d1) + { + fg = d->bg; + bg = fg_color; + } + else if ((sel) && (sel[d->d2+i])) + { + fg = d->bg; + bg = gui_mg_color; + } + else + { + fg = fg_color; + bg = d->bg; + } + + s = (*(getfuncptr)d->dp)(i+d->d2, NULL); + x = d->x + 2; + y = d->y + 2 + i*text_height(font); + text_mode(bg); + rectfill(screen, x, y, x+7, y+text_height(font)-1, bg); + x += 8; + len = strlen(s); + store = 0; + while (text_length(font, s) >= d->w - (bar ? 22 : 10)) + { + s[len] = store; + len--; + store = s[len]; + s[len] = 0; + } + textout(screen, font, s, x, y, fg); + x += text_length(font, s); + s[len] = store; + if (x <= d->x+w) + rectfill(screen, x, y, d->x+w, y+text_height(font)-1, bg); + } + else + rectfill(screen, d->x+2, d->y+2+i*text_height(font), + d->x+w, d->y+1+(i+1)*text_height(font), d->bg); + } + + if (d->y+2+i*text_height(font) <= d->y+d->h-2) + rectfill(screen, d->x+2, d->y+2+i*text_height(font), + d->x+w, d->y+d->h-2, d->bg); + + /* draw frame, maybe with scrollbar + */ + DrawScrollableFrame(d, listsize, d->d2, height, fg_color, d->bg); +} + + +/* ---------------------------------------- GUI OBJECT PROCS + + Note that many of the functions are based on the source available + in guiproc.c in Allegro +*/ +static int d_3d_box(int msg, DIALOG *d, int c) +{ + if (msg==MSG_DRAW) + Rect3D(d->x,d->y,d->w,d->h,FALSE,BEVEL); + + return(D_O_K); +} + + +static int d_inv_3d_box(int msg, DIALOG *d, int c) +{ + if (msg==MSG_DRAW) + Rect3D(d->x,d->y,d->w,d->h,TRUE,BEVEL); + + return(D_O_K); +} + + +static int d_img_bmap_proc(int msg, DIALOG *d, int c) +{ + RLE_SPRITE *bm; + + if (msg==MSG_DRAW) + { + d_inv_3d_box(MSG_DRAW,&img_picklist[IPL_IMG_BORDER],0); + + if ((bm=d->dp)) + draw_rle_sprite(screen,bm,d->x,d->y); + else + gui_textout(screen,"No Image", + d->x+d->w/2,d->y+d->h/2,ACOL(BLACK),TRUE); + } + + return(D_O_K); +} + + +static int d_img_list_proc(int msg, DIALOG *d, int c) +{ + static int my_d_list_proc(int msg, DIALOG *d, int c); + int d1; + int ret; + + d1=img_picklist[IPL_PICKLIST].d1; + + ret=my_d_list_proc(msg,d,c); + + if (d1!=img_picklist[IPL_PICKLIST].d1) + { + img_picklist[IPL_IMAGE].dp= + img_pick_data[img_picklist[IPL_PICKLIST].d1].img; + + d_inv_3d_box(MSG_DRAW,&img_picklist[IPL_IMG_BORDER],0); + d_img_bmap_proc(MSG_DRAW,&img_picklist[IPL_IMAGE],0); + } + + return(ret); +} + + +int my_d_check_proc(int msg, DIALOG *d, int c) +{ + int x; + int fg; + + if (msg==MSG_DRAW) + { + fg = (d->flags & D_DISABLED) ? gui_mg_color : d->fg; + text_mode(d->bg); + gui_textout(screen, d->dp, d->x, + d->y+(d->h-(text_height(font)-gui_font_baseline))/2, + fg, FALSE); + + x=d->x+d->w-d->h; + + Rect3D(x,d->y,d->h,d->h,TRUE,SMALL_BEVEL); + rectfill(screen,x+SMALL_BEVEL,d->y+SMALL_BEVEL, + x+d->h-SMALL_BEVEL*2,d->y+d->h-SMALL_BEVEL*2, + ACOL(WHITE)); + + if (d->flags & D_SELECTED) + DrawTick(x+SMALL_BEVEL,d->y+SMALL_BEVEL, + d->h-SMALL_BEVEL*2,d->h-SMALL_BEVEL*2); + + return D_O_K; + } + + return d_button_proc(msg, d, 0); +} + + +int my_d_radio_proc(int msg, DIALOG *d, int c) +{ + int x,fg; + + switch(msg) + { + case MSG_DRAW: + fg=(d->flags & D_DISABLED) ? gui_mg_color : d->fg; + text_mode(d->bg); + gui_textout + (screen, + d->dp,d->x+d->h+text_height(font), + d->y+(d->h-(text_height(font)-gui_font_baseline))/2,fg,FALSE); + + x = d->x; + + Rect3D(x,d->y,d->h,d->h,TRUE,SMALL_BEVEL); + rectfill(screen,x+SMALL_BEVEL,d->y+SMALL_BEVEL, + x+d->h-SMALL_BEVEL*2,d->y+d->h-SMALL_BEVEL*2, + ACOL(WHITE)); + + if (d->flags & D_SELECTED) + { + rectfill(screen,x+SMALL_BEVEL+2,d->y+SMALL_BEVEL+2, + x+d->h-SMALL_BEVEL*2-2, + d->y+d->h-SMALL_BEVEL*2-2, + ACOL(BLACK)); + } + + break; + + default: + return(d_radio_proc(msg,d,c)); + break; + } + + return(D_O_K); +} + + +static int my_d_list_proc(int msg, DIALOG *d, int c) +{ + switch(msg) + { + case MSG_DRAW: + DrawListbox(d); + break; + + default: + return(d_list_proc(msg,d,c)); + break; + } + + return (D_O_K); +} + + +static int my_d_button_proc(int msg, DIALOG *d, int c) +{ + int inv; + + switch(msg) + { + case MSG_DRAW: + if (d->flags&D_SELECTED) + inv=TRUE; + else + inv=FALSE; + + Rect3D(d->x,d->y,d->w,d->h,inv,BEVEL); + text_mode(-1); + gui_textout(screen,d->dp,d->x+(d->w/2), + d->y+d->h/2-GFX_fh()/2,d->fg,TRUE); + + break; + + default: + return(d_button_proc(msg,d,c)); + break; + } + + return (D_O_K); +} + + +/* ---------------------------------------- FILE SELECTION CODE + + This code is a copy of the file selector code provided by Shawn Hargreaves + in his Allegro library (original filename fsel.c). The only changes are + to the file_selector[] DIALOG structure and some of the fs_*_proc() + callbacks to use my 3D buttons, etc. + + Shawn Hargreaves can be contacted at: + + http://www.talula.demon.co.uk/allegro/ + shawn@talula.demon.co.uk + + If this code causes problems, blame me, not Shawn! +*/ + + +#ifndef _USE_LFN +#define _USE_LFN 0 +#endif + +static int fs_edit_proc(int, DIALOG *, int ); +static int fs_flist_proc(int, DIALOG *, int ); +static int fs_dlist_proc(int, DIALOG *, int ); +static char *fs_flist_getter(int, int *); +static char *fs_dlist_getter(int, int *); + + +#define FLIST_SIZE 2048 + +typedef struct FLIST +{ + char dir[80]; + int size; + char *name[FLIST_SIZE]; +} FLIST; + +static FLIST *flist = NULL; + +static char *fext = NULL; + + + +static DIALOG file_selector[] = +{ + /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) */ + { d_3d_box, 0, 0, 304, 160, 0, 0, 0, 0, 0, 0, NULL }, + { d_inv_3d_box, 14, 26, 276, 12, 0, 0, 0, 0, 0, 0, NULL }, + { d_ctext_proc, 152, 8, 1, 1, 0, 0, 0, 0, 0, 0, NULL }, + { my_d_button_proc, 208, 107, 80, 16, 0, 0, 0, D_EXIT, 0, 0, "OK" }, + { my_d_button_proc, 208, 129, 80, 16, 0, 0, 27, D_EXIT, 0, 0, "Cancel" }, + { fs_edit_proc, 16, 28, 272, 8, 0, 0, 0, 0, 79, 0, NULL }, + { fs_flist_proc, 16, 46, 176, 99, 0, 0, 0, D_EXIT, 0, 0, fs_flist_getter }, + { fs_dlist_proc, 208, 46, 80, 51, 0, 0, 0, D_EXIT, 0, 0, fs_dlist_getter }, + { NULL } +}; + +#define FS_MESSAGE 2 +#define FS_OK 3 +#define FS_CANCEL 4 +#define FS_EDIT 5 +#define FS_FILES 6 +#define FS_DISKS 7 + + + +/* fs_dlist_getter: + * Listbox data getter routine for the file selector disk list. + */ +static char *fs_dlist_getter(int index, int *list_size) +{ + static char d[] = "A:\\"; + + if (index < 0) { + if (list_size) + *list_size = 26; + return NULL; + } + + d[0] = 'A' + index; + return d; +} + + + +/* fs_dlist_proc: + * Dialog procedure for the file selector disk list. + */ +static int fs_dlist_proc(int msg, DIALOG *d, int c) +{ + int ret; + char *s = file_selector[FS_EDIT].dp; + + if (msg == MSG_START) + d->d1 = d->d2 = 0; + + ret = my_d_list_proc(msg, d, c); + + if (ret == D_CLOSE) { + *(s++) = 'A' + d->d1; + *(s++) = ':'; + *(s++) = '\\'; + *s = 0; + show_mouse(NULL); + SEND_MESSAGE(file_selector+FS_FILES, MSG_START, 0); + SEND_MESSAGE(file_selector+FS_FILES, MSG_DRAW, 0); + SEND_MESSAGE(file_selector+FS_EDIT, MSG_START, 0); + SEND_MESSAGE(file_selector+FS_EDIT, MSG_DRAW, 0); + show_mouse(screen); + return D_O_K; + } + + return ret; +} + + + +/* fs_edit_proc: + * Dialog procedure for the file selector editable string. + */ +static int fs_edit_proc(int msg, DIALOG *d, int c) +{ + char *s = d->dp; + int ch; + int attr; + int x; + char b[80]; + + if (msg == MSG_START) { + if (s[0]) { + _fixpath(s, b); + errno = 0; + + x = s[strlen(s)-1]; + if ((x=='/') || (x=='\\')) + put_backslash(b); + + for (x=0; b[x]; x++) { + if (b[x] == '/') + s[x] = '\\'; + else + s[x] = toupper(b[x]); + } + s[x] = 0; + } + } + + if (msg == MSG_KEY) { + if (*s) + ch = s[strlen(s)-1]; + else + ch = 0; + if (ch == ':') + put_backslash(s); + else { + if ((ch != '/') && (ch != '\\')) { + if (file_exists(s, FA_RDONLY | FA_HIDDEN | FA_DIREC, &attr)) { + if (attr & FA_DIREC) + put_backslash(s); + else + return D_CLOSE; + } + else + return D_CLOSE; + } + } + show_mouse(NULL); + SEND_MESSAGE(file_selector+FS_FILES, MSG_START, 0); + SEND_MESSAGE(file_selector+FS_FILES, MSG_DRAW, 0); + SEND_MESSAGE(d, MSG_START, 0); + SEND_MESSAGE(d, MSG_DRAW, 0); + show_mouse(screen); + return D_O_K; + } + + if (msg==MSG_CHAR) { + ch = c & 0xff; + if ((ch >= 'a') && (ch <= 'z')) + c = (c & 0xffffff00L) | (ch - 'a' + 'A'); + else if (ch == '/') + c = (c & 0xffffff00L) | '\\'; + else if (_USE_LFN) { + if ((ch > 127) || ((ch < 32) && (ch != 8) && (ch != 0))) + return D_O_K; + } + else { + if ((ch != '\\') && (ch != '_') && (ch != ':') && (ch != '.') && + ((ch < 'A') || (ch > 'Z')) && ((ch < '0') || (ch > '9')) && + (ch != 8) && (ch != 127) && (ch != 0)) + return D_O_K; + } + } + + return d_edit_proc(msg, d, c); +} + + + +/* fs_flist_putter: + * Callback routine for for_each_file() to fill the file selector listbox. + */ +static void fs_flist_putter(char *str, int attrib) +{ + int c, c2; + char *s, *ext, *tok; + char tmp[80]; + static char ext_tokens[] = " ,;"; + + s = get_filename(str); + strupr(s); + + if ((fext) && (!(attrib & FA_DIREC))) { + strcpy(tmp, fext); + ext = get_extension(s); + tok = strtok(tmp, ext_tokens); + while (tok) { + if (stricmp(ext, tok) == 0) + break; + tok = strtok(NULL, ext_tokens); + } + if (!tok) + return; + } + + if ((flist->size < FLIST_SIZE) && (strcmp(s,".") != 0)) { + for (c=0; c<flist->size; 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; i<flist->size; i++) + if (flist->name[i]) + free(flist->name[i]); + } + if (!flist) { + errno = ENOMEM; + return D_CLOSE; + } + flist->size = 0; + for (i=0; i<flist->size; 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; i<flist->size; i++) + if (flist->name[i]) + free(flist->name[i]); + free(flist); + } + flist = NULL; + } + + recurse_flag++; + ret = my_d_list_proc(msg,d,c); /* call the parent procedure */ + recurse_flag--; + + if (((sel != d->d1) || (ret == D_CLOSE)) && (recurse_flag == 0)) { + strcpy(s, flist->dir); + *get_filename(s) = 0; + put_backslash(s); + strcat(s, flist->name[d->d1]); + show_mouse(NULL); + SEND_MESSAGE(file_selector+FS_EDIT, MSG_START, 0); + SEND_MESSAGE(file_selector+FS_EDIT, MSG_DRAW, 0); + show_mouse(screen); + + if (ret == D_CLOSE) + return SEND_MESSAGE(file_selector+FS_EDIT, MSG_KEY, 0); + } + + return ret; +} + + + +/* my_file_select: + * Displays the Allegro file selector, with the message as caption. + * Allows the user to select a file, and stores the selection in path + * (which should have room for at least 80 characters). The files are + * filtered according to the file extensions in ext. Passing NULL + * includes all files, "PCX;BMP" includes only files with .PCX or .BMP + * extensions. Returns zero if it was closed with the Cancel button, + * non-zero if it was OK'd. + */ +int my_file_select(char *message, char *path, char *ext) +{ + int ret; + char *p; + int f; + + f=0; + while(file_selector[f].proc) + { + switch(f) + { + case FS_EDIT: + case FS_FILES: + case FS_DISKS: + file_selector[f].fg=ACOL(BLACK); + file_selector[f].bg=ACOL(WHITE); + break; + + default: + file_selector[f].fg=gui_fg_color; + file_selector[f].bg=gui_bg_color; + break; + } + + f++; + } + + file_selector[FS_MESSAGE].dp = message; + file_selector[FS_EDIT].dp = path; + fext = ext; + + if (!path[0]) { + getcwd(path, 80); + for (p=path; *p; p++) + if (*p=='/') + *p = '\\'; + else + *p = toupper(*p); + + put_backslash(path); + } + + clear_keybuf(); + + do { + } while (mouse_b); + + centre_dialog(file_selector); + ret = do_dialog(file_selector, FS_EDIT); + + if ((ret == FS_CANCEL) || (*get_filename(path) == 0)) + return FALSE; + + p = get_extension(path); + if ((*p == 0) && (ext) && (!strpbrk(ext, " ,;"))) { + *p = '.'; + strcpy(p+1, ext); + } + + return TRUE; +} + + +/* ---------------------------------------- GUI MENU SUPPORT FUNCS +*/ +static void DrawMenuItem(BoundBox *b,char *txt,int sel) +{ + int fg; + + fg=ACOL(GUI_TEXT); + + if (sel) + Rect3D(b->x,b->y,b->w,b->h,FALSE,SMALL_BEVEL); + else + rectfill(screen,b->x,b->y,b->x+b->w-1,b->y+b->h-1,ACOL(GUI_MID)); + + text_mode(-1); + textout(screen,font,txt,b->x+SMALL_BEVEL+2,b->y+b->h/2-GFX_fh()/2,fg); +} + + +static int MouseInBox(BoundBox *box,int no) +{ + int f; + + for(f=0;f<no;f++) + if (((mouse_x>=box[f].x)&&(mouse_x<box[f].x+box[f].w))&& + ((mouse_y>=box[f].y)&&(mouse_y<box[f].y+box[f].h))) + return(f); + + return(-1); +} + + +/* ---------------------------------------- CALLBACK AND HANDLER FUNCTIONS +*/ +static char *picklist_cb(int index,int *size) +{ + if (index<0) + { + *size=pick_no; + return(NULL); + } + else + return(pick_data[index]); +} + + +static char *img_picklist_cb(int index,int *size) +{ + if (index<0) + { + *size=img_pick_no; + return(NULL); + } + else + return(img_pick_data[index].text); +} + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void init_picklist_dialog(char *title,int width) +{ + static int done=FALSE; + + width+=15; + + picklist[PL_BORDER].x=SCRW/2-width/2-20; + picklist[PL_BORDER].w=width+40; + + picklist[PL_TITLE].w=width+30; + picklist[PL_TITLE].dp=title; + + picklist[PL_PICKLIST].x=SCRW/2-width/2-10; + picklist[PL_PICKLIST].w=width+20; + picklist[PL_PICKLIST].d1=0; + picklist[PL_PICKLIST].d2=0; + + if (done) + return; + + done=TRUE; + + /* Box + */ + picklist[PL_BORDER].proc=d_3d_box; + picklist[PL_BORDER].y=10; + picklist[PL_BORDER].h=SCRH-20; + picklist[PL_BORDER].fg=ACOL(GUI_TEXT); + picklist[PL_BORDER].bg=ACOL(GUI_MID); + picklist[PL_BORDER].key=0; + picklist[PL_BORDER].flags=0; + picklist[PL_BORDER].d1=picklist[PL_BORDER].d2=0; + picklist[PL_BORDER].dp=picklist[PL_BORDER].dp2=picklist[PL_BORDER].dp3=NULL; + + /* Title + */ + picklist[PL_TITLE].proc=d_ctext_proc; + picklist[PL_TITLE].x=SCRW/2; + picklist[PL_TITLE].y=20; + picklist[PL_TITLE].h=10; + picklist[PL_TITLE].fg=ACOL(GUI_TEXTBOLD); + picklist[PL_TITLE].bg=ACOL(GUI_MID); + picklist[PL_TITLE].key=0; + picklist[PL_TITLE].flags=0; + picklist[PL_TITLE].d1=picklist[PL_TITLE].d2=0; + picklist[PL_TITLE].dp2=picklist[PL_TITLE].dp3=NULL; + + /* List + */ + picklist[PL_PICKLIST].proc=my_d_list_proc; + picklist[PL_PICKLIST].y=30; + picklist[PL_PICKLIST].h=SCRH-60; + picklist[PL_PICKLIST].fg=ACOL(BLACK); + picklist[PL_PICKLIST].bg=ACOL(WHITE); + picklist[PL_PICKLIST].key=0; + picklist[PL_PICKLIST].flags=D_EXIT; + picklist[PL_PICKLIST].dp=picklist_cb; + picklist[PL_PICKLIST].dp2=picklist[PL_PICKLIST].dp3=NULL; + + memset(&picklist[PL_END],0,sizeof(DIALOG)); + picklist[PL_END].proc=NULL; +} + + +static void init_img_picklist_dialog(char *title) +{ + static int done=FALSE; + + img_picklist[IPL_TITLE].dp=title; + + img_picklist[IPL_PICKLIST].d1=0; + img_picklist[IPL_PICKLIST].d2=0; + + img_picklist[IPL_IMAGE].dp=img_pick_data[0].img; + + if (done) + return; + + done=TRUE; + + /* Box + */ + img_picklist[IPL_BORDER].proc=d_3d_box; + img_picklist[IPL_BORDER].y=10; + img_picklist[IPL_BORDER].h=SCRH-20; + img_picklist[IPL_BORDER].x=10; + img_picklist[IPL_BORDER].w=SCRW-20; + img_picklist[IPL_BORDER].fg=ACOL(GUI_TEXT); + img_picklist[IPL_BORDER].bg=ACOL(GUI_MID); + img_picklist[IPL_BORDER].key=0; + img_picklist[IPL_BORDER].flags=0; + img_picklist[IPL_BORDER].d1=img_picklist[IPL_BORDER].d2=0; + img_picklist[IPL_BORDER].dp=img_picklist[IPL_BORDER].dp2= + img_picklist[IPL_BORDER].dp3=NULL; + + /* Title + */ + img_picklist[IPL_TITLE].proc=d_ctext_proc; + img_picklist[IPL_TITLE].x=SCRW/2; + img_picklist[IPL_TITLE].w=SCRW-20; + img_picklist[IPL_TITLE].y=20; + img_picklist[IPL_TITLE].h=10; + img_picklist[IPL_TITLE].fg=ACOL(GUI_TEXTBOLD); + img_picklist[IPL_TITLE].bg=ACOL(GUI_MID); + img_picklist[IPL_TITLE].key=0; + img_picklist[IPL_TITLE].flags=0; + img_picklist[IPL_TITLE].d1=img_picklist[IPL_TITLE].d2=0; + img_picklist[IPL_TITLE].dp2=img_picklist[IPL_TITLE].dp3=NULL; + + /* List + */ + img_picklist[IPL_PICKLIST].proc=d_img_list_proc; + img_picklist[IPL_PICKLIST].y=30; + img_picklist[IPL_PICKLIST].h=SCRH-60; + img_picklist[IPL_PICKLIST].x=30; + img_picklist[IPL_PICKLIST].w=SCRW/2; + img_picklist[IPL_PICKLIST].fg=ACOL(BLACK); + img_picklist[IPL_PICKLIST].bg=ACOL(WHITE); + img_picklist[IPL_PICKLIST].key=0; + img_picklist[IPL_PICKLIST].flags=D_EXIT; + img_picklist[IPL_PICKLIST].dp=img_picklist_cb; + img_picklist[IPL_PICKLIST].dp2=img_picklist[IPL_PICKLIST].dp3=NULL; + + /* Image border + */ + img_picklist[IPL_IMG_BORDER].proc=d_inv_3d_box; + img_picklist[IPL_IMG_BORDER].y=30; + img_picklist[IPL_IMG_BORDER].h=MAX_GFXBM_H+4; + img_picklist[IPL_IMG_BORDER].x=SCRW-MAX_GFXBM_W-24; + img_picklist[IPL_IMG_BORDER].w=MAX_GFXBM_W+4; + img_picklist[IPL_IMG_BORDER].fg=ACOL(WHITE); + img_picklist[IPL_IMG_BORDER].bg=ACOL(BLACK); + img_picklist[IPL_IMG_BORDER].key=0; + img_picklist[IPL_IMG_BORDER].flags=0; + img_picklist[IPL_IMG_BORDER].dp=img_picklist[IPL_IMG_BORDER].dp2= + img_picklist[IPL_IMG_BORDER].dp3=NULL; + img_picklist[IPL_IMG_BORDER].d1=img_picklist[IPL_IMG_BORDER].d2=0; + + /* Image + */ + img_picklist[IPL_IMAGE].proc=d_img_bmap_proc; + img_picklist[IPL_IMAGE].x=SCRW-MAX_GFXBM_W-22; + img_picklist[IPL_IMAGE].y=32; + img_picklist[IPL_IMAGE].w=MAX_GFXBM_W; + img_picklist[IPL_IMAGE].h=MAX_GFXBM_H; + img_picklist[IPL_IMAGE].fg=ACOL(0); + img_picklist[IPL_IMAGE].bg=ACOL(0); + img_picklist[IPL_IMAGE].key=0; + img_picklist[IPL_IMAGE].flags=0; + img_picklist[IPL_IMAGE].dp2=img_picklist[IPL_IMAGE].dp3=NULL; + img_picklist[IPL_IMAGE].d1=img_picklist[IPL_IMAGE].d2=0; + + memset(&img_picklist[IPL_END],0,sizeof(DIALOG)); + img_picklist[IPL_END].proc=NULL; +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +void GUI_setscreen(int w,int h) +{ + gui_fg_color=ACOL(GUI_TEXT); + gui_bg_color=ACOL(GUI_MID); + + /* Disabled objects are used for bold text + */ + gui_mg_color=ACOL(GUI_TEXTBOLD); + + SCRW=w; + SCRH=h; +} + + +int GUI_yesno(char *question) +{ + extern void GFX_FORCE_REDRAW(void); + DIALOG *d; + int ml; + int h; + int ret; + int x,y; + + d=Grab(sizeof(DIALOG)*5); + + h=(GFX_fh()+10)*3; + ml=text_length(font,question)+GFX_fw()*2; + + 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; + + /* Question + */ + d[1].proc=d_ctext_proc; + d[1].x=SCRW/2; + d[1].w=ml-20; + d[1].y=y+BEVEL+GFX_fh(); + d[1].h=10; + d[1].fg=ACOL(GUI_TEXT); + d[1].bg=ACOL(GUI_MID); + d[1].key=0; + d[1].flags=0; + d[1].d1=d[1].d2=0; + d[1].dp=question; + d[1].dp2=d[1].dp3=NULL; + + /* YES + */ + d[2].proc=my_d_button_proc; + d[2].x=x+10; + d[2].w=(ml/2)-20; + d[2].h=GFX_fh()+3+BEVEL; + d[2].y=y+h-d[2].h-5-BEVEL; + d[2].fg=ACOL(GUI_TEXT); + d[2].bg=ACOL(GUI_MID); + d[2].key='Y'; + d[2].flags=D_EXIT; + d[2].d1=d[2].d2=0; + d[2].dp="&Yes"; + d[2].dp2=d[2].dp3=NULL; + + /* NO + */ + 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='N'; + d[3].flags=D_EXIT; + d[3].d1=d[3].d2=0; + d[3].dp="&No"; + d[3].dp2=d[3].dp3=NULL; + + d[4].proc=NULL; + + GFX_bounce(); + + if(do_dialog(d,-1)==2) + ret=TRUE; + else + ret=FALSE; + + GFX_FORCE_REDRAW(); + Release(d); + + return(ret); +} + + +int GUI_menu(char *title, int x, int y, PLAT_MENU menu[],int defval) +{ + int lx,ly; + int no; + int f; + int h; + int w; + BITMAP *under; + int cur; + int cx; + int by; + int done; + int quit; + BoundBox *box; + + /* Calc dimensions + */ + no=0; + w=text_length(font,title); + + while(menu[no].text) + { + w=MAX(w,text_length(font,menu[no].text)); + no++; + } + + h=BEVEL*2+GFX_fh()+4; + + for(f=0;f<no;f++) + h+=GFX_fh()+SMALL_BEVEL*2+2; + + h+=2; + w+=BEVEL+SMALL_BEVEL+4; + + box=Grab(sizeof(BoundBox)*no); + + if ((x+w)>SCRW) + x=SCRW-w; + + if ((y+h)>SCRH) + y=SCRH-h; + + if ((x<0)||(y<0)) + { + alert("Cannot display menu:",title,"Menu is bigger than display!", + "OK",NULL,0,0); + + return(defval); + } + + cx=x+w/2; + + cur=0; + + /* Save screen contents + */ + show_mouse(NULL); + + if (!(under=create_bitmap(w+1,h+1))) + GFX_exit(EXIT_FAILURE,"No more memory to create MENU save under\n"); + + blit(screen,under,x,y,0,0,w+1,h+1); + + /* Draw menu border and title + */ + Rect3D(x,y,w,h,FALSE,BEVEL); + text_mode(-1); + textout_centre(screen,font,title,cx,y+BEVEL*2,ACOL(GUI_TEXTBOLD)); + + /* Draw menu items + */ + by=y+BEVEL*2+GFX_fh()+4; + + for(f=0;f<no;f++) + { + box[f].x=x+BEVEL; + box[f].y=by; + box[f].w=w-BEVEL*2; + box[f].h=GFX_fh()+SMALL_BEVEL*2+2; + by+=box[f].h; + + DrawMenuItem(&box[f],menu[f].text,(f==cur)); + } + + show_mouse(screen); + GFX_bounce(); + + /* Main loop + */ + quit=FALSE; + done=FALSE; + lx=mouse_x; + ly=mouse_y; + + while((!done)&&(!quit)) + { + if (mouse_b) + { + int new; + + new=MouseInBox(box,no); + + if (new==-1) + { + quit=TRUE; + + while(mouse_b); + } + else + { + done=TRUE; + cur=new; + while(mouse_b); + } + } + else + if (keypressed()) + switch(readkey()>>8) + { + case KEY_ESC: + quit=TRUE; + break; + + case KEY_ENTER: + done=TRUE; + break; + + case KEY_DOWN: + show_mouse(NULL); + DrawMenuItem(&box[cur],menu[cur].text,FALSE); + + cur=(cur+1)%no; + + DrawMenuItem(&box[cur],menu[cur].text,TRUE); + show_mouse(screen); + break; + + case KEY_UP: + show_mouse(NULL); + DrawMenuItem(&box[cur],menu[cur].text,FALSE); + + if (cur) + cur--; + else + cur=no-1; + + DrawMenuItem(&box[cur],menu[cur].text,TRUE); + show_mouse(screen); + break; + } + else + if ((lx!=mouse_x)||(ly!=mouse_y)) + { + int new; + + lx=mouse_x; + ly=mouse_y; + + new=MouseInBox(box,no); + + if ((new!=-1)&&(new!=cur)) + { + show_mouse(NULL); + DrawMenuItem(&box[cur],menu[cur].text,FALSE); + cur=new; + DrawMenuItem(&box[cur],menu[cur].text,TRUE); + show_mouse(screen); + } + } + } + + show_mouse(NULL); + blit(under,screen,0,0,x,y,w+1,h+1); + show_mouse(screen); + destroy_bitmap(under); + Release(box); + + if (!quit) + no=menu[cur].client_index; + else + no=defval; + + return(no); +} + + +char *GUI_fsel(char *title, char *default_path, char *filter) +{ + char path[PATH_MAX+1]; + + if ((filter)&&(*filter=='.')) + filter++; + + strcpy(path,default_path); + + GFX_bounce(); + if (my_file_select(title,path,filter)) + return(Strdup(path)); + + return(NULL); +} + + +int GUI_picklist(char *title,char *opt[]) +{ + extern void GFX_FORCE_REDRAW(void); + int ml; + int ret; + + pick_no=0; + + ml=gui_strlen(title); + + while(opt[pick_no]) + { + if (gui_strlen(opt[pick_no])>ml) + ml=gui_strlen(opt[pick_no]); + pick_no++; + } + + pick_data=opt; + + init_picklist_dialog(title,ml); + + GFX_bounce(); + ret=do_dialog(picklist,-1); + GFX_FORCE_REDRAW(); + + if (ret==-1) + return(-1); + + return(picklist[IPL_PICKLIST].d1); +} + + +int GUI_client_picklist(char *title,PLAT_PICKLIST opt[],int defval) +{ + extern void GFX_FORCE_REDRAW(void); + int ml; + int ret; + char **c_opt; + int f; + + pick_no=0; + + ml=gui_strlen(title); + + while(opt[pick_no].text) + { + if (gui_strlen(opt[pick_no].text)>ml) + ml=gui_strlen(opt[pick_no].text); + pick_no++; + } + + c_opt=Grab(sizeof(char *)*(pick_no+1)); + + for(f=0;f<pick_no;f++) + c_opt[f]=opt[f].text; + + c_opt[f]=NULL; + + pick_data=c_opt; + + init_picklist_dialog(title,ml); + + GFX_bounce(); + ret=do_dialog(picklist,-1); + GFX_FORCE_REDRAW(); + Release(c_opt); + + if (ret==-1) + return(defval); + + return(opt[picklist[IPL_PICKLIST].d1].client_index); +} + + +int GUI_image_picklist(char *title,PLAT_IMG_PICKLIST opt[],int defval) +{ + extern void GFX_FORCE_REDRAW(void); + int ret; + + img_pick_no=0; + while(opt[img_pick_no].text) + img_pick_no++; + + img_pick_data=opt; + + init_img_picklist_dialog(title); + + GFX_bounce(); + ret=do_dialog(img_picklist,-1); + GFX_FORCE_REDRAW(); + + if (ret==-1) + return(defval); + + return(opt[img_picklist[IPL_PICKLIST].d1].client_index); +} + + +int GUI_radio_box(char *title,PLAT_RADIO opt[],int current,int defval) +{ + int no; + DIALOG *d; + int ml,l; + int h; + int f; + int ret; + int x,y; + + no=0; + while(opt[no].text) + no++; + + d=Grab(sizeof(DIALOG)*(no+6)); + + h=(GFX_fh()+5)*no; + ml=text_length(font,"CANCEL CANCEL"); + + for(f=0;f<no;f++) + if ((l=text_length(font,opt[f].text))>ml) + ml=l; + + h+=GFX_fh()*4; + ml+=GFX_fw()*4; + x=SCRW/2-ml/2; + y=SCRH/2-h/2; + + /* Surrounding box + */ + d[0].proc=d_3d_box; + d[0].x=x; + d[0].y=y; + d[0].w=ml; + d[0].h=h; + d[0].fg=ACOL(GUI_TEXT); + d[0].bg=ACOL(GUI_MID); + d[0].key=0; + d[0].flags=0; + d[0].d1=d[0].d2=0; + d[0].dp=d[0].dp2=d[0].dp3=NULL; + + /* Title + */ + d[1].proc=d_ctext_proc; + d[1].x=SCRW/2; + d[1].w=ml-20; + d[1].y=y+10; + d[1].h=10; + d[1].fg=ACOL(GUI_TEXTBOLD); + d[1].bg=ACOL(GUI_MID); + d[1].key=0; + d[1].flags=0; + d[1].d1=d[1].d2=0; + d[1].dp=title; + d[1].dp2=d[1].dp3=NULL; + + /* OK + */ + d[2].proc=my_d_button_proc; + d[2].x=x+10; + d[2].y=y+h-15; + d[2].w=(ml/2)-20; + d[2].h=10+BEVEL; + d[2].fg=ACOL(GUI_TEXT); + d[2].bg=ACOL(GUI_MID); + d[2].key=0; + d[2].flags=D_EXIT; + d[2].d1=d[2].d2=0; + d[2].dp="OK"; + d[2].dp2=d[2].dp3=NULL; + + /* CANCEL + */ + d[3].proc=my_d_button_proc; + d[3].x=SCRW/2+10; + d[3].y=y+h-15; + d[3].w=(ml/2)-20; + d[3].h=10+BEVEL; + d[3].fg=ACOL(GUI_TEXT); + d[3].bg=ACOL(GUI_MID); + d[3].key=0; + d[3].flags=D_EXIT; + d[3].d1=d[3].d2=0; + d[3].dp="Cancel"; + d[3].dp2=d[3].dp3=NULL; + + /* Buttons + */ + for(f=0;f<no;f++) + { + d[4+f].proc=my_d_radio_proc; + d[4+f].x=x+10; + d[4+f].y=y+20+f*10; + d[4+f].w=ml-20; + d[4+f].h=10; + d[4+f].fg=ACOL(GUI_TEXT); + d[4+f].bg=ACOL(GUI_MID); + d[4+f].key=0; + d[4+f].flags=(f==0 ? D_SELECTED : 0); + d[4+f].d1=d[4+f].d2=0; + d[4+f].dp=opt[f].text; + d[4+f].dp2=d[4+f].dp3=NULL; + } + + d[4+no].proc=NULL; + + for(f=0;f<no;f++) + if (opt[f].client_index==current) + { + d[4].flags=0; + d[4+f].flags=D_SELECTED; + } + + ret=defval; + + GFX_bounce(); + if(do_dialog(d,-1)==2) + for(f=0;f<no;f++) + if (d[4+f].flags&D_SELECTED) + ret=opt[f].client_index; + + Release(d); + + return(ret); +} + + +int GUI_multi_box(char *title,char *opt[],int *val) +{ + extern void GFX_FORCE_REDRAW(void); + int no; + DIALOG *d; + int ml,l; + int h; + int f; + int ret; + int x,y; + + no=0; + while(opt[no]) + no++; + + d=Grab(sizeof(DIALOG)*(no+6)); + + h=(GFX_fh()+5)*no; + ml=text_length(font,"CANCEL CANCEL"); + + for(f=0;f<no;f++) + if ((l=text_length(font,opt[f]))>ml) + ml=l; + + h+=GFX_fh()*4; + ml+=GFX_fw()*4; + x=SCRW/2-ml/2; + y=SCRH/2-h/2; + + /* Surrounding box + */ + d[0].proc=d_3d_box; + d[0].x=x; + d[0].y=y; + d[0].w=ml; + d[0].h=h; + d[0].fg=ACOL(GUI_TEXT); + d[0].bg=ACOL(GUI_MID); + d[0].key=0; + d[0].flags=0; + d[0].d1=d[0].d2=0; + d[0].dp=d[0].dp2=d[0].dp3=NULL; + + /* Title + */ + d[1].proc=d_ctext_proc; + d[1].x=SCRW/2; + d[1].w=ml-20; + d[1].y=y+10; + d[1].h=10; + d[1].fg=ACOL(GUI_TEXTBOLD); + d[1].bg=ACOL(GUI_MID); + d[1].key=0; + d[1].flags=0; + d[1].d1=d[1].d2=0; + d[1].dp=title; + d[1].dp2=d[1].dp3=NULL; + + /* OK + */ + d[2].proc=my_d_button_proc; + d[2].x=x+10; + d[2].y=y+h-15; + d[2].w=(ml/2)-20; + d[2].h=10+BEVEL; + d[2].fg=ACOL(GUI_TEXT); + d[2].bg=ACOL(GUI_MID); + d[2].key=0; + d[2].flags=D_EXIT; + d[2].d1=d[2].d2=0; + d[2].dp="OK"; + d[2].dp2=d[2].dp3=NULL; + + /* CANCEL + */ + d[3].proc=my_d_button_proc; + d[3].x=SCRW/2+10; + d[3].y=y+h-15; + d[3].w=(ml/2)-20; + d[3].h=10+BEVEL; + d[3].fg=ACOL(GUI_TEXT); + d[3].bg=ACOL(GUI_MID); + d[3].key=0; + d[3].flags=D_EXIT; + d[3].d1=d[3].d2=0; + d[3].dp="Cancel"; + d[3].dp2=d[3].dp3=NULL; + + /* Buttons + */ + for(f=0;f<no;f++) + { + d[4+f].proc=my_d_check_proc; + d[4+f].x=x+10; + d[4+f].y=y+20+f*10; + d[4+f].w=ml-20; + d[4+f].h=10; + d[4+f].fg=ACOL(GUI_TEXT); + d[4+f].bg=ACOL(GUI_MID); + d[4+f].key=0; + + if ((*val)&(1<<f)) + d[4+f].flags=D_SELECTED; + else + d[4+f].flags=0; + + d[4+f].d1=f; + d[4+f].d2=0; + d[4+f].dp=opt[f]; + d[4+f].dp2=d[4+f].dp3=NULL; + } + + d[4+no].proc=NULL; + + GFX_bounce(); + if(do_dialog(d,-1)==2) + { + *val=0; + + for(f=0;f<no;f++) + if (d[4+f].flags&D_SELECTED) + *val|=(1<<f); + + ret=TRUE; + } + else + ret=FALSE; + + GFX_FORCE_REDRAW(); + Release(d); + + return(ret); +} + + +int GUI_dialog(char *title, int no, PLAT_DIALOG pd[]) +{ + extern void GFX_FORCE_REDRAW(void); + DIALOG *d; + int ml,l; + int h; + int f; + int ret; + int x,y; + char *p; + int tmp; + double d_tmp; + + d=Grab(sizeof(DIALOG)*(no*3+6)); + + h=(GFX_fh()+10)*no; + ml=0; + + for(f=0;f<no;f++) + if ((pd[f].text)&&((l=text_length(font,pd[f].text))>ml)) + ml=l; + + ml+=text_length(font," ")*(DIALOG_STRLEN+3); + + h+=GFX_fh()*5; + x=SCRW/2-ml/2; + y=SCRH/2-h/2; + + /* Surrounding box + */ + d[0].proc=d_3d_box; + d[0].x=x; + d[0].y=y; + d[0].w=ml; + d[0].h=h; + d[0].fg=ACOL(GUI_TEXT); + d[0].bg=ACOL(GUI_MID); + d[0].key=0; + d[0].flags=0; + d[0].d1=d[0].d2=0; + d[0].dp=d[0].dp2=d[0].dp3=NULL; + + /* Title + */ + d[1].proc=d_ctext_proc; + d[1].x=SCRW/2; + d[1].w=ml-20; + d[1].y=y+3; + d[1].h=10; + d[1].fg=ACOL(GUI_TEXTBOLD); + d[1].bg=ACOL(GUI_MID); + d[1].key=0; + d[1].flags=0; + d[1].d1=d[1].d2=0; + d[1].dp=title; + d[1].dp2=d[1].dp3=NULL; + + /* OK + */ + d[2].proc=my_d_button_proc; + d[2].x=x+10; + d[2].w=(ml/2)-20; + d[2].h=GFX_fh()+3+BEVEL; + d[2].y=y+h-d[2].h-5-BEVEL; + d[2].fg=ACOL(GUI_TEXT); + d[2].bg=ACOL(GUI_MID); + d[2].key=0; + d[2].flags=D_EXIT; + d[2].d1=d[2].d2=0; + d[2].dp="OK"; + d[2].dp2=d[2].dp3=NULL; + + /* CANCEL + */ + d[3].proc=my_d_button_proc; + d[3].x=SCRW/2+10; + d[3].y=d[2].y; + d[3].w=(ml/2)-20; + d[3].h=d[2].h; + d[3].fg=ACOL(GUI_TEXT); + d[3].bg=ACOL(GUI_MID); + d[3].key=0; + d[3].flags=D_EXIT; + d[3].d1=d[3].d2=0; + d[3].dp="Cancel"; + d[3].dp2=d[3].dp3=NULL; + + /* Labels and text entries + */ + for(f=0;f<no;f++) + { + if (pd[f].text) + p=pd[f].text; + else + p=""; + + d[4+(f*3)].proc=d_text_proc; + d[4+(f*3)].x=x+10; + d[4+(f*3)].y=y+23+f*15; + d[4+(f*3)].w=text_length(font,p); + d[4+(f*3)].h=10; + d[4+(f*3)].fg=ACOL(GUI_TEXT); + d[4+(f*3)].bg=ACOL(GUI_MID); + d[4+(f*3)].key=0; + d[4+(f*3)].flags=0; + d[4+(f*3)].d1=0; + d[4+(f*3)].d2=0; + d[4+(f*3)].dp=p; + d[4+(f*3)].dp2=d[4+(f*3)].dp3=NULL; + + 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=x+ml-text_length(font," ")*DIALOG_STRLEN-9-BEVEL; + 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=x+ml-text_length(font," ")*DIALOG_STRLEN-9; + 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*4)].proc=NULL; + + GFX_bounce(); + if(do_dialog(d,-1)==2) + { + for(f=0;f<no;f++) + { + if (pd[f].type==PLAT_DIAL_INTEGER) + { + tmp=(int)strtol(pd[f].data.s,NULL,0); + pd[f].data.i=tmp; + } + else if (pd[f].type==PLAT_DIAL_DOUBLE) + { + d_tmp=strtod(pd[f].data.s,NULL); + pd[f].data.d=d_tmp; + } + } + + ret=TRUE; + } + else + ret=FALSE; + + GFX_FORCE_REDRAW(); + Release(d); + + return(ret); +} + + +/* END OF FILE */ diff --git a/djgpp/runcmd.c b/djgpp/runcmd.c new file mode 100644 index 0000000..66d56ba --- /dev/null +++ b/djgpp/runcmd.c @@ -0,0 +1,61 @@ +/* + + 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 + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include <unistd.h> +#include <string.h> +#include <stdio.h> + +int RunCommand(char *argv[], char *path) +{ + char cmd[PATH_MAX*2]; + int ret; + int f; + + tmpnam(path); + + f=0; + cmd[0]=0; + while(argv[f]) + { + strcat(cmd,argv[f]); + strcat(cmd," "); + f++; + } + + strcat(cmd,">> "); + strcat(cmd,path); + + ret=system(cmd); + + /* Assume that non-zero is error + */ + return(ret==0); +} + + +/* END OF FILE */ diff --git a/djgpp/vstring.c b/djgpp/vstring.c new file mode 100644 index 0000000..2cc5ee4 --- /dev/null +++ b/djgpp/vstring.c @@ -0,0 +1,42 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides portable versions of necessary string routines + +*/ +static const char rcs_id[]="$Id$"; + +#include <string.h> + + +int StrCaseCmp(char *a, char *b) +{ + return(strcasecmp(a,b)); +} + +int StrNCaseCmp(char *a, char *b, int n) +{ + return(strncasecmp(a,b,n)); +} + + +/* END OF FILE */ diff --git a/doc/bugs.htm b/doc/bugs.htm new file mode 100644 index 0000000..40dcfc0 --- /dev/null +++ b/doc/bugs.htm @@ -0,0 +1,40 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">Bugs</h1> + +<p>If you find any additional bugs please try and send as much +information (including a surefire way of repeating the problem if +possible) <a href="mailto:ianc@noddybox.demon.co.uk">here</a>. +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:<a name="CONTACTS"></a></p> + +<table border="1" cellpadding="10"> + <tr> + <td valign="top" nowrap><strong>DJGPP/DOS</strong></td> + <td valign="top"><a + href="mailto:ianc@noddybox.demon.co.uk">ianc@noddybox.demon.co.uk</a><br> + <strong>Note</strong>: messages with <strong>any sort</strong> + of attachment will not be accepted.</td> + </tr> +</table> + +<p> </p> + +<hr> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: bugs.htm,v 1.4 2000/07/18 16:49:48 dosuser Exp dosuser $</tt></p> +</body> +</html> diff --git a/doc/building.htm b/doc/building.htm new file mode 100644 index 0000000..b2de7b0 --- /dev/null +++ b/doc/building.htm @@ -0,0 +1,90 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">Building</h1> + +<p>This part of the documentation simply expands <u>slightly</u> +on the contents of the README in the source distribution.</p> + +<hr> + +<h2>Notes</h2> + +<p>Note that the viDOOM makefile expects the <strong>include</strong> +command to be honoured.</p> + +<hr> + +<h2>Instructions</h2> + +<h3>Step 1</h3> + +<p>Edit the makefile.</p> + +<h3>Step 2</h3> + +<p>Change the following line to the name of your platform:</p> + +<blockquote> + <p><tt>MAKEPLAT=djgpp</tt></p> +</blockquote> + +<p>The following platforms are currently supported:</p> + +<blockquote> + <p><strong>DJGPP - </strong>Protected-mode 32-bit MSDOS + (Windows 9x / MSDOS + DPMI)</p> +</blockquote> + +<h3>Step 3</h3> + +<p>If you are going to use the install script, then update the +following line:</p> + +<blockquote> + <p><tt>INSTALLDIR=C:/viDOOM</tt></p> +</blockquote> + +<p>so it points to the directory where you wish it to be +installed.</p> + +<h3>Step 4</h3> + +<p>Set the MKDS to the directory separator for this platform. +This is used so that the makefile can safely access +sub directories:</p> + +<blockquote> + <p><tt>MKDS=/</tt></p> +</blockquote> + +<h3>Step 5</h3> + +<p>If you wish to build the debug version remove the comment +(hash character - #) from the start of the following line:</p> + +<blockquote> + <p><tt>DEBUG=-DDEBUG</tt></p> +</blockquote> + +<h3>Step 6</h3> + +<p>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 <strong>install</strong>.</p> + +<hr width="99%"> + +<p><a href="index.htm">Back to the index</a></p> + +<p><tt>$Id: building.htm,v 1.5 2000/08/13 00:35:59 dosuser Exp dosuser $ </tt></p> +</body> +</html> diff --git a/doc/changelog.htm b/doc/changelog.htm new file mode 100644 index 0000000..1192579 --- /dev/null +++ b/doc/changelog.htm @@ -0,0 +1,49 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">Changelog</h1> + +<p>Below is a list of the major features added or bugs fixed in +each release:</p> + +<table border="1" cellpadding="3" width="100%"> +<thead> +<tr> +<th ALIGN="LEFT">Version</th> +<th ALIGN="LEFT">Date</th> +<th ALIGN="LEFT">Changes</th> +<tr> +<tbody> + <tr> + <td valign="top" nowrap>0.01</td> + <td VALIGN="TOP" nowrap>05/08/2000</td> + <td valign="top">Initial release</td> + </tr> + <tr> + <td valign="top" nowrap>0.02</td> + <td VALIGN="TOP" nowrap>13/08/2000</td> + <td valign="top"><ol> + <li>Fixed bug in step creation</li> + <li>Added functionality to allow the selection of + overlapping objects</li> + </ol> + </td> + </tr> +</tbody> +</table> + +<hr> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: changelog.htm,v 1.2 2000/08/13 17:26:40 dosuser Exp dosuser $</tt></p> +</body> +</html> diff --git a/doc/ed_ex1.png b/doc/ed_ex1.png Binary files differnew file mode 100644 index 0000000..503fdbc --- /dev/null +++ b/doc/ed_ex1.png diff --git a/doc/ed_ex2.png b/doc/ed_ex2.png Binary files differnew file mode 100644 index 0000000..8e4986d --- /dev/null +++ b/doc/ed_ex2.png diff --git a/doc/ed_ex3.png b/doc/ed_ex3.png Binary files differnew file mode 100644 index 0000000..aee4bc6 --- /dev/null +++ b/doc/ed_ex3.png diff --git a/doc/ed_line.png b/doc/ed_line.png Binary files differnew file mode 100644 index 0000000..a4aa32a --- /dev/null +++ b/doc/ed_line.png diff --git a/doc/ed_lninf.png b/doc/ed_lninf.png Binary files differnew file mode 100644 index 0000000..46cbc8a --- /dev/null +++ b/doc/ed_lninf.png diff --git a/doc/ed_merge.png b/doc/ed_merge.png Binary files differnew file mode 100644 index 0000000..f08707a --- /dev/null +++ b/doc/ed_merge.png diff --git a/doc/ed_multi.png b/doc/ed_multi.png Binary files differnew file mode 100644 index 0000000..a1bbf59 --- /dev/null +++ b/doc/ed_multi.png diff --git a/doc/ed_sect.png b/doc/ed_sect.png Binary files differnew file mode 100644 index 0000000..3bd3fad --- /dev/null +++ b/doc/ed_sect.png diff --git a/doc/ed_step.png b/doc/ed_step.png Binary files differnew file mode 100644 index 0000000..ab4140f --- /dev/null +++ b/doc/ed_step.png diff --git a/doc/ed_thing.png b/doc/ed_thing.png Binary files differnew file mode 100644 index 0000000..d063772 --- /dev/null +++ b/doc/ed_thing.png diff --git a/doc/ed_vert.png b/doc/ed_vert.png Binary files differnew file mode 100644 index 0000000..5ab35dc --- /dev/null +++ b/doc/ed_vert.png diff --git a/doc/editing.htm b/doc/editing.htm new file mode 100644 index 0000000..ed60043 --- /dev/null +++ b/doc/editing.htm @@ -0,0 +1,1295 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">Editing</h1> + +<h2 align="left">Index</h2> + +<p align="left">This page is split up into the following +sections:</p> + +<ul> + <li><a href="#THE_BASICS">The Basics</a> </li> + <li><a href="#BASIC_MOUSE">Basic Mouse Operation</a> </li> + <li><a href="#GENERAL_KEY">General Key Commands</a> </li> + <li><a href="#SECTOR_MODE">Sector Edit Mode</a><ul> + <li><a href="#SECTOR_DISPLAY">Display</a></li> + <li><a href="#SECTOR_KEYS">Extra Keys</a></li> + <li><a href="#SECTOR_INSERT">Insertion</a></li> + <li><a href="#SECTOR_DELETE">Deletion</a></li> + <li><a href="#SECTOR_POPUP">Popup Menu</a></li> + </ul> + </li> + <li><a href="#LINEDEF_MODE">Linedef Edit Mode</a><ul> + <li><a href="#LINEDEF_DISPLAY">Display</a></li> + <li><a href="#LINEDEF_KEYS">Extra Keys</a></li> + <li><a href="#LINEDEF_INSERT">Insertion</a></li> + <li><a href="#LINEDEF_DELETE">Deletion</a></li> + <li><a href="#LINEDEF_POPUP">Popup Menu</a></li> + <li><a href="#SIDEDEF_MENU">Sidedef Menu</a></li> + <li><a href="#STAIR_CREATION">Stair creation</a></li> + </ul> + </li> + <li><a href="#THING_MODE">Thing Edit Mode</a><ul> + <li><a href="#THING_DISPLAY">Display</a></li> + <li><a href="#THING_KEYS">Extra Keys</a></li> + <li><a href="#THING_INSERT">Insertion</a></li> + <li><a href="#THING_DELETE">Deletion</a></li> + <li><a href="#THING_POPUP">Popup Menu</a></li> + </ul> + </li> + <li><a href="#VERTEX_MODE">Vertex Edit Mode</a><ul> + <li><a href="#VERTEX_DISPLAY">Display</a></li> + <li><a href="#VERTEX_KEYS">Extra Keys</a></li> + <li><a href="#VERTEX_INSERT">Insertion</a></li> + <li><a href="#VERTEX_DELETE">Deletion</a></li> + <li><a href="#VERTEX_POPUP">Popup Menu</a></li> + </ul> + </li> + <li><a href="#MULTI_MODE">Multiple Edit Mode</a><ul> + <li><a href="#MULTI_DISPLAY">Display</a></li> + <li><a href="#MULTI_OPERATION">Operation</a></li> + </ul> + </li> + <li><a href="#MERGE_MAP">Merging Maps</a></li> +</ul> + +<hr> + +<h2 align="left">The Basics<a name="THE_BASICS"></a></h2> + +<p align="left">Once you start editing in viDOOM you should be +greeted by a screen similar to the following (no prizes for +guessing the map number):</p> + +<p align="left"><img src="ed_sect.png" width="640" height="480"></p> + +<p>At the top of the screen is a title bar which shows the +following information, going from left to right:</p> + +<ul> + <li>The edit mode. This is either 'Sector', 'Linedef', + 'Thing' or 'Vertex'.</li> + <li>The position of the mouse pointer in the map.</li> + <li>The current scale</li> + <li>Whether movements are locked to the current grid scale.</li> + <li>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.</li> + <li>Below this is a line where specific edit modes can show + extra information.</li> +</ul> + +<p>The main central part of the screen is made up the map being +edited.</p> + +<p>At the bottom (and sometimes the middle right) of the screen +are information boxes that display details of the object the +mouse pointer is currently over. The size and information in +these boxes changes with the edit mode.</p> + +<hr> + +<h2>Basic Mouse Operation<a name="BASIC_MOUSE"></a></h2> + +<p>The mouse acts in exactly the same way, independent of the +mode. Simply left click over an object to select it. If the +control key is pressed while selecting the object the object is +selected in addition to any others currently selected.</p> + +<p>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.</p> + +<p>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 <a href="overview.htm#HOVER_SELECT">overview</a> +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.</p> + +<p>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.</p> + +<p>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.</p> + +<hr> + +<h2>General Key Commands<a name="GENERAL_KEY"></a></h2> + +<p>There are a number of key commands that are common to all edit +modes in viDOOM. These are as follows:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap>F1</td> + <td valign="top">General Help (key commands and mouse + usage).</td> + </tr> + <tr> + <td valign="top" nowrap>F2</td> + <td valign="top">Help specific to the current edit mode</td> + </tr> + <tr> + <td valign="top" nowrap>Escape</td> + <td valign="top">Finish Editing</td> + </tr> + <tr> + <td valign="top" nowrap>Cursor Keys</td> + <td valign="top">Move the map display</td> + </tr> + <tr> + <td valign="top" nowrap>Shift + Cursor Keys</td> + <td valign="top">Move the map display quickly</td> + </tr> + <tr> + <td valign="top" nowrap>Ctrl + Cursor Keys</td> + <td valign="top">Move the map by one pixel (i.e. by + whatever value the scale is currently set to).</td> + </tr> + <tr> + <td valign="top" nowrap>Page Up/Down</td> + <td valign="top">Zoom in/out</td> + </tr> + <tr> + <td valign="top" nowrap>Q/W</td> + <td valign="top">Alert the grid lock scale</td> + </tr> + <tr> + <td valign="top" nowrap>G</td> + <td valign="top">Switch grid lines on/off</td> + </tr> + <tr> + <td valign="top" nowrap>X</td> + <td valign="top">Switch grid snapping on/off</td> + </tr> + <tr> + <td valign="top" nowrap>Tab/Shift Tab</td> + <td valign="top">Go to next/previous edit mode</td> + </tr> + <tr> + <td valign="top" nowrap>V</td> + <td valign="top"><a href="#VERTEX_MODE">VERTEX edit mode</a></td> + </tr> + <tr> + <td valign="top" nowrap>L</td> + <td valign="top"><a href="#LINEDEF_MODE">LINEDEF edit + mode</a></td> + </tr> + <tr> + <td valign="top" nowrap>S</td> + <td valign="top"><a href="#SECTOR_MODE">SECTOR edit mode</a></td> + </tr> + <tr> + <td valign="top" nowrap>T</td> + <td valign="top"><a href="#THING_MODE">THING edit mode</a></td> + </tr> + <tr> + <td valign="top" nowrap>C</td> + <td valign="top"><a href="#MULTI_MODE">MULTI edit mode</a></td> + </tr> + <tr> + <td valign="top" nowrap>F9</td> + <td valign="top">Deselect all objects</td> + </tr> + <tr> + <td valign="top" nowrap>Shift + F9</td> + <td valign="top">Invert current selection</td> + </tr> + <tr> + <td valign="top" nowrap>F10</td> + <td valign="top">Select all objects</td> + </tr> + <tr> + <td valign="top" nowrap>Shift + F10</td> + <td valign="top">Select all objects with a specific type + (not applicable to VERTEX objects).</td> + </tr> + <tr> + <td valign="top" nowrap>Ctrl + F10</td> + <td valign="top">Select 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.<p>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.</p> + <p> + 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. + </p> + <p> + Also bear in mind, that though viDOOM can be tricked into overlapping + sectors, and these can be picked using this method, a DOOM level + should <b>never</b> have overlapping sectors. Unless you want the + Cyberdemon to come and take you away in the night. + </td> + </tr> + <tr> + <td valign="top" nowrap>Alt + F10</td> + <td valign="top">As above, but any selected object is + selected in addition to the objects currently selected.</td> + </tr> + <tr> + <td valign="top" nowrap>F11/Shift + F11</td> + <td valign="top">Locate the next or previous selected + object and display it in the centre of the screen.</td> + </tr> + <tr> + <td valign="top" nowrap>Delete</td> + <td valign="top">Delete the selected objects <sup><sup>Note + 1</sup></sup></td> + </tr> + <tr> + <td valign="top" nowrap>Insert</td> + <td valign="top">Insert a new object</td> + </tr> + <tr> + <td valign="top" nowrap>F3</td> + <td valign="top">Merge a map. See the <a + href="#MERGE_MAP">map FL</a> section for details.</td> + </tr> + <tr> + <td valign="top" nowrap>F4</td> + <td valign="top">Move selected objects</td> + </tr> + <tr> + <td valign="top" nowrap>F5</td> + <td valign="top">Rotate selected objects <sup><sup>Note 2</sup></sup></td> + </tr> + <tr> + <td valign="top" nowrap>[</td> + <td valign="top">Rotate selected objects 5° to the left <sup><sup>Note + 2</sup></sup></td> + </tr> + <tr> + <td valign="top" nowrap>]</td> + <td valign="top">Rotate selected objects 5° to the right + <sup><sup>Note 2</sup></sup></td> + </tr> + <tr> + <td valign="top" nowrap>F6</td> + <td valign="top">Scale selected objects <sup><sup>Note 2</sup></sup></td> + </tr> + <tr> + <td valign="top" nowrap>{</td> + <td valign="top">Scale selected objects by 90% <sup><sup>Note + 2</sup></sup></td> + </tr> + <tr> + <td valign="top" nowrap>}</td> + <td valign="top">Scale selected objects by 110% <sup><sup>Note + 2</sup></sup></td> + </tr> + <tr> + <td valign="top" nowrap>F7</td> + <td valign="top">Set tag number for this object (only + applicable to SECTOR and LINEDEF objects).</td> + </tr> + <tr> + <td valign="top" nowrap>Shift + F7</td> + <td valign="top">Select objects with a specific tag + number (only applicable to SECTOR and LINEDEF objects).</td> + </tr> + <tr> + <td valign="top" nowrap>F8</td> + <td valign="top">Locate a certain object and display in + the centre of the screen</td> + </tr> + <tr> + <td valign="top" nowrap>Shift + F8</td> + <td valign="top">Locate a certain object, display in the + centre of the screen and select it.</td> + </tr> + <tr> + <td valign="top" nowrap>R</td> + <td valign="top">Redraw the map display. Handy for + refreshing selected objects in SECTOR mode.</td> + </tr> +</table> + +<p><strong>Note 1:</strong> 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.</p> + +<p><strong>Note 2:</strong> 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.</p> + +<hr> + +<h2><a name="SECTOR_MODE"></a>Sector Edit Mode</h2> + +<p>For a basic description of a SECTOR see the <a +href="glossary.htm#SECTOR">glossary</a>.</p> + +<h3><a name="SECTOR_DISPLAY"></a>Display in Sector Mode</h3> + +<p>When in sector mode the display will look like this:</p> + +<p><img src="ed_sect.png" width="640" height="480"></p> + +<p>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.</p> + +<p>At the bottom of the screen is a box which shows the details of +the sector the pointer is currently over.</p> + +<p>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.</p> + +<h3><a name="SECTOR_KEYS"></a>Extra Keys in Sector Mode</h3> + +<p>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.</p> + +<table border="1" cellpadding="3"> + <tr> + <td>H</td> + <td>Toggle the tag highlighting mode on an off. See the <a + href="#SECTOR_DISPLAY">display</a> section for an example + of what this does.</td> + </tr> + <tr> + <td valign="top" nowrap>M</td> + <td valign="top">Change sector move mode. See <a + href="overview.htm#SECTOR_MOVE">overview</a> for details.</td> + </tr> + <tr> + <td valign="top" nowrap>, (comma)</td> + <td valign="top">Decrease selected sectors floor height + by 8</td> + </tr> + <tr> + <td valign="top" nowrap>. (period)</td> + <td valign="top">Increase selected sectors floor height + by 8</td> + </tr> + <tr> + <td valign="top" nowrap><</td> + <td valign="top">Decrease selected sectors ceiling height + by 8</td> + </tr> + <tr> + <td valign="top" nowrap>></td> + <td valign="top">Increase selected sectors ceiling height + by 8</td> + </tr> + <tr> + <td valign="top" nowrap>-</td> + <td valign="top">Decrease selected sectors lighting level + by 16</td> + </tr> + <tr> + <td valign="top" nowrap>+</td> + <td valign="top">Increase selected sectors lighting level + by 16</td> + </tr> +</table> + +<h3><a name="SECTOR_INSERT"></a>Sector Insertion</h3> + +<p>When you insert a sector a popup menu is displayed where you +can select a type of sector to create.</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong>Create unbound sector</strong></td> + <td valign="top">This will create a sector that is + unbound to any linedefs/sidedefs. It will have a normal + type as defined in the <a + href="overview.htm#NORMAL_TYPES">config file</a>, a tag + of zero and a floor height, ceiling height and light + level as defined in the <a + href="overview.htm#DEFAULT_SECTOR_LIGHT_ETC">config file</a>. + The floor and ceiling flats will be set to the <a + href="overview.htm#EMPTY_TEXTURE_NAME">empty texture name</a>. + After it's creation the sector number will be displayed + onscreen.<p>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.</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><strong>Create polygon</strong></td> + <td valign="top">On 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.<p>You will be asked + then for the following information:</p> + <ul> + <li>A <a href="overview.htm#LINEDEF_CLASSES">class</a> + and <a href="overview.htm#LINEDEF_TYPES">type</a> + of linedef (e.g. scrolling walls, normal, + switches) out of those defined in the config + file.</li> + <li>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 <a + href="overview.htm#DEFAULT_SECTOR_LIGHT_ETC">default</a> + values will be used.</li> + <li>A further linedef type that defines the linedef's + flags, as defined in the <a + href="overview.htm#LINEDEF_DEFAULTS">config file</a>.</li> + <li>The style in which the sector should be painted + as defined in the <a + href="overview.htm#SECTOR_STYLES">config file</a>.</li> + <li>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.</li> + </ul> + </td> + </tr> +</table> + +<h3><a name="SECTOR_DELETE"></a>Sector Deletion</h3> + +<p>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.</p> + +<h3><a name="SECTOR_POPUP"></a>Sector Popup Menu</h3> + +<p>On selecting sectors and pressing the right mouse button to +get the sector popup menu the following options will be +presented:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong>Change floor height</strong></td> + <td valign="top">Change the height of the floor of the + selected sectors.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change ceiling height</strong></td> + <td valign="top">Change the height of the ceiling of the + selected sectors.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change light level</strong></td> + <td valign="top">Alter the light level of the sectors.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change tag</strong></td> + <td valign="top">Alter the tag value of the sectors.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change floor</strong></td> + <td valign="top">Shows a picklist of the flats from which + the floor texture can be selected.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change ceiling</strong></td> + <td valign="top">Shows a picklist of the flats from which + the ceiling texture can be selected.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change type</strong></td> + <td valign="top">Changes the sector type. The <a + href="overview.htm#SECTOR_CLASSES">classes</a> and their <a + href="overview.htm#SECTOR_TYPES">sector types</a> are + defined in the config file.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Paint sector in style</strong></td> + <td valign="top">Paints the sector using the textures + described as being a style in the <a + href="overview.htm#SECTOR_STYLES">config file</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Move</strong></td> + <td valign="top">Move the selected sectors.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Delete</strong></td> + <td valign="top">Delete the selected sectors. This just + always shows a reminder that empty sectors will be + deleted when the map is saved.</td> + </tr> +</table> + +<hr> + +<h2><a name="LINEDEF_MODE"></a>Linedef Edit Mode</h2> + +<p>For a basic description of a LINEDEF see the <a +href="glossary.htm#LINEDEF">glossary</a>.</p> + +<h3><a name="LINEDEF_DISPLAY"></a>Display in Linedef Mode</h3> + +<p>When in linedef mode the display will look like this:</p> + +<p><img src="ed_line.png" width="640" height="480"></p> + +<p>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..</p> + +<p>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 <a +href="overview.htm#LINEDEF_CLASSES">class</a> of linedef. This +can be altered in the <a +href="overview.htm#SHOW_FULL_LINEDEF_INFO">config</a> file so +that the linedef type is show as as it's hex number and the name +defined for the linedef <a href="overview.htm#LINEDEF_TYPES">type</a> +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.</p> + +<p><img src="ed_lninf.png" width="396" height="72"></p> + +<p>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.</p> + +<h3><a name="LINEDEF_KEYS"></a>Extra Keys in Linedef Mode</h3> + +<p>The following extra keys can be used while in linedef mode.</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap>H</td> + <td valign="top">Toggle the tag highlighting mode on an + off. See the <a href="#LINEDEF_DISPLAY">display</a> + section for an example of what this does.</td> + </tr> + <tr> + <td valign="top" nowrap>F12</td> + <td valign="top">Check the currently selected linedefs. + It checks and prompts for the following things:<ul> + <li>Removal of lower textures on 1-sided linedefs.<br> + This check can be disabled in the <a + href="overview.htm#CHECK_LINE_1SIDE_LOWER">config + file</a>.</li> + <li>Removal of upper textures on 1-sided linedefs.<br> + This check can be disabled in the <a + href="overview.htm#CHECK_LINE_1SIDE_UPPER">config + file</a>.</li> + <li>Addition of missing middle textures on 1-sided + linedefs.<br> + This check can be disabled in the <a + href="overview.htm#CHECK_LINE_1SIDE_MIDDLE">config + file</a>.</li> + <li>Removal of all textures on 2-sided linedefs where + both sides of the linedef are in the same sector.<br> + This check can be disabled in the <a + href="overview.htm#CHECK_LINE_2SIDE_SAME_SECTOR">config + file</a>.</li> + <li>Removal of middle textures on 2-sided linedefs.<br> + This check can be disabled in the <a + href="overview.htm#CHECK_LINE_2SIDE_MIDDLE">config + file</a>.</li> + <li>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.<br> + This check can be disabled in the <a + href="overview.htm#CHECK_LINE_2SIDE_LOWER">config + file</a>.</li> + <li>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.<br> + This check can be disabled in the <a + href="overview.htm#CHECK_LINE_2SIDE_UPPER">config + file</a>.</li> + </ul> + <p>Note that whenever textures are to be added viDOOM + will display the picklist to request what texture to + paint, unless the LINEDEF_CHECK_DEFAULT section in the <a + href="overview.htm#LINEDEF_CHECK_DEFAULT">config</a> file + is set up.</p> + <p><strong>Important Note:</strong> 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.</p> + </td> + </tr> +</table> + +<h3><a name="LINEDEF_INSERT"></a>Linedef Insertion</h3> + +<p>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 <a +href="overview.htm#LINEDEF_DEFAULTS">config file</a>) 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.</p> + +<h3><a name="LINEDEF_DELETE"></a>Linedef Deletion</h3> + +<p>Linedefs can be safely deleted from the map at any time.</p> + +<h3><a name="LINEDEF_POPUP"></a>Linedef Popup Menu</h3> + +<p>On selecting things and pressing the right mouse button to get +the thing popup menu the following options will be presented:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong>Change linedef flags</strong></td> + <td valign="top">Allows the flags of the selected + linedefs to be changed. On selecting this a dialog will + appear allowing any of flags (as defined by the <a + href="overview.htm#LINEDEF_FLAGS">config file</a>) to to + toggled on or off.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change linedef type</strong></td> + <td valign="top">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 <a + href="overview.htm#LINEDEF_CLASSES">config file</a>). + 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 <a + href="overview.htm#LINEDEF_TYPES">config file</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Swap sides</strong></td> + <td valign="top">Swaps the sides of the linedef, so that + the linedef points in the other directions. Note that the + sidedefs are re-arranged so that the texturing and + sector numbers on the sides of the linedef are not + switched.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Split line</strong></td> + <td valign="top">Splits the selected linedefs in the + middle.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Select trail from this + linedef</strong></td> + <td valign="top">Selects 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.<p>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.</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><strong>Join linedefs with steps</strong></td> + <td valign="top">Allows two selected linedefs to be + joined with steps. See the <a href="#STAIR_CREATION">Stair + creation</a> section for details.</td> + </tr> + <tr> + <td><strong>Right Sidedef</strong></td> + <td>This will display a sub menu for operation for the + right sidedef. See the <a href="#SIDEDEF_MENU">Sidedef + menu</a> for details.</td> + </tr> + <tr> + <td><strong>Left Sidedef</strong></td> + <td>This will display a sub menu for operation for the + left sidedef. See the <a href="#SIDEDEF_MENU">Sidedef + menu</a> for details.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change tag</strong></td> + <td valign="top">Change the tag number for the selected + linedefs.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Move</strong></td> + <td valign="top">Move the selected linedefs.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Delete</strong></td> + <td valign="top">Delete the selected linedefs.</td> + </tr> +</table> + +<h3><a name="SIDEDEF_MENU"></a>Sidedef Menu</h3> + +<p>On selecting the <strong>Right sidedef</strong> or <strong>Left +sidedef</strong> options above the following options can be +chosen.</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong>Change upper texture</strong></td> + <td valign="top">Alter the upper texture on the selected + sidedef.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change middle texture</strong></td> + <td valign="top">Alter the middle texture on the selected + sidedef.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change lower texture</strong></td> + <td valign="top">Alter the lower texture on the selected + sidedef.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change texture offset</strong></td> + <td valign="top">Sets the texture offset for the selected + sidedef.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Adjust texture offset</strong></td> + <td valign="top">Adjusts 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.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change sector</strong></td> + <td valign="top">Alters the sector number the sidedef is + linked with.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Align textures</strong></td> + <td valign="top">Aligns 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.<p>Remember + that if doing the same set of linedefs then the order + should be reversed when doing the left sidedef over the + right sidedef.</p> + </td> + </tr> +</table> + +<h3><a name="STAIR_CREATION"></a>Stair creation</h3> + +<p>This joins the two selected linedefs with steps. Before +starting this option a couple of caveats should be noted:</p> + +<ul> + <li>Lines must be non-zero in length and not share any + vertices.</li> + <li>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 <strong>Swap sides</strong> + on the linedefs as required before starting (the sides + can be swapped back once the steps have been defined).</li> + <li>If the linedefs already have a left sidedef, this will be + deleted in preference for the new one facing onto the new + sectors.</li> + <li>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.</li> + <li>If the steps pass through a sector, it must be the same + sector.</li> +</ul> + +<p>i.e. the following two examples are OK, L1 and L2 can be +joined with stairs:</p> + +<p><img src="ed_ex1.png" width="204" height="97"></p> + +<p><img src="ed_ex2.png" width="204" height="97"></p> + +<p>But the following example, where stairs would cross both +sectors S3 and S4 is not allowed:</p> + +<p><img src="ed_ex3.png" width="204" height="97"></p> + +<p>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:</p> + +<p><img src="ed_step.png" width="640" height="480"></p> + +<p>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:</p> + +<ul> + <li>No of steps</li> + <li>The difference in floor height between each step</li> + <li>The difference in ceiling height between each step</li> + <li>The step drawing mode (<strong>Straight</strong> or <strong>Curve</strong> + mode).</li> + <li>Which side is being moved when in <strong>Curve</strong> + mode.</li> +</ul> + +<p>On the left is a box giving a quick help on the following +keys:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap>+</td> + <td valign="top">Increase the number of steps in the + staircase (maximum 128)</td> + </tr> + <tr> + <td valign="top" nowrap>- </td> + <td valign="top">Decrease the number of steps in the + staircase (minimum 1)</td> + </tr> + <tr> + <td valign="top" nowrap>C</td> + <td valign="top">Change between <strong>Straight</strong> + and <strong>Curve</strong> 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.</td> + </tr> + <tr> + <td valign="top" nowrap>S</td> + <td valign="top">Swaps between the two walls when + defining the curve of the walls in <strong>curve</strong> + mode.</td> + </tr> + <tr> + <td valign="top" nowrap>R</td> + <td valign="top">Swap 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.<br> + Obviously, the butterfly effect is <b>not</b> what is wanted...</td> + </tr> +</table> + +<p>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.</p> + +<p>At this point you will be asked if the ceiling should also be +stepped. Selecting <strong>No</strong> 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.</p> + +<p>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.</p> + +<hr> + +<h2><a name="THING_MODE"></a>Thing Edit Mode</h2> + +<p>For a basic description of a THING see the <a +href="glossary.htm#THING">glossary</a>.</p> + +<h3><a name="THING_DISPLAY"></a>Display in Thing Mode</h3> + +<p>When in thing mode the display will look like this:</p> + +<p><img src="ed_thing.png" width="640" height="480"></p> + +<p>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 <a +href="overview.htm#THING_CLASSES">config file</a>).</p> + +<p>At the bottom of the screen is a box which shows the details of +the thing the pointer is currently over.</p> + +<h3><a name="THING_KEYS"></a>Extra Keys in Thing Mode</h3> + +<p>There are no extra keys in thing edit mode.</p> + +<h3><a name="THING_INSERT"></a>Thing Insertion</h3> + +<p>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.</p> + +<ul> + <li>Insert a new thing.</li> + <li>Select the new thing and change it's type to be a + Cyberdemon (see the <a href="#THING_POPUP">Popup Menu</a> + for how to do this).</li> + <li>All newly inserted things will now be Cyberdemons, until + a further edit is made.</li> +</ul> + +<h3><a name="THING_DELETE"></a>Thing Deletion</h3> + +<p>Things can be safely deleted from the map at any time.</p> + +<h3><a name="THING_POPUP"></a>Thing Popup Menu</h3> + +<p>On selecting things and pressing the right mouse button to get +the thing popup menu the following options will be presented:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong>Change type</strong></td> + <td valign="top">Change 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 <a + href="overview.htm#THING_CLASSES">config file</a>). 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 <a + href="overview.htm#THING_TYPES">config file</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change angle</strong></td> + <td valign="top">Allows 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.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Change flags</strong></td> + <td valign="top">Allows the flags of the selected things + to be changed. On selecting this a dialog will appear + allowing any of flags (as defined by the <a + href="overview.htm#THING_FLAGS">config file</a>) to to + toggled on or off.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Snap selected things</strong></td> + <td valign="top">Snaps the selected things to the current + grid.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Move</strong></td> + <td valign="top">Move the selected things. Follow the + on-screen prompts for details on how to move the things + or cancel the operation.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Delete</strong></td> + <td valign="top">Delete the selected things.</td> + </tr> +</table> + +<hr> + +<h2><a name="VERTEX_MODE"></a>Vertex Edit Mode</h2> + +<p>For a basic description of a VERTEX see the <a +href="glossary.htm#VERTEX">glossary</a>.</p> + +<h3><a name="VERTEX_DISPLAY"></a>Display in Vertex Mode</h3> + +<p>When in vertex mode the display will look like this:</p> + +<p><img src="ed_vert.png" width="640" height="480"></p> + +<p>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.</p> + +<p>At the bottom of the Cyber demons is a box which shows the details of +the vertex the pointer is currently over.</p> + +<h3><a name="VERTEX_KEYS"></a>Extra Keys in Vertex Mode</h3> + +<p>The following extra keys can be used while in linedef mode.</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap>F12</td> + <td valign="top">Goes through all the vertices and delete + ones that are not bound to a linedef.</td> + </tr> +</table> + +<h3><a name="VERTEX_INSERT"></a>Vertex Insertion</h3> + +<p>Inserting a vertex simply inserts a new vertex unbound to any +linedefs at the pointer location.</p> + +<h3><a name="VERTEX_DELETE"></a>Vertex Deletion</h3> + +<p>Vertices can only be deleted if they are not bound to any +linedefs. Linedefs must be <a href="#LINEDEF_DELETE">deleted</a> +before you can delete the vertex.</p> + +<h3><a name="VERTEX_POPUP"></a>Vertex Popup Menu</h3> + +<p>On selecting vertices and pressing the right mouse button to +get the vertex popup menu the following options will be +presented:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong>Chain selected vertices</strong></td> + <td valign="top">Selecting 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.<p>On selecting this option you will be first + prompted to selected a <a + href="overview.htm#LINEDEF_CLASSES">class</a> and <a + href="overview.htm#LINEDEF_TYPES">type</a> 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 <a + href="overview.htm#LINEDEF_DEFAULTS">config file</a>.</p> + <p>If the selected linedef type is one sided and the <a + href="overview.htm#ASK_MIDDLE_ON_2SIDED">config file + options</a> 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.</p> + <p><strong>Tip:</strong> One thing this option is very + useful for is creating pillars and the such like inside + sectors. Insert new vertexes (with the <a + href="overview.htm#INSERT_SELECT">insert select</a> + option in the config file enabled) in the shape you want + in an <strong><u>anti-clockwise</u></strong> direction. + Then select this option and a one-sided linedef type and + the result will be a column in the room.</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><strong>Chain selected vertices + into a sector</strong></td> + <td valign="top">Selecting 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 <strong><u>clockwise</u></strong> + direction.<p>You will be asked then for the following + information:</p> + <ul> + <li>A <a href="overview.htm#LINEDEF_CLASSES">class</a> + and <a href="overview.htm#LINEDEF_TYPES">type</a> + of linedef (e.g. scrolling walls, normal, + switches) out of those defined in the config + file.</li> + <li>The new sectors floor height, ceiling height and + light level.</li> + <li>A further linedef type that defines the linedef's + flags, as defined in the <a + href="overview.htm#LINEDEF_DEFAULTS">config file</a>.</li> + <li>The style in which the sector should be painted + as defined in the <a + href="overview.htm#SECTOR_STYLES">config file</a>.</li> + <li>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 <strong><u>clockwise</u></strong>order.</li> + </ul> + <p><strong>Tip:</strong> 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.</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><strong>Merge selected vertices</strong></td> + <td valign="top">The 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.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Snap selected vertices</strong></td> + <td valign="top">Snaps the selected vertices to the + current grid.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Move</strong></td> + <td valign="top">Move the selected vertices. Follow the + on-screen prompts for details on how to move the vertices + or cancel the operation.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>Delete</strong></td> + <td valign="top">Delete the selected vertices.</td> + </tr> +</table> + +<hr> + +<h2><a name="MULTI_MODE"></a>Multi Edit Mode</h2> + +<h2><a name="MULTI_DISPLAY"></a>Display</h2> + +<p>When in multi mode the display will look like this:</p> + +<p><img src="ed_multi.png" width="640" height="480"></p> + +<p>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.</p> + +<p>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 <a +href="overview.htm#THING_CLASSES">config file</a>)</p> + +<p>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.</p> + +<p> </p> + +<h2><a name="MULTI_OPERATION"></a>Operation</h2> + +<p>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.</p> + +<p>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.</p> + +<hr> + +<h2><a name="MERGE_MAP"></a>Merging Maps</h2> + +<p>Pressing F3 in any edit mode will allow a different map to be +merged in with the currently edited map.</p> + +<p>First you will be asked if you wish to temporarily load a PWAD +and load the first map from it. If you select <strong>Yes</strong> +then you will be prompted for a PWAD file to read. If you select <strong>No</strong> +you will be asked for a level to load from the currently loaded +WADs.</p> + +<p><strong>Tip:</strong> The idea of this question is that you +can save PWAD files with a structure you wish to re-use in +multiple maps as the first map. Any linedefs in this map that +have a left sidedef bound to sector number -1 will have the +sector number reset to the sector in which the merged structure +has been placed. Note that if you do insert structures this way +it will generally be required to check the sidedefs to make sure +they have all their necessary textures and remember that the +structure will have it's original sector properties (floor, +ceiling and light levels).</p> + +<p>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.</p> + +<p><img src="ed_merge.png" width="640" height="480"></p> + +<p>On the bottom left is a box giving a quick help on the +following keys:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap>, (comma)</td> + <td valign="top">Rotate the map 1° to the left.</td> + </tr> + <tr> + <td valign="top" nowrap>. (period)</td> + <td valign="top">Rotate the map 1° to the right.</td> + </tr> + <tr> + <td valign="top" nowrap><</td> + <td valign="top">Rotate the map 10° to the left.</td> + </tr> + <tr> + <td valign="top" nowrap>></td> + <td valign="top">Rotate the map 10° to the right.</td> + </tr> +</table> + +<p>Pressing ESC will cancel the operation while pressing a mouse +button will place the map where it currently is.</p> + +<p>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).</p> + +<p>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.</p> + +<hr> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: editing.htm,v 1.12 2000/08/13 00:35:59 dosuser Exp dosuser $</tt></p> +</body> +</html> diff --git a/doc/glossary.htm b/doc/glossary.htm new file mode 100644 index 0000000..ef5912a --- /dev/null +++ b/doc/glossary.htm @@ -0,0 +1,127 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">Glossary</h1> + +<p>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. </p> + +<h2><a name="WAD">WAD</a></h2> + +<p>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, <a href="#IWAD">IWAD</a> +and <a href="#PWAD">PWAD</a> files. </p> + +<h2><a name="IWAD">IWAD</a></h2> + +<p>An IWAD file is is the 'Internal WAD' file. The IWAD file is +the main <a href="#WAD">WAD</a> file as supplied by id Software. +Note that only id Software are meant to produce IWAD files. </p> + +<h2><a name="PWAD">PWAD</a></h2> + +<p>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 <a href="#MAP">MAP</a> will mean +that DOOM will read the first map from the PWAD file, rather than +it's own IWAD file. </p> + +<p>Hmmmm.... Sure I could have explained that better. </p> + +<h2><a name="MAP">MAP</a></h2> + +<p>A map is taken to mean a DOOM level. Note there is two naming +conventions for maps, <b>E</b><b><i>x</i></b><b>M</b><b><i>y</i></b> +(where <i>x</i> is the episode number, and <i>y</i> the map +number in that episode) used in DOOM and Ultimate DOOM, and <b>MAP</b><b><i>nn</i></b> +(where <i>nn</i> is a number between 01 and 32) used in DOOM 2 +and Final Doom. </p> + +<p>A map is made up of a number of different elements, namely <a +href="#SECTOR">sectors</a>, <a href="#LINEDEF">linedefs</a>, <a +href="#SIDEDEF">sidedefs</a>, <a href="#THING">things</a> and <a +href="#VERTEX">vertexes</a>. Following are some (very) basic +definitions for these things, but you would be better reading the +<a href="thanks.htm#DOOMSPEC">Unofficial DOOM specs</a> for more +accurate definitions. </p> + +<p>MAPs generated in viDOOM must be built with a <a href="#BSP">Node +Builder</a> before they can be used in DOOM. </p> + +<h2><a name="VERTEX">VERTEX</a></h2> + +<p>A vertex is simply an X,Y co-ordinate in the DOOM world. </p> + +<h2><a name="THING">THING</a></h2> + +<p>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. </p> + +<h2><a name="LINEDEF">LINEDEF</a></h2> + +<p>A LINEDEF is a line that connects two <a href="#VERTEX">vertexes</a>. +A LINEDEF at it's most basic is used to make up the walls that +make up the DOOM levels. A LINEDEF must <i>always</i> have a +right <a href="#SIDEDEF">SIDEDEF</a> associated with it. 2 sided +LINEDEFS will also have a left SIDEDEF associated with it. </p> + +<p>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. </p> + +<h2><a name="SIDEDEF">SIDEDEF</a></h2> + +<p>A SIDEDEF is basically used to describe the <a href="#TEXTURE">textures</a> +that are painted upon a <a href="#LINEDEF">LINEDEF</a>. </p> + +<h2><a name="SECTOR">SECTOR</a></h2> + +<p>Though technically incorrect, it is simplest to picture a +SECTOR as an object enclosed by <a href="#LINEDEF">LINEDEFS</a>. +A sector is used to define the floor and ceiling heights and <a +href="#FLAT">flats</a> used to draw the floor and ceiling, in +addition to the lighting for that area. </p> + +<h2><a name="TEXTURE">TEXTURE</a></h2> + +<p>A texture is the graphics used to paint the walls in DOOM. </p> + +<h2><a name="FLAT">FLAT</a></h2> + +<p>A flat is the graphics used to paint the floors and ceiling in +DOOM. </p> + +<h2><a name="BSP">Node Builder</a></h2> + +<p>Does some of the nastier work of level building by creating +the extra information over and above the parts mentioned in <a +href="#MAP">MAPS</a> so that DOOM can actually understand the +level data enough to play it. </p> + +<p><a href="thanks.htm#BSP">BSP</a> is perhaps the best known of +these, and the one that was used all through viDOOM's +development. </p> + +<p> </p> + +<hr width="99%"> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: glossary.htm,v 1.2 2000/07/18 16:49:48 dosuser Exp dosuser $ </tt></p> +</body> +</html> diff --git a/doc/index.htm b/doc/index.htm new file mode 100644 index 0000000..e122330 --- /dev/null +++ b/doc/index.htm @@ -0,0 +1,47 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">viDOOM 0.02</h1> + +<p align="center">"... but what I talk about is DOOM, +because in the end, DOOM is all that counts."<br> +The Dark Half - <i>Stephen King</i> </p> + +<p align="center">viDOOM is released as free software under the +GNU General License. See <a href="license.htm">licence</a> for +details. </p> + +<hr> + +<h2>Index</h2> + +<ol> + <li><a href="thanks.htm">Acknowledgements and thanks</a> </li> + <li><a href="glossary.htm">Simple glossary</a> </li> + <li><a href="overview.htm">Overview (Configuration, etc)</a> </li> + <li><a href="mainmenu.htm">Main menu</a> </li> + <li><a href="editing.htm">Editing</a> </li> + <li><a href="porting.htm">Porting</a> </li> + <li><a href="bugs.htm">Bug Reports</a></li> + <li><a href="building.htm">Building</a> (only needs to be + read for the source distribution)</li> + <li><a href="changelog.htm">Changelog</a></li> +</ol> + +<hr width="99%"> + +<p><a href="http://www.noddybox.demon.co.uk/vidoom">viDOOM home +page</a></p> + +<p><tt>$Id: index.htm,v 1.6 2000/07/24 16:31:58 dosuser Exp +dosuser $ </tt></p> +</body> +</html> diff --git a/doc/license.htm b/doc/license.htm new file mode 100644 index 0000000..d07b0b8 --- /dev/null +++ b/doc/license.htm @@ -0,0 +1,362 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<pre> + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + + <signature of Ty Coon>, 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. +</pre> + + +<hr width="99%"> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: license.htm,v 1.1 2000/07/13 15:05:48 dosuser Exp dosuser $</tt></p> +</body> +</html> diff --git a/doc/mainmenu.htm b/doc/mainmenu.htm new file mode 100644 index 0000000..e768904 --- /dev/null +++ b/doc/mainmenu.htm @@ -0,0 +1,111 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">Main Menu</h1> + +<p>Depending on the setting in <a href="overview.htm#GAME_ASK">configuration</a> +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 <a href="overview.htm#GAME_TYPE">default game type</a> will +be used.</p> + +<p>After this you will be presented with the main menu containing +the following options.</p> + +<h3>Edit The Current Level</h3> + +<p>Edit the current level. See <a href="editing.htm">editing</a> +for details.</p> + +<h3>Load Level from open WADs</h3> + +<p>Selects a level to load from the open IWAD and PWAD files. +Note that the level is loaded from the <strong>most recent</strong> +WAD file opened that holds a map for the selected level. If you +already have a level open for editing and the <strong>Edit The +Current Level</strong> option has been used then confirmation +will be asked before allowing you to proceed. This warning can be +disabled in the INI file (see <a href="overview.htm#MAP_CLEAR">overview</a>).</p> + +<h3>Save Current Level</h3> + +<p>Saves the map you are currently editing into a <a +href="glossary.htm#PWAD">PWAD</a> file. This PWAD will <strong>only</strong> +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.</p> + +<p>Note that the saved map must be built with a <a +href="glossary.htm#BSP">node builder</a> before it can be played +in DOOM if the <a href="overview.htm#NODE_BUILDER">node building +section in the config file</a> has not been set up.</p> + +<p><strong>Important note: </strong>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 <em>will</em> be +renumbered if any have been deleted so that they fit together +contiguously after saving.</p> + +<h3>Create New Empty Level</h3> + +<p>Creates a completely empty level for editing. If you already +have a level open for editing and the <strong>Edit The Current +Level</strong> option has been used then confirmation will be +asked before allowing you to proceed. This warning can be +disabled in the INI file (see <a href="overview.htm#MAP_CLEAR">overview</a>).</p> + +<h3>Change Current Level Name</h3> + +<p>Allows the map to be assigned to a different map number. See +the <a href="glossary.htm#MAP">glossary</a> for some extra info +on map/level numbers.</p> + +<h3>Open PWAD file</h3> + +<p>Allows a PWAD file to be opened.</p> + +<h3>Close PWAD file</h3> + +<p>Closes one of the currently open PWAD files. Note that viDOOM +will not let you unload the <a href="glossary.htm#IWAD">IWAD</a> +opened at startup.</p> + +<h3>Preview Level</h3> + +<p>Allows a level to be previewed without disturbing the level +currently being edited. Note that the preview is <em>very</em> +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.</p> + +<h3>About viDOOM</h3> + +<p>See who was responsible for this.</p> + +<h3>Quit</h3> + +<p>Exit viDOOM. If you have a level open for editing and the <strong>Edit +The Current Level</strong> option has been used then confirmation +will be asked before allowing you to proceed. This warning can be +disabled in the INI file (see <a href="overview.htm#MAP_EXIT">overview</a>).</p> + +<hr> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: mainmenu.htm,v 1.6 2000/08/13 00:14:33 dosuser Exp dosuser $ </tt></p> +</body> +</html> diff --git a/doc/overview.htm b/doc/overview.htm new file mode 100644 index 0000000..4e682a8 --- /dev/null +++ b/doc/overview.htm @@ -0,0 +1,881 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">viDOOM Overview</h1> + +<ul> + <li><a href="#INTRODUCTION">Introduction</a></li> + <li><a href="#WHY_BOTHER">Why bother?</a></li> + <li><a href="#SUPPORTED_SYSTEMS">Supported systems</a></li> + <li>Configuration<ul> + <li><a href="#ENVIRONMENT">Environment</a></li> + <li><a href="#VIDOOM_INI">VIDOOM.INI</a></li> + <li><a href="#CONFIG_FILE">Config file</a></li> + </ul> + </li> +</ul> + +<hr> + +<h2><a name="INTRODUCTION"></a>Introduction</h2> + +<p>viDOOM is a Free Software DOOM editor. It supports the +following <a href="http://www.idsoftware.com">id</a> produced +games: </p> + +<ul> + <li>Doom</li> + <li>The Ultimate Doom</li> + <li>Doom 2 - Hell On Earth</li> + <li>Final Doom</li> +</ul> + +<p>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.</p> + +<p>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.</p> + +<hr> + +<h2><a name="WHY_BOTHER"></a>Why bother?</h2> + +<p>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 <a href="http://www.doomworld.com">Doomworld</a> +and all good FTP servers). </p> + +<p>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.</p> + +<p>I reasonably like the way viDOOM works, so I release it on the +off chance other people may too. </p> + +<hr> + +<h2><a name="SUPPORTED_SYSTEMS"></a>Supported systems</h2> + +<p>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: </p> + +<ul> + <li>Protected-mode 32-bit MSDOS (Windows 9x / MSDOS + DPMI)</li> +</ul> + +<hr> + +<h2><a name="ENVIRONMENT"></a>Environment</h2> + +<p>If defined in the environment, the value of <strong><tt>VIDOOM_DIR</tt></strong> +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.</p> + +<p><strong>Note:</strong><br> +How this environment is set will differ from system. Basically +viDOOM just calls the C library <tt>getenv()</tt> function. So,. +for instance in a Unix type system this could be:</p> + +<blockquote> + <p><tt>% setenv VIDOOM_DIR $HOME/viDOOM</tt><br> + or<br> + <tt>% export VIDOOM_DIR $HOME/viDOOM</tt></p> +</blockquote> + +<p>Whereas in DOS/DJGPP version this could be:</p> + +<blockquote> + <p><tt>C:\> set VIDOOM_DIR=C:\viDOOM</tt></p> +</blockquote> + +<hr> + +<h2><a name="VIDOOM_INI"></a>Initialisation File - VIDOOM.INI</h2> + +<p>On starting viDOOM will look for a file in the current +directory called <strong>vidoom.ini</strong>. 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: </p> + +<p><tt>[Section]<br> +identifier=value<br> +</tt></p> + +<p>Blank lines and lines starting with a comment character (#) +are ignored. The following sections and identifiers are explained +below.</p> + +<ul> + <li><a href="#GAME"><tt>[Game]</tt></a></li> + <li><a href="#EDITOR"><tt>[Editor]</tt></a></li> + <li><a href="#viDOOM"><tt>[viDOOM]</tt></a></li> + <li><a href="#CHECK_LINEDEF"><tt>[Check Linedef]</tt></a></li> + <li><a href="#NODE_BUILDER"><tt>[Node Builder]</tt></a></li> + <li><a href="#GUI"><tt>[GUI]</tt></a></li> + <li><a href="#GAME_NAME"><tt>[</tt><em><tt>Game Name</tt></em><tt>]</tt></a></li> +</ul> + +<p>After reading VIDOOM.INI, then a defined <a +href="#CONFIG_FILE">config file</a> is also read.</p> + +<hr size="1"> + +<h3><a name="GAME"></a>[Game]</h3> + +<p>Controls for the version of DOOM</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><a name="GAME_TYPE"></a><b><tt>game</tt></b></td> + <td valign="top">Use this to say which version of DOOM + you will be editing. The following values are allowed: <ul> + <li><strong>Doom</strong></li> + <li><strong>Ultimate Doom</strong></li> + <li><strong>Doom 2</strong></li> + <li><strong>TNT: Evilution</strong></li> + <li><strong>Plutonia Experiment</strong></li> + <li><strong>ZDoom</strong></li> + </ul> + </td> + </tr> + <tr> + <td><a name="GAME_ASK"></a><strong>ask</strong></td> + <td>If set to <strong>yes</strong> then on starting + viDOOM will ask for the game type to edit.</td> + </tr> +</table> + +<hr size="1"> + +<h3><a name="EDITOR"></a>[Editor]</h3> + +<p>Global editor configuration</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><a name="ASK_MIDDLE_ON_2SIDED"></a><b><tt>ask_middle_on_2sided</tt></b></td> + <td valign="top">When creating a new sector and the + sector has a two-sided boundary asks whether a middle + texture should be asked for. Allowable values <strong>yes</strong> + and <strong>no</strong></td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>auto_block_linedefs</tt></b></td> + <td valign="top">When linedef flags are altered and this + is set to <strong>yes</strong>, linedefs that were + 2-sided and are now 1-sided have the impassible flags + automatically set.<br> + Likewise linedefs that were 1-sided and are now 2-sided + have the impassible flag automatically cleared.<br> + If set to <i>no</i> no action is taken when these events + happen. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>bright</tt></b></td> + <td valign="top">Describes a gamma value applied to any + textures, flats and sprites read in from the DOOM WAD + files. Allowable values are any floating point number.</td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>clear_on_menu</tt></b></td> + <td valign="top">If set to <strong>yes</strong> then once + the pop-up menu has been used to modify the selected + objects they are automatically unselected. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>clear_on_move</tt></b></td> + <td valign="top">If set to <strong>yes</strong> then once + the selected objects have been moved they are + automatically unselected. </td> + </tr> + <tr> + <td valign="top" nowrap><a + name="DEFAULT_SECTOR_LIGHT_ETC"></a><b><tt>default_light_level</tt></b><tt><br> + </tt><b><tt>default_floor_height</tt></b><tt><br> + </tt><b><tt>default_ceiling_height</tt></b></td> + <td valign="top">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.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>default_edit_mode</tt></strong></td> + <td valign="top">Defines the default edit mode when + loading a new map into the editor. Possible values are:<ul> + <li><a href="editing.htm#SECTOR_MODE"><strong>sector</strong></a></li> + <li><a href="editing.htm#LINEDEF_MODE"><strong>linedef</strong></a></li> + <li><a href="editing.htm#THING_MODE"><strong>thing</strong></a></li> + <li><a href="editing.htm#VERTEX_MODE"><strong>vertex</strong></a></li> + <li><a href="editing.htm#MULTI_MODE"><strong>multi</strong></a></li> + </ul> + </td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>default_scale</tt></strong></td> + <td valign="top">The starting scale used in the editor.</td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>grid</tt></b></td> + <td valign="top">Use this to say whether the grid will be + shown on screen while editing. Allowable values are <strong>yes</strong> + and <strong>no</strong>. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>grid_lock</tt></b></td> + <td valign="top">Use this to say whether inserted and + moved object in the editor will be snapped on a grid. + Allowable values are <strong>yes</strong> and <strong>no</strong>. + </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>grid_size</tt></b></td> + <td valign="top">Describes the size of the grid used by + the above items. Allowable values are integer values + greater than two.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="HOVER_SELECT"></a><b><tt>hover_select</tt></b></td> + <td valign="top">When 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: <ul> + <li><strong>none</strong> - nothing is done. The + right mouse button works as expected.</li> + <li><strong>add</strong> - the object the mouse is + over is added to the selected objects before + displaying the menu.</li> + <li><strong>single</strong> - the object the mouse is + over is made the sole selected object before + displaying the menu.</li> + </ul> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="INSERT_SELECT"></a><b><tt>insert_select</tt></b></td> + <td valign="top">When 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: <ul> + <li><strong>none</strong> - nothing is done. The new + object is left unselected.</li> + <li><strong>add</strong> - the new object is added to + the selected objects.</li> + <li><strong>single</strong> - the new object is made + the sole selected object.</li> + </ul> + </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>linedef_select</tt></b></td> + <td valign="top">Defines who many pixels around a LINEDEF + the bounding box stretches when selecting a line.</td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>merge_linedef</tt></b></td> + <td valign="top">If 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: <ul> + <li><strong>always</strong> - always merge the + overlapping linedefs without any prompting.</li> + <li><strong>ask</strong> - confirms with the user + before merging linedefs or not as requested. </li> + <li><strong>never</strong> - never merge overlapping + linedefs. </li> + </ul> + </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>new_2sided_select</tt></b></td> + <td valign="top">When 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: <ul> + <li><strong>select</strong> - clears the currently + selected linedefs (if any) and selects the + linedefs that have new double sides.</li> + <li><strong>ask</strong> - confirms with the user. If + the user opts to select the linedefs, the current + selection is cleared and the altered linedefs + selected.</li> + <li><strong>never</strong> - never select the altered + linedefs. Note that a notice is still displayed + so that you know new left sidedefs have been + created.</li> + </ul> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="SECTOR_MOVE"></a><b><tt>sector_move</tt></b></td> + <td valign="top">Defines which linedefs are actually + moved when moving a sector. Possible values are: <ul> + <li><strong>all</strong> - move all linedefs that + border the sector.</li> + <li><strong>right</strong> - move only linedefs that + have this sector to their right.</li> + <li><strong>left</strong> - move only linedefs that + have this sector to their left.</li> + </ul> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="SHOW_FULL_LINEDEF_INFO"></a><strong><tt>show_full_linedef_info</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> then in + the <a href="editing.htm#LINEDEF_DISPLAY">linedef edit + display</a> the linedef type will be shown as the full + linedef name as defined in the <a href="#LINEDEF_TYPES">config + file</a>. If set to <strong>no</strong> then linedef type + will be displayed as a hex value and it's class.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>tag_highlight</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> then the + tag highlighting mode is enabled by default in sector and + linedef modes.</td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>vertex_radius</tt></b></td> + <td valign="top">Describes 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.</td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>width</tt></b><tt><br> + </tt><b><tt>height</tt></b></td> + <td valign="top">Describes the size of the display used + by viDOOM. viDOOM expects a resolution of at least + 640x480.</td> + </tr> +</table> + +<hr size="1"> + +<h3><a href="#CONFIG_FILE" name="viDOOM"></a>[viDOOM]</h3> + +<p>Main menu configuration</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><b><tt>initial_empty_map</tt></b></td> + <td valign="top">If set to <strong>yes</strong> then on + startup viDOOM will have an empty map, either MAP01 or + E1M1, ready for editing.</td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>load_flats</tt></b></td> + <td valign="top">If set to <b>yes</b> then the graphics + for the flats will be loaded so they can be selected + graphically. If set to <b>no</b> then flats are selected + just using their name. <br> + This is provided as the graphics reading is not very + efficient and can be slow on certain machines. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>load_textures</tt></b></td> + <td valign="top">If set to <b>yes</b> then the graphics + for the textures will be loaded so they can be selected + graphically. If set to <b>no</b> then textures are + selected just using their name. <br> + This is provided as the graphics reading is not very + efficient and can be slow on certain machines. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>load_sprites</tt></b></td> + <td valign="top">If set to <b>yes</b> then the graphics + for the things will be loaded so they can be selected + graphically. If set to <b>no</b> then things are selected + just using their name. <br> + This is provided as the graphics reading is not very + efficient and can be slow on certain machines. </td> + </tr> + <tr> + <td valign="top" nowrap><a name="MAP_CLEAR"></a><b><tt>map_clear_warning</tt></b></td> + <td valign="top">If set to <b>yes</b> 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. </td> + </tr> + <tr> + <td valign="top" nowrap><a name="MAP_EXIT"></a><b><tt>map_exit_warning</tt></b></td> + <td valign="top">If set to <b>yes</b> then a warning is + displayed if exit is chosen and the editor option has + been used. </td> + </tr> + <tr> + <td valign="top" nowrap><a name="OVERWRITE_WARNING"></a><b><tt>overwrite_warning</tt></b></td> + <td valign="top">If set to <b>yes</b> then a warning is + displayed if you save a map over a file that already + exists. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>show_titlepic</tt></b></td> + <td valign="top">If set to <b>yes</b> then the title + picture for the version of DOOM you are editing will be + displayed on the main title screen. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>sort_flat_names</tt></b></td> + <td valign="top">If set to <b>yes</b> then when selecting + ceiling or floor flats they will be sorted into + alphabetical order. If set to <b>no</b> they are simply + in the order they appear in the IWAD file. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>sort_texture_names</tt></b></td> + <td valign="top">If set to <b>yes</b> then when selecting + wall textures they will be sorted into alphabetical + order. If set to <b>no</b> they are simply in the order + they appear in the IWAD file. </td> + </tr> +</table> + +<hr size="1"> + +<h3><a name="CHECK_LINEDEF"></a><strong>[Check LINEDEF]</strong></h3> + +<p>This defines how the <strong>Check LINEDEF</strong> function +in the editor (see <a href="editing.htm#LINEDEF_KEYS">editing</a> +for details) operates. Note that part of the configuration for +this command also occurs in the <a href="#LINEDEF_CHECK_DEFAULT">config +file</a>. This is required as texture names can be different in +different versions of DOOM. The following options are definable +within the INI file:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong><tt>assume_yes</tt></strong></td> + <td valign="top">If this is set to <strong>yes</strong> + 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.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="CHECK_LINE_1SIDE_LOWER"></a><strong><tt>check_1side_lower</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> 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.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="CHECK_LINE_1SIDE_MIDDLE"></a><strong><tt>check_1side_middle</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> 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.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="CHECK_LINE_1SIDE_UPPER"></a><strong><tt>check_1side_upper</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> 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.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="CHECK_LINE_2SIDE_LOWER"></a><strong><tt>check_2side_lower</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> 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.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="CHECK_LINE_2SIDE_MIDDLE"></a><strong><tt>check_2side_middle</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> 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.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="CHECK_LINE_2SIDE_UPPER"></a><strong><tt>check_2side_upper</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> 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.</td> + </tr> + <tr> + <td valign="top" nowrap><a + name="CHECK_LINE_2SIDE_SAME_SECTOR"></a><strong><tt>check_2side_same_sector</tt></strong></td> + <td valign="top">If set to <strong>yes</strong> 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.</td> + </tr> +</table> + +<hr size="1"> + +<h3><a name="NODE_BUILDER"></a>[Node Builder]</h3> + +<p>Node Builder configuration - used to build nodes for maps +automatically when saving.</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><b><tt>always_view_output</tt></b></td> + <td valign="top">Normally viDOOM will only show the + output from the build command if it fails for some + reason. Setting this to <strong>yes</strong> means any + output from the node builder will be displayed + regardless.</td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>command</tt></b></td> + <td valign="top">Defines the command used to execute the + node builder. e.g.<p><tt>command=c:\bsp\bsp.exe</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>ignore</tt></strong></td> + <td valign="top">If 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 <a href="editing.htm#MERGE_MAP">editing</a> + for details) need not be put through the node building + process. e.g. if set to<p><tt>ignore=str</tt></p> + <p>Then saving a map named <strong>MAP01.WAD</strong> + will be passed through the node builder, whereas <strong>WALL_STRUCT.WAD</strong> + would not be.</p> + <p>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.</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>infile</tt></b></td> + <td valign="top">Defines 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.<p><tt>infile=%</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>outfile</tt></b></td> + <td valign="top">Defines 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.<p><tt>outfile=-o %</tt></p> + <p>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 <strong>after</strong> + the % that will get tacked onto the end of the name, e.g.</p> + <p><tt>outfile=-o %_NEW</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>in_before_out</tt></b></td> + <td valign="top">Defines the order of the the arguments + to the node builder. If set to <strong>yes</strong> then + the node builder is invoked as:<p><tt>command infile + outfile</tt></p> + <p>If set to <strong>no</strong> then the command is + built as:</p> + <p><tt>command outfile infile</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>use</tt></b></td> + <td valign="top">If set to <strong>yes</strong> then the + node builder described above is used on any maps being + saved. If set to <strong>no</strong> then the map is + saved and the nodes must be built outside of viDOOM.</td> + </tr> +</table> + +<hr size="1"> + +<h3><a name="GUI"></a>[GUI]</h3> + +<p>GUI configuration. All the values in this section are an RGB +triplet defined as an hex number, i.e. <tt>0xRRGGBB</tt>. The +following values can be set from the INI file.</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong><tt>gui_hi</tt></strong></td> + <td valign="top">The brightest colour used to draw the 3D + looking interface.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>gui_mid</tt></strong></td> + <td valign="top">The medium colour used to draw the 3D + looking interface.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>gui_lo</tt></strong></td> + <td valign="top">The darkest colour used to draw the 3D + looking interface.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>gui_text</tt></strong></td> + <td valign="top">The colour of text.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>gui_textshadow</tt></strong></td> + <td valign="top">The 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 <strong>text</strong> + then no shadows are drawn.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>gui_bold</tt></strong></td> + <td valign="top">The colour of bold text (used for + titles)</td> + </tr> +</table> + +<hr size="1"> + +<h3><a name="GAME_NAME"></a>[<i>Game name</i>]</h3> + +<p>One of these sections appears for each possible setting of the +game variable in the [Game] section. These are:</p> + +<ul> + <li><tt>[Doom]</tt></li> + <li><tt>[Ultimate Doom]</tt></li> + <li><tt>[Doom 2]</tt></li> + <li><tt>[TNT:Evilution]</tt></li> + <li><tt>[Plutonia Experiment]</tt></li> + <li><tt>[ZDoom]</tt></li> +</ul> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><b><tt>iwad</tt></b></td> + <td valign="top">Defines the path to the IWAD for this + game. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>pwad_dir</tt></b></td> + <td valign="top">Defines the default load/save directory + for editing PWAD files. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>level_style</tt></b></td> + <td valign="top">Defines the level naming convention for + the game. Allowable values are: <ul> + <li><b>Doom</b> - allows level names E1M1 to E3M9</li> + <li><b>Ultimate Doom</b> - allows level names E1M1 to + E4M9</li> + <li><b>Doom 2</b> - allows level names MAP01 to MAP32</li> + </ul> + </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>preload</tt></b></td> + <td valign="top">Lists a number of PWAD files to preload + on startup. PWAD files are separated by ; and the full + path is expected. </td> + </tr> + <tr> + <td valign="top" nowrap><b><tt>vidoom_config</tt></b></td> + <td valign="top">Defines the <a href="#CONFIG_FILE">config + file</a> for this version of DOOM. This defines the + values used for defining things, linedefs, sectors and so + on. <br> + viDOOM is currently supplied with <b>doom.cfg</b> and <b>doom2.cfg</b>. + <br> + It is planned to soon include a <b>zdoom.cfg</b> so that + ZDOOM/BOOM special features can be added to levels.</td> + </tr> +</table> + +<hr> + +<h2><a name="CONFIG_FILE"></a>Config file</h2> + +<p>There is two config files supplied with viDOOM, <strong>doom.cfg</strong> +and <strong>doom2.cfg</strong>. Each file is comprised of +sections followed by the data expected in each section. Each +section is defined by a line like:</p> + +<p><tt>%SECTION_NAME</tt></p> + +<p>While the data lines are on individual lines with the pipe (|) +character used to separate fields, e.g.</p> + +<p><tt>Field 1|Field 2</tt></p> + +<p>Blank lines and lines starting with a comment character (#) +are ignored. The following sections are defined:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong><tt>%INCLUDE_FILES</tt></strong></td> + <td valign="top">Defines any other config files to + include before processing this one. Simply type the + filenames to be included on individual lines.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="THING_CLASSES"></a><strong><tt>%THING_CLASSES</tt></strong></td> + <td valign="top">Defines 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.<p><tt>Monster|0xff0000</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="LINEDEF_CLASSES"></a><strong><tt>%LINEDEF_CLASSES</tt></strong></td> + <td valign="top">Defines the classes to group LINEDEF + types into in the editor picklists. Each line is a class + name.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="SECTOR_CLASSES"></a><strong><tt>%SECTOR_CLASSES</tt></strong></td> + <td valign="top">Defines the classes to group SECTOR + types into in the editor picklists. Each line is a class + name.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="THING_TYPES"></a><strong><tt>%THING_TYPES</tt></strong></td> + <td valign="top">Defines the names and IDs of the THINGs + supported by DOOM. Each line is in the form + "Class|Name|ID|Radius|Sprite Name". e.g.<p><tt>Monster|Former + Human|3004|20|POSSA1</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="THING_FLAGS"></a><strong><tt>%THING_FLAGS</tt></strong></td> + <td valign="top">Defines the flags used when defining + THINGs. Each line is in the form "Bit + Number|Name|Shorthand Name". e.g.<p><tt>0|Skill 1 + and 2|Sk 1/2</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="LINEDEF_TYPES"></a><strong><tt>%LINEDEF_TYPES</tt></strong></td> + <td valign="top">Defines the names and IDs of the LINEDEF + types supported by DOOM. Each line is in the form + "Class|ID|Name", e.g.<p><tt>Special|48|Scrolling + wall </tt></p> + <p><strong>Note:</strong> Please note that the text for + the LINEDEF types in the supplied config files is taken + directly from the Unofficial Doom Specs (see the <a + href="thanks.htm#DOOMSPEC">thanks</a> page for details).</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="LINEDEF_FLAGS"></a><strong><tt>%LINEDEF_FLAGS</tt></strong></td> + <td valign="top">Defines the flags used when defining + LINEDEFs. Each line is in the form "Bit + Number|Name|Shorthand Character". e.g.<p><tt>0|Impassible|I</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>%LINEDEF_FLAGS_EXTRA</tt></strong></td> + <td valign="top">Configuration 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.<p><tt>2|0|3|4</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="LINEDEF_DEFAULTS"></a><strong><tt>%LINEDEF_DEFAULTS</tt></strong></td> + <td valign="top">This 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.<p><tt>2-sided + wall|0x47</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="SECTOR_TYPES"></a><strong><tt>%SECTOR_TYPES</tt></strong></td> + <td valign="top">Defines the names and IDs for the + different sector types. Each line is in the form + "Class|ID|Long name|Short name". e.g.<p><tt>Damage/Lights|4|Lose + -10/20% health & blink lights 0.5 sec|-10/20% & + 0.5 blink</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="SECTOR_STYLES"></a><strong><tt>%SECTOR_STYLES</tt></strong></td> + <td valign="top">Defines styles for painting sectors + quickly. The form of each line is + "Mode|Name|Upper|Middle|Lower|Floor|Ceiling". + e.g.<p><tt>0x19|Quarry|SP_ROCK1|SP_ROCK1|SP_ROCK1|RROCK09|F_SKY1</tt></p> + <p>The mode is a bit significant number where the bits + have the following meaning:</p> + <ul> + <li>Bit 0 - Paint textures on the sidedefs facing + into this sector</li> + <li>Bit 1 - Paint textures on the sidedefs facing out + of this sector</li> + <li>Bit 2 - Leave current lower/upper settings</li> + <li>Bit 3 - Set upper unpegged if an upper texture is + painted</li> + <li>Bit 4 - Set lower unpegged if a lower texture is + painted</li> + </ul> + <p>If neither bits 2, 3 or 4 are set it is assumed that + lower/upper unpegged will be cleared on painting those + textures.</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="EMPTY_TEXTURE_NAME"></a><strong><tt>%EMPTY_TEXTURE_NAME</tt></strong></td> + <td valign="top">Simply defines the empty texture name + used by DOOM. This will generally just be the - + character, e.g.<p><tt>%EMPTY_TEXTURE_NAME<br> + -</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="NORMAL_TYPES"></a><strong><tt>%NORMAL_TYPES</tt></strong></td> + <td valign="top">Defines 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.<p><tt>%NORMAL_TYPES<br> + 0|0</tt></p> + </td> + </tr> + <tr> + <td valign="top" nowrap><a name="LINEDEF_CHECK_DEFAULT"></a><strong><tt>%LINEDEF_CHECK_DEFAULT</tt></strong></td> + <td valign="top">Provides 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.<p><tt>%LINEDEF_CHECK_DEFAULT<br> + ASHWALL</tt></p> + <p>See <a href="editing.htm#LINEDEF_KEYS">editing</a> for + details on the check linedef operation.</p> + </td> + </tr> +</table> + +<hr> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: overview.htm,v 1.9 2000/08/13 00:35:59 dosuser Exp dosuser $ </tt></p> +</body> +</html> diff --git a/doc/porting.htm b/doc/porting.htm new file mode 100644 index 0000000..99d3cf1 --- /dev/null +++ b/doc/porting.htm @@ -0,0 +1,1318 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">Porting viDOOM</h1> + +<p>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.</p> + +<ul> + <li><a href="#MAKEFILE">Makefile configuration</a></li> + <li><a href="#INI">INI File</a></li> + <li><a href="#FILES">Files</a></li> + <li><a href="#MAIN">Main entry point</a></li> + <li><a href="#GFX_H">Graphics and input</a></li> + <li><a href="#PLATGUI_H">Platform GUI</a></li> + <li><a href="#FILE_H">File interface</a></li> + <li><a href="#MEM_H">Memory allocation</a></li> + <li><a href="#RUNCMD_H">External command execution</a></li> + <li><a href="#VSTRING_H">String functions</a></li> + <li><a href="#INSTALLATION">Installation script</a></li> + <li><a href="#DOCUMENTATION">Documentation</a></li> +</ul> + +<hr> + +<h2><a name="MAKEFILE"></a>Makefile configuration</h2> + +<p><strong><u>makefile</u></strong></p> + +<p><a name="MAKEPLAT"></a>Set the variable <strong>MAKEPLAT</strong> +to the name of your platform, eg.</p> + +<p><tt>MAKEPLAT=</tt><em><tt>OS</tt></em></p> + +<p>You will then need to create a matching file the <strong>make</strong> +sub directory called <em>OS</em>.cfg. Also all the OS dependent C +source should go into a sub directory defined in the following +make config file by the <strong>PLATFORM</strong> variable. See +the <a href="#FILES">Files</a> section for an overview of these +files.</p> + +<p><a name="MAKE_CONFIG"></a><strong><u>make config file</u></strong></p> + +<p>The following values need to be set in the file <strong>make</strong><em><strong>/OS</strong></em><strong>.cfg</strong>:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong><tt>CC</tt></strong></td> + <td valign="top">Set to the name of the C compiler.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>LD</tt></strong></td> + <td valign="top">The name of the linker.</td> + </tr> + <tr> + <td valign="top" nowrap><a name="PLATFORMVAR"></a><strong><tt>PLATFORM</tt></strong></td> + <td valign="top">The 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).</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>EXE_EXT</tt></strong></td> + <td valign="top">An extension to add to the executable + name, e.g.<br> + <tt>EXE_EXT=.EXE</tt></td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>OBJ_EXT</tt></strong></td> + <td valign="top">The extension used in this OS to denote + object files produced by the C compiler. Generally:<br> + <tt>OBJ_EXT=.o</tt></td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>LIBS</tt></strong></td> + <td valign="top">Any extra libraries to link in with + viDOOM for the OS dependent routines.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>EXRACF</tt></strong></td> + <td valign="top">Any extra C flags required when + compiling the sources. Use it to enable optimisation and + to include any extra include paths required by this OS.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>EXTRALF</tt></strong></td> + <td valign="top">Any extra flags required when linking + viDOOM. Use it to enable include any extra library paths + required by this OS.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>DIRSEP</tt></strong></td> + <td valign="top">The directory separator character for + this OS. The character must be included in quotes, e.g.<font + face="Courier New"><tt><br> + </tt></font><tt>DIRSEP="/"</tt></td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>MATHLIB</tt></strong></td> + <td valign="top">The options required to include the + maths library when linking.</td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>TRACEFORM</tt></strong></td> + <td valign="top">This 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:<br> + <tt>TRACEFORM="%s:%d",__FILE__,__LINE__</tt><p>It + can just be defined to an empty string if you are not + compiling the debug version.</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>EXEFLAG</tt></strong></td> + <td valign="top">The flag to provide to the linker to + generate an executable. The flag is used in a rule + something like this:<br> + <tt>$(LD) $(EXTRALF) $(EXEFLAG) vidoom$(EXE_EXT) + $(ALL+VIDOOM_OBJECTS)</tt></td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>OBJFLAG</tt></strong></td> + <td valign="top">The 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:<br> + <tt>$(CC) $(EXTRACF) $(OBJFLAG) file.c</tt></td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>DEFINEFLAG</tt></strong></td> + <td valign="top">The 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):<br> + <tt>$(CC) $(EXTRACF) $(OBJFLAG) $(DEFINEFLAG)MACRO=value + file.c</tt></td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>INCFLAG</tt></strong></td> + <td valign="top">The 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):<br> + <tt>$(CC) $(EXTRACF) $(OBJFLAG) $(INCFLAG)include_dir + file.c</tt></td> + </tr> + <tr> + <td valign="top" nowrap><strong><tt>MAKEINSTALL</tt></strong></td> + <td valign="top">The command used to execute the <strong>install</strong> + makefile as described in the <a href="#INSTALLATION">installation + script </a>section. The command must define the + INSTALLDIR variable for the makefile and invoke the first + rule in the install makefile.<p>For instance, using a + normal unix/GCC type make command, this would be:<br> + <tt>make INSTALL_DIR='$(INSTALL_DIR)' -f install</tt></p> + </td> + </tr> +</table> + +<hr> + +<h2><a name="INI"></a>INI File</h2> + +<p>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 <em>OS</em> value +you set <a href="#MAKEPLAT">MAKEPLAT</a> to for this platform, +e.g.</p> + +<p><tt>[</tt><em><tt>OS</tt></em><tt>]<br> +guimode=3D</tt></p> + +<hr> + +<h2><a name="FILES"></a>Files</h2> + +<p>The following files are the minimum that must be provided by +the platform:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong>make/</strong><em><strong>OS</strong></em><strong>.cfg</strong></td> + <td valign="top">The make config file. Described in the <a + href="#MAKE_CONFIG">previous section</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>main.c</strong></td> + <td valign="top">This goes in the <a href="#PLATFORMVAR">platform + directory</a> and provides the <a href="#MAIN">startup + code</a> for the operating system.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>gfx.c</strong></td> + <td valign="top">This goes in the <a href="#PLATFORMVAR">platform + directory</a> and provides the <a href="#GFX_H">low level + graphics and input</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>platgui.c</strong></td> + <td valign="top">This goes in the <a href="#PLATFORMVAR">platform + directory</a> and provides the <a href="#PLATGUI_H">system + dependent GUI</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>file.c</strong></td> + <td valign="top">This goes in the <a href="#PLATFORMVAR">platform + directory</a> and provides the portable part of the <a + href="#FILE_H">file system interface</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>mem.c</strong></td> + <td valign="top">This goes in the <a href="#PLATFORMVAR">platform + directory</a> and provides the <a href="#MEM_H">memory + handling</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>runcmd.c</strong></td> + <td valign="top">This goes in the <a href="#PLATFORMVAR">platform + directory</a> and provides the method for <a + href="#RUNCMD_H">running external commands</a>.</td> + </tr> + <tr> + <td><strong>vstring.c</strong></td> + <td>This goes in the <a href="#PLATFORMVAR">platform + directory</a> and provides functions for <a + href="#VSTRING_H">string comparisons</a>.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>install</strong></td> + <td valign="top">This goes in the <a href="#PLATFORMVAR">platform + directory</a> and is the makefile invoked to <a + href="#INSTALLATION">install viDOOM</a>.</td> + </tr> +</table> + +<hr> + +<h2><a name="MAIN"></a>Main entry point</h2> + +<p><strong><u>main.c</u></strong></p> + +<p>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:</p> + +<p><tt>int viDOOM(int argv, char *argv[])</tt></p> + +<p>If the OS uses main() as an entry point the following example +could be enough:</p> + +<pre>int main(int argc,char *argv[]) +{ + return (viDOOM(argc,argv)); +}</pre> + +<hr> + +<h2><a name="GFX_H"></a>Graphics and input</h2> + +<p><strong><u>gfx.c</u></strong></p> + +<p>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:</p> + +<ul> + <li>A true, or hicolor, display.</li> + <li>A Fixed font.</li> + <li>Default origin is in the top left of the display, with X + positive along and Y positive down.</li> + <li>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.</li> + <li>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 <tt>0xRRGGBB</tt>. + Some examples are:<ul type="disc"> + <li><tt>0xFF0000</tt> - Red</li> + <li><tt>0x00FF00</tt> - Green</li> + <li type="disc"><tt>0x0000FF</tt> - Blue</li> + <li><tt>0xFFFFFF</tt> - White</li> + <li><tt>0x808080</tt> - 50% grey</li> + <li><tt>0x000000</tt> - Black</li> + </ul> + </li> +</ul> + +<p>The following types are defined and used by the GFX object :</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><pre>typedef void *GFX_IMAGE; </pre> + </td> + <td valign="top">This is an opaque type provided to allow + the GFX object to provide whatever is required to + reference a bitmap on the machine.</td> + </tr> + <tr> + <td valign="top" nowrap><pre>typedef struct + { + int w; + int h; + int pal[256]; + unsigned char *data; + } GFX_BITMAP; </pre> + </td> + <td valign="top">This type represents the bitmap objects + that viDOOM defines. These bitmaps are converted into + GFX_IMAGE prior to use. The fields are: <table border="0" + cellpadding="3" cellspacing="6"> + <tr> + <td valign="top" nowrap>w</td> + <td valign="top" nowrap>-</td> + <td valign="top">width of bitmap</td> + </tr> + <tr> + <td valign="top" nowrap>h</td> + <td valign="top" nowrap>-</td> + <td valign="top">height of bitmap</td> + </tr> + <tr> + <td valign="top" nowrap>pal[256]</td> + <td valign="top" nowrap>-</td> + <td valign="top">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.</td> + </tr> + <tr> + <td valign="top" nowrap>*data</td> + <td valign="top" nowrap>-</td> + <td valign="top">A pointer to the data of the + bitmap. This should be accessed using pointer + arithmetic as *(data+(x)+(y*w))</td> + </tr> + </table> + </td> + </tr> + <tr> + <td valign="top" nowrap><pre>typedef struct + { + int type; + int shift; + int ctrl; + int alt; + char ascii; + int code; + } GFXKey;</pre> + </td> + <td valign="top">This defines an object for reporting key + presses. The fields are:<table border="0" cellpadding="3" + cellspacing="6"> + <tr> + <td valign="top" nowrap>type</td> + <td valign="top" nowrap>-</td> + <td valign="top">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.</td> + </tr> + <tr> + <td valign="top" nowrap>shift</td> + <td valign="top" nowrap>-</td> + <td valign="top">TRUE if the Shift key is being + pressed.</td> + </tr> + <tr> + <td valign="top" nowrap>ctrl</td> + <td valign="top" nowrap>-</td> + <td valign="top">TRUE if the Control key is being + pressed.</td> + </tr> + <tr> + <td valign="top" nowrap>alt</td> + <td valign="top" nowrap>-</td> + <td valign="top">TRUE if the Alt key is being + pressed.</td> + </tr> + <tr> + <td valign="top" nowrap>ascii</td> + <td valign="top" nowrap>-</td> + <td valign="top">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.</td> + </tr> + <tr> + <td valign="top" nowrap>code</td> + <td valign="top" nowrap>-</td> + <td valign="top">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.</td> + </tr> + </table> + </td> + </tr> + <tr> + <td valign="top" nowrap><pre>typedef struct GFXMouse + { + int type; + int shift; + int ctrl; + int alt; + int x; + int y; + int b; + } GFXMouse;</pre> + </td> + <td valign="top">This defines the type for reporting + mouse movements and button presses. The fields are:<table + border="0" cellpadding="3" cellspacing="6"> + <tr> + <td valign="top" nowrap>type</td> + <td valign="top" nowrap>-</td> + <td valign="top">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.</td> + </tr> + <tr> + <td valign="top" nowrap>shift</td> + <td valign="top" nowrap>-</td> + <td valign="top">TRUE if the Shift key is being + pressed.</td> + </tr> + <tr> + <td valign="top" nowrap>ctrl</td> + <td valign="top" nowrap>-</td> + <td valign="top">TRUE if the Control key is being + pressed.</td> + </tr> + <tr> + <td valign="top" nowrap>alt</td> + <td valign="top" nowrap>-</td> + <td valign="top">TRUE if the Alt key is being + pressed.</td> + </tr> + <tr> + <td valign="top" nowrap>x</td> + <td valign="top" nowrap>-</td> + <td valign="top">The X co-ordinate of the mouse, + relative to the top left of the display.</td> + </tr> + <tr> + <td valign="top" nowrap>y</td> + <td valign="top" nowrap>-</td> + <td valign="top">The Y co-ordinate of the mouse, + relative to the top left of the display.</td> + </tr> + <tr> + <td valign="top" nowrap>b</td> + <td valign="top" nowrap>-</td> + <td valign="top">The currently pressed buttons. + This should be made up of a bit mask composed + from GFX_BUTLEFT, GFX_BUTMIDDLE and GFX_BUTRIGHT.</td> + </tr> + </table> + </td> + </tr> + <tr> + <td valign="top" nowrap><pre>typedef union GFXEvent + { + int type; + GFXKey key; + GFXMouse mouse; + } GFXEvent;</pre> + </td> + <td valign="top">This defines the type for reporting + events (a combination of both mouse movements or key + presses). The fields are:<table border="0" + cellpadding="3" cellspacing="6"> + <tr> + <td valign="top" nowrap>type</td> + <td valign="top" nowrap>-</td> + <td valign="top">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.</td> + </tr> + <tr> + <td valign="top" nowrap>key</td> + <td valign="top" nowrap>-</td> + <td valign="top">The GFXKey structure defining + the event if this is a GFX_KEY_EVENT.</td> + </tr> + <tr> + <td valign="top" nowrap>mouse</td> + <td valign="top" nowrap>-</td> + <td valign="top">The GFXMouse structure defining + the event if this is a GFX_MOUSE_EVENT.</td> + </tr> + </table> + </td> + </tr> +</table> + +<p>The following interfaces must be supplied by the GFX object:</p> + +<p><strong><tt>void GFX_init(void)</tt></strong></p> + +<blockquote> + <p>Initialises the GFX object. No other GFX interfaces are + called prior to this, with the possible (though current not + used) exception of <strong><tt>GFX_exit()</tt></strong>.</p> +</blockquote> + +<p><strong><tt>void GFX_close(void)</tt></strong></p> + +<blockquote> + <p>Called when viDOOM is terminating. Note that other (none + system dependent) processing may go on between calling this + and then invoking <strong><tt>exit()</tt></strong> or <strong><tt>return()</tt></strong>.</p> +</blockquote> + +<p><strong><tt>GFX_IMAGE GFX_create_image(GFX_BITMAP *bm)</tt></strong></p> + +<blockquote> + <p>Should create a GFX_IMAGE from the passed bitmap <em>bm</em>.</p> +</blockquote> + +<p><strong><tt>void GFX_destroy_image(GFX_IMAGE img)</tt></strong></p> + +<blockquote> + <p>Release the bitmap object pointed to by <em>img</em>.</p> +</blockquote> + +<p><strong><tt>void GFX_draw_image(GFX_IMAGE img, int x, int y)</tt></strong></p> + +<blockquote> + <p>Draws <em>img</em> with it's top-left co-ordinate + represented by <em>x,y</em>. This function should implement + any necessary clipping when drawing the bitmap.</p> +</blockquote> + +<p><strong><tt>void GFX_fill_screen(GFX_IMAGE img)</tt></strong></p> + +<blockquote> + <p>Should fill the screen with the image, scaled if + necessary. Note that this call is just used for the menu + backdrop, so if it cannot be honoured no harm will be done.</p> +</blockquote> + +<p><a name="GFX_OPEN"></a><strong><tt>void GFX_open(int width, +int height)</tt></strong></p> + +<blockquote> + <p>Opens the display (or window or whatever) with the + specified <em>width</em> and <em>height</em>. Note that + failures in here should terminate the program.</p> +</blockquote> + +<p><strong><tt>void GFX_clear(int col)</tt></strong></p> + +<blockquote> + <p>This clears the display to the passed colour <em>col</em>.</p> +</blockquote> + +<p><strong><tt>void GFX_redraw(void)</tt></strong></p> + +<blockquote> + <p>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).</p> +</blockquote> + +<p><strong><tt>void GFX_line(int x1, int y1, int x2, int y2, int +col)</tt></strong></p> + +<blockquote> + <p>Draw a line from <em>x1,y1</em> to <em>x2,y2</em> in + colour <em>col</em>.</p> +</blockquote> + +<p><strong><tt>void GFX_plot(int x, int y, int col)</tt></strong></p> + +<blockquote> + <p>Plot the point <em>x,y</em> in colour <em>col</em>.</p> +</blockquote> + +<p><strong><tt>void GFX_circle(int x, int y, int r, int col)<br> +void GFX_fcircle(int x, int y, int r, int col)</tt></strong></p> + +<blockquote> + <p>Draw a circle centred on <em>x,y</em> with a radius <em>r</em> + and in colour <em>col</em>. The <strong>fcircle</strong> + version should draw a filled circle.</p> +</blockquote> + +<p><strong><tt>void GFX_rect(int x, int y, int w, int h, int col)<br> +void GFX_frect(int x, int y, int w, int h, int col)</tt></strong></p> + +<blockquote> + <p>Draw a rectangle with one corner at <em>x,y</em> and the + other corner at <em>(x+w),(y+h)</em> in colour <em>col</em>. + Note that zero length and negative width and heights must be + allowed. The <strong>frect </strong>version should draw a + filled rectangle.</p> +</blockquote> + +<p><strong><tt>void GFX_set_XOR_mode(void)<br> +void GFX_clear_XOR_mode(void)</tt></strong></p> + +<blockquote> + <p>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.</p> +</blockquote> + +<p><strong><tt>void GFX_print(int x, int y, int col, char *fmt, +...)</tt></strong></p> + +<blockquote> + <p>Print the printf style arguments (<em>fmt</em> and <em>...</em>) + with their top left corner at <em>x,y</em> in colour <em>col</em>. + Note that text should rendered transparently.</p> +</blockquote> + +<p><strong><tt>int GFX_fh(void)<br> +int GFX_fw(void)</tt></strong></p> + +<blockquote> + <p>Return the height (GFX_fh) and width (GFX_fw) of the fixed + width font used for display purposes.</p> +</blockquote> + +<p><strong><tt>int GFX_mouse_buttons(void)</tt></strong></p> + +<blockquote> + <p>Returns the number of mouse buttons. This is just used as + check on initialisation as viDOOM expects at least 2 mouse + buttons.</p> +</blockquote> + +<p><strong><tt>int GFX_mouse(int *x, int *y)</tt></strong></p> + +<blockquote> + <p>Return the current point position in <em>x</em> and <em>y</em>. + If any of the passed pointers are NULL that variable should + be ignored.</p> +</blockquote> + +<p><strong><tt>void GFX_waitkey(GFXKEy *key)</tt></strong></p> + +<blockquote> + <p>Waits for a <em>key</em> to be pressed and returns the key + press in <em>key</em>. If <em>key</em> is NULL simply wait + for a key press.</p> +</blockquote> + +<p><strong><tt>int GFX_key(GFXKey *key)</tt></strong></p> + +<blockquote> + <p>Returns TRUE if a key has been pressed and returns the + keypress in <em>key</em>. Returns FALSE if there is no + outstanding keypresses, in which case the contents of <em>key</em> + are undefined.</p> +</blockquote> + +<p><strong><tt>void GFX_bounce(void)</tt></strong></p> + +<blockquote> + <p>Waits for all keys and mouse buttons to be released. On a + real event-driven system could be ignored, or flush any + outstanding events.</p> +</blockquote> + +<p><strong><tt>void GFX_await_input(GFXEvent *ev)</tt></strong></p> + +<blockquote> + <p>Waits for either a keypress or a mouse button to be + pressed and fills in <em>ev</em> accordingly.</p> +</blockquote> + +<p><strong><tt>void GFX_await_input_full(GFXEvent *ev)</tt></strong></p> + +<blockquote> + <p>Waits for either a keypress, a mouse button to be pressed + or the mouse to be moved and fills in <em>ev</em> + accordingly.</p> +</blockquote> + +<p><strong><tt>void GFX_exit(int code, char *fmt, ...)</tt></strong></p> + +<blockquote> + <p>This call should do any necessary tidying of the display + (switching from graphics mode, closing windows, whatever) + then display the printf style arguments (<em>fmt</em> and <em>...</em>) + and the exit with the passed return <em>code</em>.</p> +</blockquote> + +<p><strong><tt>void GFX_save_screen(char *path)</tt></strong></p> + +<blockquote> + <p>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 <em>path</em>.</p> +</blockquote> + +<hr> + +<h2><a name="PLATGUI_H"></a>Platform GUI</h2> + +<p><strong><u>platgui.c</u></strong></p> + +<p>This provides access to the platform's GUI routines.</p> + +<p>The following types are defined and used by the PLATGUI object +:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><pre>typedef struct + { + char *text; + GFX_IMAGE img; + int client_index; + } PLAT_IMG_PICKLIST;</pre> + </td> + <td valign="top">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.<p>The + fields in the structure are:</p> + <table border="0" cellpadding="3" cellspacing="6"> + <tr> + <td valign="top" nowrap>text</td> + <td valign="top" nowrap>-</td> + <td valign="top">This defines the text for a + picklist entry. NULL marks the end of the list of + picklist entries.</td> + </tr> + <tr> + <td valign="top" nowrap>img</td> + <td valign="top" nowrap>-</td> + <td valign="top">The GFX_IMAGE to associate with + this entry. Can be NULL to indicate show no + image.</td> + </tr> + <tr> + <td valign="top" nowrap>client_index</td> + <td valign="top" nowrap>-</td> + <td valign="top">The value returned if this item + is selected.</td> + </tr> + </table> + </td> + </tr> + <tr> + <td valign="top" nowrap><pre>typedef struct + { + char *text; + int client_index; + } PLAT_PICKLIST;</pre> + </td> + <td valign="top">This structure is used to define a + picklist that has client defined values attached to the + entries.<p>The fields in the structure are:</p> + <table border="0" cellpadding="3" cellspacing="6"> + <tr> + <td valign="top" nowrap>text</td> + <td valign="top" nowrap>-</td> + <td valign="top">This defines the text for a + picklist entry. NULL marks the end of the list of + picklist entries.</td> + </tr> + <tr> + <td valign="top" nowrap>client_index</td> + <td valign="top" nowrap>-</td> + <td valign="top">The value returned if this item + is selected.</td> + </tr> + </table> + </td> + </tr> + <tr> + <td valign="top" nowrap><pre>typedef struct + { + char *text; + int client_index; + } PLAT_MENU;</pre> + </td> + <td valign="top">This structure is used to define menu + entries that have client defined values attached to them.<p>The + fields in the structure are:</p> + <table border="0" cellpadding="3" cellspacing="6"> + <tr> + <td valign="top" nowrap>text</td> + <td valign="top" nowrap>-</td> + <td valign="top">This defines the text for the + menu entry. NULL marks the end of the list of + menu entries.</td> + </tr> + <tr> + <td valign="top" nowrap>client_index</td> + <td valign="top" nowrap>-</td> + <td valign="top">The value returned if this item + is selected.</td> + </tr> + </table> + </td> + </tr> + <tr> + <td valign="top" nowrap><pre>typedef struct + { + char *text; + int client_index; + } PLAT_RADIO;</pre> + </td> + <td valign="top">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.<p>The fields in the structure are:</p> + <table border="0" cellpadding="3" cellspacing="6"> + <tr> + <td valign="top" nowrap>text</td> + <td valign="top" nowrap>-</td> + <td valign="top">This defines the text for the + radio button. NULL marks the end of the list of + radio button entries.</td> + </tr> + <tr> + <td valign="top" nowrap>client_index</td> + <td valign="top" nowrap>-</td> + <td valign="top">The value returned if this item + is selected.</td> + </tr> + </table> + </td> + </tr> + <tr> + <td valign="top" nowrap><pre>typedef struct + { + char *text; + int type; + union /* Data */ + { + int i; + char s[PLAT_DIAL_MAXSTRLEN+1]; + double d; + } data; + } PLAT_DIALOG;</pre> + </td> + <td valign="top">This structure is used to define entries + for a simple dialog.<p>The fields in the structure are:</p> + <table border="0" cellpadding="3" cellspacing="6"> + <tr> + <td valign="top" nowrap>text</td> + <td valign="top" nowrap>-</td> + <td valign="top">This defines the text for this + field in the dialog. NULL marks the end of the + list of dialog entries.</td> + </tr> + <tr> + <td valign="top" nowrap>type</td> + <td valign="top" nowrap>-</td> + <td valign="top">The type of field this is. + Possible values are PLAT_DIAL_STRING, + PLAT_DIAL_INTEGER and PLAT_DIAL_DOUBLE.</td> + </tr> + <tr> + <td valign="top" nowrap>data.i</td> + <td valign="top" nowrap>-</td> + <td valign="top">This is the field that is + displayed and updated on exit if the type is + PLAT_DIAL_INTEGER.</td> + </tr> + <tr> + <td valign="top" nowrap>data.s</td> + <td valign="top" nowrap>-</td> + <td valign="top">This is the field that is + displayed and updated on exit if the type is + PLAT_DIAL_STRING.</td> + </tr> + <tr> + <td valign="top" nowrap>data.d</td> + <td valign="top" nowrap>-</td> + <td valign="top">This is the field that is + displayed and updated on exit if the type is + PLAT_DIAL_DOUBLE.</td> + </tr> + </table> + </td> + </tr> +</table> + +<p>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 <strong><tt>GUI_setscreen()</tt></strong>:</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><strong>GUI_HI</strong></td> + <td valign="top">The brightest colour used to draw the 3D + looking interface.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>GUI_MID</strong></td> + <td valign="top">The medium colour used to draw the 3D + looking interface.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>GUI_LO</strong></td> + <td valign="top">The darkest colour used to draw the 3D + looking interface.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>GUI_TEXT</strong></td> + <td valign="top">The colour of text.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>GUI_TEXTSHADOW</strong></td> + <td valign="top">The colour of the shadow behind text. + This is only really used by viDOOM's own portable GUI + routines.</td> + </tr> + <tr> + <td valign="top" nowrap><strong>GUI_BOLD</strong></td> + <td valign="top">The colour of bold text (used for + titles).</td> + </tr> +</table> + +<h3>Functions</h3> + +<p>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):</p> + +<p><strong><tt>void GUI_setscreen(int width, int height)</tt></strong></p> + +<blockquote> + <p>Once the display has been opened with <a href="#GFX_OPEN"><strong>GFX_open()</strong></a> + then this is called to inform the platform's GUI routines of + the display size.</p> +</blockquote> + +<p><strong><tt>int GUI_yesno(char *question)</tt></strong></p> + +<blockquote> + <p>Display an alert with <em>question</em> in it and <em>Yes</em> + and <em>No</em> buttons. Returns TRUE if <em>Yes</em> is + pressed and FALSE if <em>No</em> is pressed.</p> +</blockquote> + +<p><strong><tt>int GUI_menu(char *title, int x, int y, PLAT_MENU +menu[], int defval)</tt></strong></p> + +<blockquote> + <p>Displays a menu with title <em>title</em> at position <em>x,y</em>. + The displayed items are taken from <em>menu</em>. The return + is the client_index field from the selected menu item, or <em>defval</em> + if the menu is cancelled.</p> +</blockquote> + +<p><strong><tt>char *GUI_fsel(char *title, char *default_path, +char filter)</tt></strong></p> + +<blockquote> + <p>Allows a file to be selected. The file selector should + have <em>title</em> for it's title and start selecting from + the <em>default_path</em>. If <em>filter </em>is NULL then + all files should be displayed, otherwise only files ending in + <em>filter</em>.</p> + <p>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 <a href="#FRELEASE"><strong>FRelease()</strong></a>.</p> +</blockquote> + +<p><strong><tt>int GUI_picklist(char *title, char *opts[])</tt></strong></p> + +<blockquote> + <p>Displays a picklist with title <em>title</em>. The options + are taken from the array of character pointers <em>opts</em>. + The return value is the index of the selected item in <em>opts</em> + if selected, or -1 if the picklist is cancelled.</p> +</blockquote> + +<p><strong><tt>int GUI_client_picklist(char *title, PLAT_PICKLIST +opts[], int defval)</tt></strong></p> + +<blockquote> + <p>Displays a picklist with title <em>title</em>. The text + items to display are taken from <em>opts</em>. The return is + the client_index field from the selected picklist item, or <em>defval</em> + if the picklist is cancelled.</p> +</blockquote> + +<p><strong><tt>int GUI_image_picklist(char *title, +PLAT_IMG_PICKLIST opts[], int defval)</tt></strong></p> + +<blockquote> + <p>Displays a picklist with title <em>title</em>. The text + items and associated image to display are taken from <em>opts</em>. + The return is the client_index field from the selected + picklist item, or <em>defval</em> if the picklist is + cancelled.</p> +</blockquote> + +<p><strong><tt>int GUI_radio_box(char *title, PLAT_RADIO opts[], +int current, int defval)</tt></strong></p> + +<blockquote> + <p>Displays a dialog containing radio buttons with title <em>title</em>. + The text to display is taken from <em>opts</em>. The selected + object when the the radio box is first displayed is the + option who's client_index field matches <em>current</em> (or + the first item if there is no match). The return is the + client_index field from the selected radio button, or <em>defval</em> + if the radio box is cancelled.</p> +</blockquote> + +<p><strong><tt>int GUI_multi_box(char *title, char *opts[], int +*val)</tt></strong></p> + +<blockquote> + <p>Display a mutli-selection radio box. The items are + described <em>opts</em>, which terminates with a NULL + pointer. <em>Val</em> points to a value which is used to + enable/disable the options dependent on the integers bit + setting. The integer pointed to by <em>val</em> is updated on + exit of the multi-selection box if it is not cancelled.</p> + <p>Note that the bit patterns are matched bit number to opt + index. ie.</p> + <ul> + <li>val & 0x0001 corresponds to opts[0]</li> + <li>val & 0x0002 corresponds to opts[1] ...</li> + <li>val & 0x0010 corresponds to opts[4] ...</li> + <li>val & 0x0100 corresponds to opts[8] ...</li> + <li>val & 0x8000 corresponds to opts[15]</li> + </ul> + <p>A maximum of 16 bits should be all that needs supporting + currently. The return is TRUE if the dialog is accepted, + otherwise FALSE.</p> +</blockquote> + +<p><strong><tt>int GUI_dialog(char *title, int no, PLAT_DIALOG +dial[])</tt></strong></p> + +<blockquote> + <p>Displays a dialog with the title <em>title</em>. The + fields for the dialog are extracted from <em>dial</em>, for + which there is expected to be <em>no</em> 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 <em>dial</em> elements is undefined.</p> +</blockquote> + +<hr> + +<h2><a name="FILE_H"></a>File interface</h2> + +<p><strong><u>file.c</u></strong></p> + +<p>This provides access to various file system functions and also +provides some filename manipulation routines. The following +interfaces should be provided:</p> + +<p><strong><tt>char *Pwd(void)</tt></strong></p> + +<blockquote> + <p>This call should return the current working directory. The + return should be static.</p> +</blockquote> + +<p><strong><tt>void Cd(char *path)</tt></strong></p> + +<blockquote> + <p>This call should change the current working directory to <em>path</em>.</p> +</blockquote> + +<p><strong><tt>char *Dirname(char *path)</tt></strong></p> + +<blockquote> + <p>This call should return the directory part of <em>path</em> + if any. The return should be static.</p> +</blockquote> + +<p><strong><tt>char *Basename(char *path)</tt></strong></p> + +<blockquote> + <p>This call should return the filename part of <em>path</em>. + The return should be static, or a pointer into the <em>path</em> + parameter.</p> +</blockquote> + +<p><strong><tt>int FileExists(char *path)</tt></strong></p> + +<blockquote> + <p>This call should return TRUE if the file pointed to by <em>path</em> + exists.</p> +</blockquote> + +<p><strong><tt>int FilenamesEqual(char *path1, char *path2)</tt></strong></p> + +<blockquote> + <p>This call should return TRUE if the file pointed to by <em>path1</em> + and <em>path2</em> 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 <strong>strcasecmp()</strong> + on the paths.</p> +</blockquote> + +<hr> + +<h2><a name="MEM_H"></a>Memory allocation</h2> + +<p><strong><u>mem.c</u></strong></p> + +<p>This provides memory allocation. While memory allocation can +generally be done portably using <tt>malloc()</tt> providing this +library just covers for any possible OS dependent twist. Also +these routines are expected to handle errors internally. In all +the interfaces <em>file</em> and <em>line</em> parameters are +included so that errors can be reported more accurately.</p> + +<p>The following interfaces should be provided:</p> + +<p><strong><tt>void *FGrab (char *file, int line, int len)</tt></strong></p> + +<blockquote> + <p>This call should allocate <em>len</em> bytes and return a + pointer to it. A <em>len</em> of zero is valid. Memory should + be initialised to zero. Failure to allocate the memory should + terminate the program.</p> +</blockquote> + +<p><strong><tt>void *FReGrab (char *file, int line, void *ptr, +int len)</tt></strong></p> + +<blockquote> + <p>This call should re-allocate the memory pointed to by <em>ptr</em> + and return a new memory area of <em>len</em> bytes. The + original data pointed to by <em>ptr</em> should be copied to + the new memory area. Failure to allocate the memory should + terminate the program.</p> +</blockquote> + +<p><strong><tt>char *FStrdup (char *file, int line, char *str)</tt></strong></p> + +<blockquote> + <p>This call should allocate enough bytes to copy the nul + terminated <em>str</em> to it. The returned pointer should + point to the new copy of <em>str</em>.<em> </em>Failure to + allocate the memory should terminate the program.</p> +</blockquote> + +<p><strong><tt>void *FCopy (char *file, int line, void *ptr, int +len)</tt></strong></p> + +<blockquote> + <p>This call should allocate <em>len</em> bytes and copy <em>len</em> + bytes from <em>ptr</em> into the new area. The newly + allocated memory should be returned. Failure to allocate the + memory should terminate the program.</p> +</blockquote> + +<p><a name="FRELEASE"></a><strong><tt>void FRelease (char *file, +int line, void *ptr)</tt></strong></p> + +<blockquote> + <p>This call should release the memory pointed to by <em>ptr</em>, + which will have been allocated by FGrab, FReGrab, FStrdup or + FCopy.</p> +</blockquote> + +<hr> + +<h2><a name="RUNCMD_H"></a>External command execution</h2> + +<p><strong><u>runcmd.c</u></strong></p> + +<p>Provides a mechanism to run an external command. The following +interfaces should be provided:</p> + +<p><strong><tt>int RunCommand(char *argv[], char *path)</tt></strong></p> + +<blockquote> + <p>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.</p> + <p>The <em>argv</em> 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.</p> + <p><tt>argv[0]="bsp"<br> + argv[1]="file.wad"<br> + argv[2]="-o file.wad"<br> + argv[3]=NULL</tt></p> + <p>The <em>path</em> 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 <tt>remove()</tt> the file after + it has read it.</p> +</blockquote> + +<hr> + +<h2><a name="VSTRING_H"></a>Portable String routines</h2> + +<p><strong><u>vstring.c</u></strong></p> + +<p>Provides common string functions that are not actually part of +the ANSI standard:</p> + +<p><strong><tt>int StrCaseCmp(char *a, char *b)</tt></strong></p> + +<blockquote> + <p>Performs in exactly the same way as the ANSI <tt>strcmp()</tt> + function, save for the fact that the case of the strings + being compared is ignored.</p> +</blockquote> + +<p><strong><tt>int StrNCaseCmp(char *a, char *b)</tt></strong></p> + +<blockquote> + <p>Performs in exactly the same way as the ANSI <tt>strncmp()</tt> + function, save for the fact that the case of the strings + being compared is ignored.</p> +</blockquote> + +<hr> + +<h2><a name="INSTALLATION"></a>Installation script</h2> + +<p>Each platform should provide a makefile called <strong>install</strong>. +This is invoked from the top level makefile like this:</p> + +<blockquote> + <p><tt>cd $(PLATFORM) ; $(MAKEINSTALL)</tt></p> +</blockquote> + +<p>Note that the install makefile will be invoked with the <a +href="#PLATFORMVAR">PLATFORM</a> directory as the current working +directory.</p> + +<p>The following files must be copied (where $SRC represents +the source build directory and $INSTALLDIR the install +directory):</p> + +<table border="1" cellpadding="3"> + <tr> + <td valign="top" nowrap><tt>$SRC/vidoom</tt></td> + <td valign="top"><tt>$INSTALLDIR/vidoom</tt><p>Note that + this file may have a system specific extension (e.g. .EXE + in DOS)</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><tt>$SRC/LICENSE</tt></td> + <td valign="top"><tt>$INSTALLDIR/LICENSE</tt><p>The GNU + GPL should be copied into the installation directory so that + binary distributions can be easily generated with the license + included.</p> + </td> + </tr> + <tr> + <td valign="top" nowrap><tt>$SRC/base.ini</tt></td> + <td valign="top"><tt>$INSTALLDIR/vidoom.ini</tt></td> + </tr> + <tr> + <td valign="top" nowrap><tt>$SRC/*.cfg</tt></td> + <td valign="top"><tt>$INSTALLDIR/*.cfg</tt></td> + </tr> + <tr> + <td valign="top" nowrap><tt>$SRC/doc/*.htm</tt></td> + <td valign="top"><tt>$INSTALLDIR/doc/*.htm</tt></td> + </tr> + <tr> + <td valign="top" nowrap><tt>$SRC/doc/*.png</tt></td> + <td valign="top"><tt>$INSTALLDIR/doc/*.png</tt></td> + </tr> +</table> + +<p>Note that, obviously, any OS specific files should also be copied.</p> + +<hr> + +<h2><a name="DOCUMENTATION"></a>Documentation</h2> + +<p>If you release a port of viDOOM to any platform please update <a +href="bugs.htm#CONTACTS">doc/bugs.htm</a> with a contact address +for problems on that platform.</p> + +<hr> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: porting.htm,v 1.19 2000/08/13 00:46:22 dosuser Exp dosuser $</tt></p> +</body> +</html> diff --git a/doc/thanks.htm b/doc/thanks.htm new file mode 100644 index 0000000..aae404f --- /dev/null +++ b/doc/thanks.htm @@ -0,0 +1,70 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>viDOOM - Free Software DOOM editor</title> +</head> + +<body> + +<h1 align="center">Acknowledgements and Thanks</h1> + +<p>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. </p> + +<p><b><i>Doom - </i></b><a href="http://www.idsoftware.com"><b>id +Software</b></a><br> +Creators of DOOM, who thankfully wrote a terribly nice game and +then made it even nicer by making the WAD format simple and open. +</p> + +<p><a name="DOOMSPEC"></a><b><i>Unofficial Doom Specs -</i></b> <a +href="mailto:msfell@aol.com"><b>Matthew S Fell</b></a><br> +Writer and maintainer of the <a +href="http://doomgate.gamers.org/dhs/helpdocs/dmsp1666.html">Unofficial +DOOM Specs</a>. viDOOM would have been impossible without this +marvellous tome.</p> + +<p><a name="BSP"></a><b><i>BSP -</i></b> <b>Colin Reed/ </b><a +href="mailto:killough@classicgaming.com"><b>Lee Killough</b></a><br> +Developers of the BSP node builder. Without this viDOOM is +completely useless. </p> + +<p><b><i>Maths help -</i></b> <a +href="mailto:matthew@mjwilson.demon.co.uk"><b>Mathew Wilson</b></a><br> +Someone who knows much more maths than I ever will and writer of +the LinesCross() algorithm - saviour of the LINEDEF selection +code.</p> + +<p><em><strong>More maths help - </strong></em><a +href="http://www.faqs.org/faqs/graphics/algorithms-faq/"><strong>comp.graphics.algorithms +FAQ</strong></a><br> +Provided a much better 'is a point in a polygon?' than my +original one ever was...</p> + +<p><b><i>Music -</i></b> <a +href="http://www.c64audio.com/c64audio.asp"><b>C64 Audio</b></a><br> +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. </p> + +<p><b><i>VIM -</i></b> <a href="http://www.vim.org/"><b>Various +authors</b></a><br> +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... </p> + +<p> </p> + +<hr width="99%"> + +<p><a href="index.htm">Back to index</a></p> + +<p><tt>$Id: thanks.htm,v 1.5 2000/08/13 00:35:59 dosuser Exp dosuser $ </tt></p> +</body> +</html> diff --git a/doom.cfg b/doom.cfg new file mode 100644 index 0000000..2f7c71d --- /dev/null +++ b/doom.cfg @@ -0,0 +1,527 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# +# $Id: doom.cfg,v 1.26 2000/07/19 16:36:12 dosuser Exp dosuser $ +# +# Doom config file. The following sections may be present: +# +# %INCLUDE_FILES - include other config files +# %THING_CLASSES - classes of things (ammo, monsters, etc) +# %LINEDEF_CLASSES - classes of linedefs +# %SECTOR_CLASSES - classes of sectors +# %THING_TYPES - details types and IDs of things +# %THING_FLAGS - details flags and meaning for things +# %LINEDEF_FLAGS - details flags and meaning for linedefs +# %LINEDEF_FLAGS_EXTRA - details which flags indicate certain features +# %LINEDEF_TYPES - details types and IDs for linedefs +# %LINEDEF_DEFAULTS - default types for linedefs +# %SECTOR_STYLES - define texturing styles for linedefs +# %SECTOR_TYPES - details types and IDs of sectors +# %EMPTY_TEXTURE_NAME - name used for the empty texture +# %NORMAL_TYPES - values for normal sectors and linedefs +# %LINEDEF_CHECK_DEFAULT - optional textuire to use filling in missing +# textures when performing check linedefs +# + + +# THING_CLASSES +# +# Classes of things. Format is "class name|colour" +# +# Colour is defined as a hex number, each byte either R, G or B - 0xRRGGBB +# +# +%THING_CLASSES +Ammo|0x808000 +Dead Things|0x800000 +Health Items|0x00a000 +Other Items|0xa0a000 +Keys|0x00a0a0 +Monster|0xd01010 +Player Start|0xa000a0 +Scenery|0xa22a2a +Teleport|0x00a000 +Weapon|0xa0a000 + + +# LINEDEF_CLASSES +# +# Classes of linedefs. Format is "class name" +# +# +%LINEDEF_CLASSES +Normal +Local door +Remote door +Ceiling +Lift +Floor +Stair +Moving floor +Crushing ceiling +Exit level +Teleport +Light effect +Special + + +# SECTOR_CLASSES +# +# Classes of sectors. Format is "class name" +# +# +%SECTOR_CLASSES +Normal +Lights +Damage +Damage/Lights +Damage/Exit +Door +Secret + + +# THING_TYPES section. Each lines is "class|name|id|radius|sprite_name" +# +# Where class is a class from the %THING_CLASSES section +# +# sprite_name can be "-" to incidate no graphics +# +%THING_TYPES +Ammo|Ammo clip|2007|20|CLIPA0 +Ammo|Shotgun shells|2008|20|SHELA0 +Ammo|A rocket|2010|20|ROCKA0 +Ammo|Cell charge|2047|20|CELLA0 +Ammo|Box of ammo|2048|20|AMMOA0 +Ammo|Box of shells|2049|20|SBOXA0 +Ammo|Box of rockets|2046|20|BROKA0 +Ammo|Big cell charge|17|20|CELPA0 +Ammo|Backpack|8|20|BPAKA0 + +Dead Things|Exploded player|10|20|PLAYW0 +Dead Things|Bloody mess|12|20|PLAYW0 +Dead Things|Pool of blood and flesh|24|20|POL5A0 +Dead Things|Dead player|15|20|PLAYW0 +Dead Things|Dead former human|18|20|POSSU0 +Dead Things|Dead sergeant|19|20|SPOSU0 +Dead Things|Dead imp|20|20|TROOU0 +Dead Things|Dead demon|21|20|SARGN0 +Dead Things|Dead cacodemon|22|20|HEADL0 +Dead Things|Dead lost soul|23|20|SKULJ0 + +Health Items|Stimpak|2011|20|STIMA0 +Health Items|Medikit|2012|20|MEDIA0 +Health Items|Health potion|2014|20|BON1A0 +Health Items|Spirt armour|2015|20|BON2A0 +Health Items|Green armour|2018|20|ARM1A0 +Health Items|Blue armour|2019|20|ARM2A0 +Health Items|Soulsphere|2013|20|SOULA0 +Health Items|Berserk|2023|20|PSTRA0 + +Other Items|Invulnerable|2022|20|PINVA0 +Other Items|Invisibility|2024|20|PINSA0 +Other Items|Radiation suit|2025|20|SUITA0 +Other Items|Map|2026|20|PMAPA0 +Other Items|Light amplification goggles|2045|20|PVISA0 + +Keys|Blue keycard|5|20|BKEYA0 +Keys|Blue skullkey|40|20|BSKUA0 +Keys|Red keycard|13|20|RKEYA0 +Keys|Red skullkey|38|20|RSKUA0 +Keys|Yellow keycard|6|20|YKEYA0 +Keys|Yellow skullkey|39|20|YSKUA0 + +Monster|Former Human|3004|20|POSSA1 +Monster|Former Sergeant|9|20|SPOSA1 +Monster|Imp|3001|20|TROOA1 +Monster|Demon|3002|30|SARGA1 +Monster|Spectre|58|30|SARGA1 +Monster|Lost soul|3006|16|SKULA1 +Monster|Cacodemon|3005|31|HEADA1 +Monster|Baron of Hell|3003|24|BOSSA1 +Monster|Spider Mastermind|7|128|SPIDA1D1 +Monster|Cyberdemon|16|40|CYBRA1 +Monster|Barrel|2035|16|BAR1A0 + +Player Start|Player 1 start|1|16|PLAYA1 +Player Start|Player 2 start|2|16|PLAYA1 +Player Start|Player 3 start|3|16|PLAYA1 +Player Start|Player 4 start|4|16|PLAYA1 +Player Start|Deatchmatch start|11|16|PLAYA1 + +Scenery|Tall techno pillar|48|16|ELECA0 +Scenery|Tall green pillar|30|16|COL1A0 +Scenery|Tall red pillar|32|16|COL3A0 +Scenery|Short green pillar|31|16|COL2A0 +Scenery|Short green pillar with beating heart|36|16|COL5A0 +Scenery|Short red pillar|33|16|COL4A0 +Scenery|Short red pillar with skull|37|16|COL6A0 +Scenery|Small brown pointy stump|47|16|SMITA0 +Scenery|Gray tree|43|16|TRE1A0 +Scenery|Large brown tree|54|32|TRE2A0 +Scenery|Floor lamp|2028|16|COLUA0 +Scenery|Candle|34|16|CANDA0 +Scenery|Candelabra|35|16|CBRAA0 +Scenery|Tall blue firestick|44|16|TBLUA0 +Scenery|Tall green firestick|45|16|TGRNA0 +Scenery|Tall red firestick|46|16|TREDA0 +Scenery|Short blue firestick|55|16|SMBTA0 +Scenery|Short green firestick|56|16|SMGTA0 +Scenery|Short red firestick|57|16|SMRTA0 +Scenery|Evil Eye|41|16|CEYEA0 +Scenery|Flaming skull rock|42|16|FSKUA0 + +Scenery|Hanging victim, twitching|49|16|GOR1A0 +Scenery|Hanging victim, twitching (let thru)|63|16|GOR1A0 +Scenery|Hanging victim, arms out|50|16|GOR2A0 +Scenery|Hanging victim, arms out (let thru)|59|16|GOR2A0 +Scenery|Hanging pair of legs|52|16|GOR4A0 +Scenery|Hanging pair of legs (let thru)|60|16|GOR4A0 +Scenery|Hanging victim, 1-legged|51|16|GOR3A0 +Scenery|Hanging victim, 1-legged (let thru)|61|16|GOR3A0 +Scenery|Hanging leg|53|16|GOR5A0 +Scenery|Hanging leg (let thru)|62|16|GOR5A0 + +Scenery|Impaled human|25|16|POL1A0 +Scenery|Twitching impaled human|26|16|POL6A0 +Scenery|Skull on a pole|27|16|POL4A0 +Scenery|Skewerd skulls|28|16|POL2A0 +Scenery|Pile of skulls and candles|29|16|POL3A0 + +Teleport|Teleport landing|14|16|TFOGA0 + +Weapon|Chainsaw|2005|20|CSAWA0 +Weapon|Shotgun|2001|20|SHOTA0 +Weapon|Chaingun|2002|20|MGUNA0 +Weapon|Rocket launcher|2003|20|LAUNA0 +Weapon|Plasma gun|2004|20|PLASA0 +Weapon|BFG 9000|2006|20|BFUGA0 + + +# THING_FLAGS section. Each line is "bit number|name|short hand name" +# +# Note there can be no gaps in the bit numbers. If there are bits that +# don't matter they must still defined, eg. +# 0|Bit 0 +# 1|Unused +# 2|Bit 2 +# +%THING_FLAGS +0|Skill 1 and 2|Sk 1/2 +1|Skill 3|Sk 3 +2|Skill 4 and 5|Sk 4/5 +3|Deaf|Deaf +4|Deathmatch only|Deathmatch + + +# LINEDEF_TYPES section. Each line is "class|id|name" +# +# Class is one of the classes from %LINEDEF_CLASSES +# +%LINEDEF_TYPES +Normal|0|Normal + +Special|48|Scrolling wall + +Local door|1|SRm door med 4 - open/close +Local door|26|SR door med 4 - open/close BLUE KEY +Local door|28|SR door med 4 - open/close RED KEY +Local door|27|SR door med 4 - open/close YELLOW KEY +Local door|31|S1 door med - - open +Local door|32|S1 door med - - open BLUE KEY +Local door|33|S1 door med - - open RED KEY +Local door|34|S1 door med - - open YELLOW KEY +Local door|46|GR door med - - open +Local door|117|SR blaze turbo 4 - open/close +Local door|118|S1 blaze turbo - - open + +Remote door|4|W1 door med 4 - open,close +Remote door|29|S1 door med 4 - open,close +Remote door|90|WR door med 4 - open,close +Remote door|63|SR door med 4 - open,close +Remote door|2|W1 door med - - open +Remote door|103|S1 door med - - open +Remote door|86|WR door med - - open +Remote door|61|SR door med - - open +Remote door|3|W1 door med - - close +Remote door|50|S1 door med - - close +Remote door|75|WR door med - - close +Remote door|42|SR door med - - close +Remote door|16|W1 door med 30 - close, then opens +Remote door|76|WR door med 30 - close, then opens +Remote door|108|W1 blaze turbo 4 - open,close +Remote door|111|WR blaze turbo 4 - open,close +Remote door|105|S1 blaze turbo 4 - open,close +Remote door|114|SR blaze turbo 4 - open,close +Remote door|109|W1 blaze turbo - - open +Remote door|112|S1 blaze turbo - - open +Remote door|106|WR blaze turbo - - open +Remote door|115|SR blaze turbo - - open +Remote door|110|W1 blaze turbo - - close +Remote door|113|S1 blaze turbo - - close +Remote door|107|WR blaze turbo - - close +Remote door|116|SR blaze turbo - - close +Remote door|133|S1 blaze turbo - - open BLUE KEY +Remote door|99|SR blaze turbo - - open BLUE KEY +Remote door|135|S1 blaze turbo - - open RED KEY +Remote door|134|SR blaze turbo - - open RED KEY +Remote door|137|S1 blaze turbo - - open YELLOW KEY +Remote door|136|SR blaze turbo - - open YELLOW KEY + +Ceiling|40|W1 mover slow - - up to HEC +Ceiling|41|S1 mover slow - - down to floor +Ceiling|43|SR mover slow - - down to floor +Ceiling|44|W1 mover slow - - down to floor + 8 +Ceiling|49|S1 mover slow - - down to floor + 8 +Ceiling|72|WR mover slow - - down to floor + 8 + +Lift|10|W1 lift fast 3 - lift +Lift|21|S1 lift fast 3 - lift +Lift|88|WRm lift fast 3 - lift +Lift|62|SR lift fast 3 - lift +Lift|121|W1 lift turbo 3 - lift +Lift|122|S1 lift turbo 3 - lift +Lift|120|WR lift turbo 3 - lift +Lift|123|SR lift turbo 3 - lift + +Floor|119|W1 mover slow - - up to nhEF +Floor|128|WR mover slow - - up to nhEF +Floor|18|S1 mover slow - - up to nhEF +Floor|69|SR mover slow - - up to nhEF +Floor|22|W1& mover slow - TX up to nhEF +Floor|95|WR& mover slow - TX up to nhEF +Floor|20|S1& mover slow - TX up to nhEF +Floor|68|SR& mover slow - TX up to nhEF +Floor|47|G1& mover slow - TX up to nhEF +Floor|5|W1 mover slow - - up to LIC +Floor|91|WR mover slow - - up to LIC +Floor|101|S1 mover slow - - up to LIC +Floor|64|SR mover slow - - up to LIC +Floor|24|G1 mover slow - - up to LIC +Floor|130|W1 mover turbo - - up to nhEF +Floor|131|S1 mover turbo - - up to nhEF +Floor|129|WR mover turbo - - up to nhEF +Floor|132|SR mover turbo - - up to nhEF +Floor|56|W1& mover slow - - up to LIC - 8, CRUSH +Floor|94|WR& mover slow - - up to LIC - 8, CRUSH +Floor|55|S1 mover slow - - up to LIC - 8, CRUSH +Floor|65|SR mover slow - - up to LIC - 8, CRUSH +Floor|58|W1 mover slow - - up 24 +Floor|92|WR mover slow - - up 24 +Floor|15|S1& mover slow - TX up 24 +Floor|66|SR& mover slow - TX up 24 +Floor|59|W1& mover slow - TXP up 24 +Floor|93|WR& mover slow - TXP up 24 +Floor|14|S1& mover slow - TX up 32 +Floor|67|SR& mover slow - TX up 32 +Floor|140|S1 mover med - - up 512 +Floor|30|W1 mover slow - - up ShortestLowerTexture +Floor|96|WR mover slow - - up ShortestLowerTexture +Floor|38|W1 mover slow - - down to LEF +Floor|23|S1 mover slow - - down to LEF +Floor|82|WR mover slow - - down to LEF +Floor|60|SR mover slow - - down to LEF +Floor|37|W1 mover slow - NXP down to LEF +Floor|84|WR mover slow - NXP down to LEF +Floor|19|W1 mover slow - - down to HEF +Floor|102|S1 mover slow - - down to HEF +Floor|83|WR mover slow - - down to HEF +Floor|45|SR mover slow - - down to HEF +Floor|36|W1 mover fast - - down to HEF + 8 +Floor|71|S1 mover fast - - down to HEF + 8 +Floor|98|WR mover fast - - down to HEF + 8 +Floor|70|SR mover fast - - down to HEF + 8 +Floor|9|S1 mover slow - NXP donut (see note 12 above) + +Stair|8|W1 mover slow - - stairs +Stair|7|S1 mover slow - - stairs +Stair|100|W1 mover turbo - - stairs (each up 16 not 8) + crush +Stair|127|S1 mover turbo - - stairs (each up 16 not 8) + crush + +Moving floor|53|W1& lift slow 3 - start moving floor +Moving floor|54|W1& - - - - stop moving floor +Moving floor|87|WR& lift slow 3 - start moving floor +Moving floor|89|WR& - - - - stop moving floor + +Crushing ceiling|6|W1& crush med 0 - start crushing, fast hurt +Crushing ceiling|25|W1& crush med 0 - start crushing, slow hurt +Crushing ceiling|73|WR& crush slow 0 - start crushing, slow hurt +Crushing ceiling|77|WR& crush med 0 - start crushing, fast hurt +Crushing ceiling|57|W1& - - - - stop crush +Crushing ceiling|74|WR& - - - - stop crush +Crushing ceiling|141|W1& none? slow 0 - start crushing, slow hurt "Silent" + +Exit level|11|S- clunk - - - End level, go to next level +Exit level|51|S- clunk - - - End level, go to secret level +Exit level|52|W- clunk - - - End level, go to next level +Exit level|124|W- clunk - - - End level, go to secret level + +Teleport|39|W1m tport - - - Teleport +Teleport|97|WRm tport - - - Teleport +Teleport|125|W1m tport - - - Teleport monsters only +Teleport|126|WRm tport - - - Teleport monsters only + +Light effect|35|W1 - - - - 0 +Light effect|104|W1 - - - - LE (light level) +Light effect|12|W1 - - - - HE (light level) +Light effect|13|W1 - - - - 255 +Light effect|79|WR - - - - 0 +Light effect|80|WR - - - - HE (light level) +Light effect|81|WR - - - - 255 +Light effect|17|W1 - - - - Light blinks (see [4-9-1] type 3) +Light effect|138|SR clunk - - - 255 +Light effect|139|SR clunk - - - 0 + + + +# LINEDEF_FLAGS section. Each line is "bit number|name|short hand char" +# +# Note there can be no gaps in the bit numbers. If there are bits that +# don't matter they must still defined, eg. +# 0|Bit 0|1 +# 1|Unused|- +# 2|Bit 2|1 +# +%LINEDEF_FLAGS +0|Impassible|I +1|Block monsters|M +2|Two-sided|2 +3|Upper unpegged|U +4|Lower unpegged|L +5|Secret|S +6|Blocks sound|B +7|Not on map|N +8|Already on map|A + + +# LINEDEF_FLAGS_EXTRA +# +# Simply defines which of the LINEDEF flag bits are the ones that indicates +# certain eatures. This will probably never change anyhow, but is configurable +# in case. The format is: +# +# <bit for 2-sided-ness>|<bit for impassible>| +# <bit for upper unpegged>|<bit for lower unpegged> +# +# This section MUST appear before LINEDEF_DEFAULTS +# +%LINEDEF_FLAGS_EXTRA +2|0|3|4 + + +# LINEDEF_DEFAULTS +# +# Defaults to use for linedefs. Should appear after LINEDEF_FLAGS. Format: +# Name|Flags values +# +%LINEDEF_DEFAULTS +Empty|0x00 +Wall|0x01 +2-sided wall|0x47 +2-sided passable|0x04 +2-sided blocks monsters|0x46 + + +# SECTOR_TYPES +# +# Defines values and descriptions for the SECTOR special value +# +# Format: +# Class|Id|Long Name|Short Name +# +# Long name should be no longer than 60 characters, Short no longer than 30 +# Class is one of the classes from %SECTOR_CLASSES +# +%SECTOR_TYPES +Normal|0|Normal|Normal +Lights|1|Light random off|Random off +Lights|2|Blink lights 0.5 second|0.5 blink +Lights|3|Blink lights 1.0 second|1.5 blink +Damage/Lights|4|Lose -10/20% health & blink lights 0.5 sec|-10/20% & 0.5 blink +Damage|5|Lose -5/10% health|-5/10% +Damage|7|Lose -2/5% health|-2/5% +Lights|8|Oscillating light|Oscillating light +Secret|9|Secret|Secret +Door|10|Door closes after 30 seconds|30 sec door +Damage/Exit|11|-10/20% health - end level if < 11%|Damage/end level +Lights|12|Blink lights synchronised 0.5 second|0.5 blink sync +Lights|13|Blink lights synchronised 1.0 second|1.5 blink sync +Door|14|Door opens after 300 seconds|300 sec door +Damage|16|Lose -10/20% health|-10/20% +Lights|17|Light random on/off|Random on/off + + + +# SECTOR_STYLES +# +# Sector textureing styles. Note this section is not additive like the +# other sections (as different DOOMs can have different texture names). +# +# Format : +# +# Mode|Name|Upper|Middle|Lower|Floor|Ceiling +# +# Mode is made up of the following bit fields: +# +# Bit 0 - Paint textures on the sidedefs facing into this sector +# Bit 1 - Paint textures on the sidedefs facing out of this sector +# Bit 2 - Leave current lower/upper settings +# Bit 3 - Set upper unpegged if an upper texture is painted +# Bit 4 - Set lower unpegged if a lower texture is painted +# +# If none of bits 2,3 or 4 are set it is assumed that lower/upper unpegged will +# be cleared on painting those textures. +# +%SECTOR_STYLES +0x19|Quarry|ASHWALL|ASHWALL|ASHWALL|MFLR8_2|F_SKY1 +0x19|Fire Quarry|ROCKRED1|ROCKRED1|ROCKRED1|MFLR8_2|F_SKY1 +0x19|Computer Room|COMPTALL|COMPTALL|COMPTALL|CRATOP1|FLAT2 +0x19|Demon Room|MARBFACE|MARBFACE|MARBFACE|DEM1_6|DEM1_5 + + +# EMPTY_TEXTURE_NAME +# +# The empty texture name. For DOOM this is '-'. +# +%EMPTY_TEXTURE_NAME +- + + +# NORMAL_TYPES +# +# The type values used to represent normal sectors and linedefs +# +# Format: +# Value for sectors|Value for linedefs +# +%NORMAL_TYPES +0|0 + + +# LINEDEF_CHECK_DEFAULT +# +# This controls the linedef F12 checking. Where it finds missing textures +# it will replace them with this one, rather than asking, unless this section +# is not defined or is defined to the same value as EMPTY_TEXTURE_NAME. +# +# Format: +# texture_name +# +%LINEDEF_CHECK_DEFAULT +ASHWALL2 diff --git a/doom2.cfg b/doom2.cfg new file mode 100644 index 0000000..1f58a0a --- /dev/null +++ b/doom2.cfg @@ -0,0 +1,72 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# +# $Id: doom2.cfg,v 1.12 2000/06/12 15:58:54 dosuser Exp dosuser $ +# +# Doom 2 config file. See the heading of doom.cfg for details +# + +%INCLUDE_FILES +doom.cfg + +# THING_TYPES section +# +%THING_TYPES +Dead Things|Pool of blood|79|20|POB1A0 +Dead Things|Pool of blood|80|20|POB2A0 +Dead Things|Pool of brains|81|20|BRS1A0 + +Health Items|Megasphere|83|20|MEGAA0 + +Monster|Wolfenstien SS|84|20|SSWVA1 +Monster|Chaingunner|65|20|CPOSA1 +Monster|Hell Knight|69|24|BOS2A1C1 +Monster|Arachnotron|68|64|BSPIA1D1 +Monster|Pain Elemental|71|31|PAINA1 +Monster|Revenant|66|20|SKELA1D1 +Monster|Mancubus|67|48|FATTA1 +Monster|Arch Vile|64|20|VILEA1D1 +Monster|Boss Brain|88|16|BBRNA0 +Monster|Hellspawn Generator|89|16|BOSFB0 +Monster|Hellspawn Spot|87|16|FIRED0 + +Misc|Commander Keen|72|10|KEENA0 + +Scenery|Tall techno floor lamp|85|16|TLMPA0 +Scenery|Short techno floor lamp|86|16|TLP2A0 +Scenery|Burning barrel|70|16|FCANA0 +Scenery|Hanging victim, guts removed|73|16|HDB1A0 +Scenery|Hanging victim, guts and brain removed|74|16|HDB2A0 +Scenery|Hanging torso, looking down|75|16|HDB3A0 +Scenery|Hanging torso, open skull|76|16|HDB4A0 +Scenery|Hanging torso, looking up|77|16|HDB5A0 +Scenery|Hanging torso, brain removed|78|16|HDB6A0 + +Weapon|Double-barrel shotgun|82|20|SGN2A0 + + +# SECTOR_STYLES +# +%SECTOR_STYLES +0x19|Quarry|SP_ROCK1|SP_ROCK1|SP_ROCK1|RROCK09|F_SKY1 +0x19|Concrete Room|STONE|STONE|STONE|FLAT5_4|GRNLITE1 +0x19|Computer Room|COMPTALL|COMPTALL|COMPTALL|FLAT19|FLAT17 +0x19|Demon Room|MARBFACE|MARBFACE|MARBFACE|DEM1_6|DEM1_5 +0x03|Teleport|SUPPORT3|SUPPORT3|SUPPORT3|GATE3|GATE4 @@ -0,0 +1,734 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor main definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <ctype.h> + +#include "edit.h" +#include "editvar.h" + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +void EditSetScreen(int w,int h) +{ + TRACE; + + SCRW=w; + SCRH=h; + + FH=GFX_fh(); + + vertex=MapNew(sizeof(Object)); + linedef=MapNew(sizeof(Object)); + sidedef=MapNew(sizeof(Object)); + thing=MapNew(sizeof(Object)); + sector=MapNew(sizeof(Object)); + selected=ListNew(sizeof(int)); +} + +void EditPreviewWadMap(char *name,WadMap *m) +{ + int min_x,min_y,cx,cy,scale; + int f; + Linedef *l; + Vertex *v1,*v2; + int done; + int redraw; + GFXKey key; + Thing *t; + int vertmode; + int linemode; + int things; + + TRACE; + + scale=25; + cx=0; + cy=0; + + done=FALSE; + redraw=TRUE; + linemode=TRUE; + vertmode=TRUE; + things=TRUE; + + while(!done) + { + if (redraw) + { + min_x=cx-(SCRW/2)*scale; + min_y=cy-(SCRH/2)*scale; + + GFX_clear(BLACK); + + if (things) + for(f=0;f<MapSize(m->thing);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;f<MapSize(m->linedef);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;f<MapSize(m->vertex);f++) + { + v1=MapElem(m->vertex,f); + + GFX_plot((v1->x-min_x)/scale, + (-v1->y-min_y)/scale,WHITE); + } + + GuiDrawInfoBox("Preview Map",1,1,FALSE, + "Map : %s|" + "Scale : %d|" + "X : %d|" + "Y : %d|" + "Linedefs : %s|" + "Vertexes : %s|" + "Things : %s|" + " |" + "Press F1 for help",name,scale,cx,cy, + YESNO(linemode), + YESNO(vertmode), + YESNO(things)); + + GFX_redraw(); + } + + GFX_waitkey(&key); + + redraw=TRUE; + + switch(key.code) + { + case GFX_ESC: + done=TRUE; + break; + + case GFX_DOWN: + cy+=scale*(key.shift ? 20 : 1); + break; + + case GFX_UP: + cy-=scale*(key.shift ? 20 : 1); + break; + + case GFX_RIGHT: + cx+=scale*(key.shift ? 20 : 1); + break; + + case GFX_LEFT: + cx-=scale*(key.shift ? 20 : 1); + break; + + case GFX_PGUP: + if (++scale>32) + scale=32; + break; + + case GFX_PGDN: + if (--scale==0) + scale=1; + break; + + case GFX_ASCII: + switch(toupper(key.ascii)) + { + case 'L': + linemode=!linemode; + break; + case 'V': + vertmode=!vertmode; + break; + case 'T': + things=!things; + break; + default: + break; + } + break; + + case GFX_F1: + GuiInfoBox("HELP", + "Cursor keys - move map|" + "Cursor keys + shift - move map quickly|" + "Page Down - reduce scale|" + "Page Up - increase scale|" + "L (toggle) - draw linedefs|" + "V (toggle) - draw vertex points|" + "T (toggle) - draw things|" + "ESC - quit"); + break; + + default: + redraw=FALSE; + break; + } + } +} + + +void EditLoad(WadMap *map) +{ + int f; + Vertex *v; + Linedef *l; + Sector *s; + Thing *t; + EditVert *ev; + EditLine *el; + EditSect *es; + EditThing *et; + Object o; + int min_x=0,max_x=0,min_y=0,max_y=0; + int find; + + TRACE; + + scale=MAX(0,MIN(32,default_scale)); + + if (MapSize(map->vertex)) + { + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + find=TRUE; + } + else + { + find=FALSE; + ox=-scale*SCRW/2; + oy=scale*SCRH/2; + } + + vertex=MapEmpty(vertex); + linedef=MapEmpty(linedef); + thing=MapEmpty(thing); + sector=MapEmpty(sector); + sidedef=MapEmpty(sidedef); + selected=ListEmpty(selected); + + switch(default_edit_mode) + { + case EDIT_SECTOR: + SetEditMode(SECTOR_MODE); + break; + case EDIT_VERTEX: + SetEditMode(VERTEX_MODE); + break; + case EDIT_LINEDEF: + SetEditMode(LINEDEF_MODE); + break; + case EDIT_THING: + SetEditMode(THING_MODE); + break; + case EDIT_MULTI: + SetEditMode(MULTI_MODE); + break; + default: + SetEditMode(SECTOR_MODE); + break; + } + + /* Get vertex from WadMap + */ + for(f=0;f<MapSize(map->vertex);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;f<MapSize(map->sidedef);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;f<MapSize(map->linedef);f++) + { + l=MapElem(map->linedef,f); + el=Grab(sizeof(EditLine)); + + memcpy(&el->l,l,sizeof(Linedef)); + + el->no=f; + el->sr=GETSIDE(l->right); + + if (l->left!=-1) + el->sl=GETSIDE(l->left); + else + el->sl=NULL; + + el->v[0]=GETVERT(l->from); + el->v[1]=GETVERT(l->to); + + IntListUniqAdd(el->v[0]->l,f); + IntListUniqAdd(el->v[1]->l,f); + + LineCalcBounding(el); + + o.select=SELECT_NONE; + o.data=el; + + MapAdd(linedef,f,&o); + } + + /* Get sectors from WadMap + */ + for(f=0;f<MapSize(map->sector);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;f<MapSize(map->thing);f++) + { + t=MapElem(map->thing,f); + et=Grab(sizeof(EditThing)); + memcpy(&et->t,t,sizeof(Thing)); + o.select=SELECT_NONE; + o.data=et; + MapAdd(thing,f,&o); + } + + /* Set up multi map if default mode is MULTI mode + */ + if (default_edit_mode==EDIT_MULTI) + GenerateMultiMap(); +} + + +void EditSave(WadMap *map) +{ + int f; + Object *o; + EditVert *v; + EditThing *t; + EditSect *s; + EditLine *l; + + TRACE; + + MapEmpty(map->linedef); + MapEmpty(map->sidedef); + MapEmpty(map->thing); + MapEmpty(map->vertex); + MapEmpty(map->sector); + + for(f=0;f<MapSize(vertex);f++) + { + v=GETVERT(f); + MapAdd(map->vertex,f,&(v->v)); + } + + /* Sidedefs are the only edit object stored fully in DOOM format + */ + for(f=0;f<MapSize(sidedef);f++) + { + o=MapElem(sidedef,f); + MapAdd(map->sidedef,f,o->data); + } + + for(f=0;f<MapSize(linedef);f++) + { + l=GETLINE(f); + MapAdd(map->linedef,f,&(l->l)); + } + + for(f=0;f<MapSize(thing);f++) + { + t=GETTHING(f); + MapAdd(map->thing,f,&(t->t)); + } + + for(f=0;f<MapSize(sector);f++) + { + s=GETSECT(f); + MapAdd(map->sector,f,&(s->s)); + } +} + + +void EditLoop(void) +{ + GFXEvent ev; + + TRACE; + + GFX_bounce(); + FullRedraw(); + quit=FALSE; + + while(!quit) + { + GFX_redraw(); + GFX_await_input_full(&ev); + + new_selection=FALSE; + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleKey(ev.key); + break; + + case GFX_MOUSE_EVENT: + HandleMouse(ev.mouse); + break; + + default: + break; + } + } +} + + +void EditCompact(void) +{ + Map new_t,new_v,new_l,new_s,new_si; + int f; + int r; + int i; + Object o; + Object *oo; + EditLine *l; + EditSect *s; + EditVert *v; + Sidedef *side; + + TRACE; + + ClearSelection(); + + new_t=MapNew(sizeof(Object)); + new_v=MapNew(sizeof(Object)); + new_l=MapNew(sizeof(Object)); + new_s=MapNew(sizeof(Object)); + new_si=MapNew(sizeof(Object)); + + /* Compress linedef + */ + i=0; + for(f=0;f<MapSize(linedef);f++) + { + memcpy(&o,MapElem(linedef,f),sizeof(Object)); + + if (o.data) + MapAdd(new_l,i++,&o); + } + + /* Compress things + */ + i=0; + for(f=0;f<MapSize(thing);f++) + { + memcpy(&o,MapElem(thing,f),sizeof(Object)); + + if (o.data) + MapAdd(new_t,i++,&o); + } + + /* Compress sidedef + */ + i=0; + for(f=0;f<MapSize(sidedef);f++) + if (GETSIDE(f)) + i++; + + if (i) + for(f=MapSize(sidedef)-1;f>=0;f--) + { + memcpy(&o,MapElem(sidedef,f),sizeof(Object)); + + if (o.data) + { + i--; + MapAdd(new_si,i,&o); + } + else + for(r=0;r<MapSize(new_l);r++) + { + oo=MapElem(new_l,r); + l=oo->data; + + if (l->l.left>=f) + l->l.left--; + + if (l->l.right>=f) + l->l.right--; + } + } + + /* Compress sectors + */ + i=0; + for(f=0;f<MapSize(sector);f++) + { + s=GETSECT(f); + + if ((s)&&(ListSize(s->all))) + 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;r<MapSize(new_si);r++) + { + side=SIDEFROM(new_si,r); + + if (side->sector>=f) + side->sector--; + } + } + } + + /* Compress vertexes (deleting unused ones first) + */ + for(f=0;f<MapSize(vertex);f++) + { + oo=MapElem(vertex,f); + + if (oo->data) + { + v=oo->data; + + if (ListSize(v->l)==0) + { + ListClear(v->l); + Release(oo->data); + oo->data=NULL; + } + } + } + + i=0; + for(f=0;f<MapSize(vertex);f++) + if (GETVERT(f)) + i++; + + if (i) + for(f=MapSize(vertex)-1;f>=0;f--) + { + memcpy(&o,MapElem(vertex,f),sizeof(Object)); + + if (o.data) + { + i--; + MapAdd(new_v,i,&o); + } + else + for(r=0;r<MapSize(new_l);r++) + { + oo=MapElem(new_l,r); + l=oo->data; + + if (l->l.from>=f) + l->l.from--; + + if (l->l.to>=f) + l->l.to--; + } + } + + for(r=0;r<MapSize(new_l);r++) + { + oo=MapElem(new_l,r); + l=oo->data; + + 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;f<MapSize(new_s);f++) + { + oo=MapElem(new_s,f); + s=oo->data; + s->no=f; + } + + for(f=0;f<MapSize(new_l);f++) + { + oo=MapElem(new_l,f); + l=oo->data; + 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;f<MapSize(linedef);f++) + { + l=GETLINE(f); + + if (l->l.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;f<MapSize(vertex);f++) + ListEmpty(GETVERT(f)->l); + + for(f=0;f<MapSize(linedef);f++) + { + l=GETLINE(f); + IntListUniqAdd(l->v[0]->l,f); + IntListUniqAdd(l->v[1]->l,f); + } + + /* Recalc sector containing values + */ + SectorCalcContainingAll(); +} + + +/* END OF FILE */ @@ -0,0 +1,70 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor definitions + + Note that the lindefs, vertices, etc here are copied from the WadMap + loaded prior to editting. They are then reconverted back to the WadMap + for saving. + + $Id$ + +*/ + +#ifndef _EDIT_H +#define _EDIT_H + +#include "wad.h" + +/* Inform the editor of the screen size +*/ +void EditSetScreen(int w,int h); + + +/* Preview a rough map from a passed WadMap +*/ +void EditPreviewWadMap(char *name,WadMap *map); + + +/* Load in the editor data from a WadMap. Clears the current editor state. +*/ +void EditLoad(WadMap *map); + + +/* Save the editor data back into the WadMap +*/ +void EditSave(WadMap *map); + + +/* Editor loop +*/ +void EditLoop(void); + + +/* Compact the various objects, updating references as required. +*/ +void EditCompact(void); + +#endif + + +/* END OF FILE */ diff --git a/editcord.c b/editcord.c new file mode 100644 index 0000000..da3097f --- /dev/null +++ b/editcord.c @@ -0,0 +1,225 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor co-ordinate utilities + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <math.h> + +#include "texture.h" +#include "editvar.h" + +/* ---------------------------------------- MAP DRAWING AND POSITION FUNCTIONS +*/ +int SnapX(int x) +{ + TRACE; + + if (!grid_lock) + return(x); + + if (x>=0) + return (((x+grid_size/2)/grid_size)*grid_size); + else + return (((x-grid_size/2)/grid_size)*grid_size); +} + +int SnapY(int y) +{ + TRACE; + + if (!grid_lock) + return(y); + + if (y>=0) + return (((y+grid_size/2)/grid_size)*grid_size); + else + return (((y-grid_size/2)/grid_size)*grid_size); +} + + +int Len(int x1,int y1,int x2,int y2) +{ + double a,b,c; + + TRACE; + + x2-=x1; + y2-=y1; + x2=ABS(x2); + y2=ABS(y2); + + if (!x2) + return(y2); + else if (!y2) + return(x2); + + a=x2*x2; + b=y2*y2; + c=sqrt(a+b); + return((int)c); +} + + +/* Many thanks to Mathew Wilson (www.mjwilson.demon.co.uk) for this routine +*/ +int LinesCross(int x1_1,int y1_1,int x1_2,int y1_2, + int x2_1,int y2_1,int x2_2,int y2_2) +{ + double x0,y0,x1,y1,u0,v0,u1,v1; + double t; + double m,l; + + x0=(double)x1_1; + y0=(double)y1_1; + u0=(double)x1_2-x1_1; + v0=(double)y1_2-y1_1; + + x1=(double)x2_1; + y1=(double)y2_1; + u1=(double)x2_2-x2_1; + v1=(double)y2_2-y2_1; + + /* Find 1st divisor (to check for zero) + */ + t=(u1*v0)-(v1*u0); + + if (t==0.0) + return(FALSE); + + m=(v0*(x0-x1)-u0*(y0-y1))/t; + + l=(v1*(x0-x1)-u1*(y0-y1))/t; + + if ((l>=0.0)&&(l<=1.0)&&(m>=0.0)&&(m<=1.0)) + return(TRUE); + + return(FALSE); +} + + +int CalcTextureWidth(DirName u,DirName m,DirName l) +{ + int a,b,c; + int w=99999; + + TRACE; + + TextureSize(u,&a,NULL); + TextureSize(m,&b,NULL); + TextureSize(l,&c,NULL); + + if ((a)&&(a<w)) + w=a; + + if ((b)&&(b<w)) + w=b; + + if ((c)&&(c<w)) + w=c; + + if (w==99999) + w=0; + + return(w); +} + + +void LineCalcBounding(EditLine *l) +{ + TRACE; + + l->min_x=MIN(l->v[0]->v.x,l->v[1]->v.x); + l->max_x=MAX(l->v[0]->v.x,l->v[1]->v.x); + l->min_y=MIN(l->v[0]->v.y,l->v[1]->v.y); + l->max_y=MAX(l->v[0]->v.y,l->v[1]->v.y); +} + + +void SectorCalcBounding(EditSect *s) +{ + Iterator i; + Short *f; + EditVert *v; + + TRACE; + + s->min_x=32000; + s->min_y=32000; + s->max_x=-32000; + s->max_y=-32000; + i=ListIterator(s->v); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + s->min_x=MIN(s->min_x,v->v.x); + s->max_x=MAX(s->max_x,v->v.x); + s->min_y=MIN(s->min_y,v->v.y); + s->max_y=MAX(s->max_y,v->v.y); + + i=IteratorNext(i); + } +} + + +int LineOnDisplay(EditLine *l) +{ + TRACE; + + /* Remember: DOOM Y positions are the reverse of the order on screen + */ + return ((MapToX(l->min_x)<SCRW)&&(MapToX(l->max_x)>=0)&& + (MapToY(l->max_y)<SCRH)&&(MapToY(l->min_y)>=0)); +} + + +int SectorOnDisplay(EditSect *s) +{ + TRACE; + + /* Remember: DOOM Y positions are the reverse of the order on screen + */ + return ((MapToX(s->min_x)<SCRW)&&(MapToX(s->max_x)>=0)&& + (MapToY(s->max_y)<SCRH)&&(MapToY(s->min_y)>=0)); +} + + +int PointOnDisplay(int x,int y,int r) +{ + TRACE; + + /* Remember: DOOM Y positions are the reverse of the order on screen + */ + return ((MapToX(x+r)>=0)&&(MapToX(x-r)<SCRW)&& + (MapToY(y-r)>=0)&&(MapToY(y+r)<SCRH)); +} + + +/* END OF FILE */ diff --git a/editcrse.c b/editcrse.c new file mode 100644 index 0000000..c4f745f --- /dev/null +++ b/editcrse.c @@ -0,0 +1,398 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + SECTOR interactive creation + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" +#include "sectors.h" + +#include <ctype.h> + + +/* ---------------------------------------- SECTOR CREATION PRIVATE ROUTINES +*/ +static void SwapTexture(DirName a, DirName b) +{ + DirName t; + + strcpy(t,a); + strcpy(a,b); + strcpy(b,t); +} + + +static List ReverseList(List l) +{ + Iterator i; + List new; + + new=ListNew(sizeof(int)); + + i=ListIterator(l); + + while(i) + { + ListInsert(new,IteratorData(i)); + i=IteratorNext(i); + } + + return(new); +} + + +static List CopyList(List l) +{ + Iterator i; + List new; + + new=ListNew(sizeof(int)); + + i=ListIterator(l); + + while(i) + { + ListAppend(new,IteratorData(i)); + i=IteratorNext(i); + } + + return(new); +} + + +/* ---------------------------------------- SECTOR CREATION ROUTINES +*/ +int CreateUnboundSector(int special,int floor,int ceiling,int light,int tag, + DirName floor_t,DirName ceiling_t) +{ + Object o; + EditSect *s; + int sn; + + TRACE; + + sn=MapSize(sector); + + s=Grab(sizeof(EditSect)); + + s->no=sn; + s->s.special=special; + s->s.floor=floor; + s->s.ceiling=ceiling; + s->s.light=light; + strcpy(s->s.floor_t,floor_t); + strcpy(s->s.ceiling_t,ceiling_t); + s->v=ListNew(sizeof(Short)); + s->sr=ListNew(sizeof(EditLine *)); + s->sl=ListNew(sizeof(EditLine *)); + s->all=ListNew(sizeof(EditLine *)); + s->min_x=s->min_y=s->max_x=s->max_y=0; + + o.select=SELECT_NONE; + o.data=s; + MapAdd(sector,sn,&o); + + return(sn); +} + +int CreateSector(List in_v) +{ + List v; + Iterator i; + int *f; + int from; + int to; + int type; + int flag; + int two; + int first; + int sect; + int wr,wl; + int oxr,oxl; + DirName sr_upper,sr_middle,sr_lower; + DirName sl_upper,sl_middle,sl_lower; + EditSect *s; + EditVert *v1,*v2; + int special,floor,ceiling,light; + int in_floor,in_ceiling,in_light; + DirName floor_t,ceiling_t; + int in_sector,new_sec; + int swap; + int nl; + int style_flag; + List left_offset; + + TRACE; + + /* Check enough vertexes + */ + if (ListSize(in_v)<3) + { + GuiInfoBox("ERROR","Need 3 or more vertices|" + "to create a sector"); + FullRedraw(); + return(FALSE); + } + + /* Check all points lie either inside the same sector or outside a sector + */ + in_sector=-1; + + i=ListIterator(in_v); + + f=IteratorData(i); + v1=GETVERT(*f); + in_sector=SectorHoldingPoint(v1->v.x,v1->v.y); + i=IteratorNext(i); + + /* Check to see if the vertices are all inside the same sector. If some or + all of the vertices lie outside the same sector then the sector is + assumed to not be in another one + */ + while(i) + { + f=IteratorData(i); + v1=GETVERT(*f); + + new_sec=SectorHoldingPoint(v1->v.x,v1->v.y); + + if ((in_sector!=-1)&&(new_sec!=in_sector)) + in_sector=-1; + + i=IteratorNext(i); + } + + if (in_sector!=-1) + { + s=GETSECT(in_sector); + light=in_light=s->s.light; + floor=in_floor=s->s.floor; + ceiling=in_ceiling=s->s.ceiling; + } + else + { + s=NULL; + light=in_light=default_light_level; + floor=in_floor=default_floor_height; + ceiling=in_ceiling=default_ceiling_height; + } + + special=0; + + /* Now get the linedef and sector values + */ + if (!GetSectorValues(&type,&flag,&two, + &floor,&ceiling,&light, + in_floor,in_ceiling, + &style_flag, + floor_t,ceiling_t, + sr_upper,sr_middle,sr_lower, + sl_upper,sl_middle,sl_lower)) + return(FALSE); + + /* See if the sector is inside another sector and see if the user wants + the new sectors right sidedefs pointing out into the containing sector + */ + if (in_sector!=-1) + swap=YesNo("Sector in another sector. Make RIGHT SIDEDEF point out?"); + else + swap=FALSE; + + + /* Past here the user cannot cancel the create operation, so now create + a copy of the vertex list (reversed if necessary) and reverse the + textures as necessary + */ + if (swap) + { + if (two) + { + SwapTexture(sr_upper,sl_upper); + SwapTexture(sr_middle,sl_middle); + SwapTexture(sr_lower,sl_lower); + } + + v=ReverseList(in_v); + } + else + v=CopyList(in_v); + + /* Add either lower/upper unpegged according to the sector style flags + */ + if (style_flag&SSTYLE_UPPER_PEG) + flag|=upper_peg_mask; + + if (style_flag&SSTYLE_LOWER_PEG) + flag|=lower_peg_mask; + + /* Create list for left offsets if needed + */ + if (two) + left_offset=ListNew(sizeof(int)); + else + left_offset=NULL; + + /* Calc texture widths and get a new sector number + */ + oxr=0; + oxl=0; + + wr=CalcTextureWidth(sr_upper,sr_middle,sr_lower); + + if (two) + wl=CalcTextureWidth + (sl_upper,sl_middle,sl_lower); + else + wl=0; + + if (swap) + { + sect=in_sector; + in_sector=CreateUnboundSector + (special,floor,ceiling,light,0, + floor_t,ceiling_t); + } + else + sect=CreateUnboundSector + (special,floor,ceiling,light,0, + floor_t,ceiling_t); + + i=ListIterator(v); + + memcpy(&to,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + first=to; + + while(i) + { + from=to; + memcpy(&to,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + + nl=CreateNewLinedef + (from,to, + flag,type,0,two, + oxr,0,sect, + sr_upper,sr_middle,sr_lower, + oxl,0,in_sector, + sl_upper,sl_middle,sl_lower); + + v1=GETVERT(from); + v2=GETVERT(to); + + IntListUniqAdd(v1->l,nl); + IntListUniqAdd(v2->l,nl); + + if (wr) + oxr=(oxr+Len(v1->v.x,v1->v.y, + v2->v.x,v2->v.y))%wr; + + /* The left sidedef has the offsets coming from the opposite direction + so have to be applied in reverse once all the lines have been + created. Damn, wish I'd realised that earlier + */ + if (two) + ListInsert(left_offset,&nl); + } + + /* Create the line to close the polygon + */ + nl=CreateNewLinedef(to,first, + flag,type,0,two, + oxr,0,sect, + sr_upper,sr_middle,sr_lower, + oxl,0,in_sector, + sl_upper,sl_middle,sl_lower); + + v1=GETVERT(to); + v2=GETVERT(first); + + IntListUniqAdd(v1->l,nl); + IntListUniqAdd(v2->l,nl); + + if (two) + ListInsert(left_offset,&nl); + + /* Apply the left offsets + */ + if (two) + { + EditLine *l; + + i=ListIterator(left_offset); + + while(i) + { + f=IteratorData(i); + + l=GETLINE(*f); + + if (wl) + oxl=(oxl+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%wl; + + l->sl->x=oxl; + + i=IteratorNext(i); + } + + ListClear(left_offset); + } + + /* Calc sector bounds + */ + if (swap) + s=GETSECT(in_sector); + else + s=GETSECT(sect); + + SectorCalcContainingAll(); + SectorCalcBounding(s); + + ListClear(v); + + /* Check for mergeable LINEDEFS + */ + i=ListIterator(s->v); + + while(i) + { + Short *s; + + s=IteratorData(i); + CheckMergeLinedef(GETVERT(*s)); + i=IteratorNext(i); + } + + /* Recalc containing in case LINEDEFS where merged + */ + SectorCalcContainingAll(); + + return(TRUE); +} + + +/* END OF FILE */ diff --git a/editdraw.c b/editdraw.c new file mode 100644 index 0000000..0ec30a7 --- /dev/null +++ b/editdraw.c @@ -0,0 +1,346 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + General editor drawing routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <math.h> + +#include "editvar.h" + + +/* ---------------------------------------- DRAWING FUNCTIONS +*/ +void DrawArrow(int x1,int y1,int x2,int y2,int c) +{ + int dx,dy; + double ang; + int x,y; + + TRACE; + + dx=x1-x2; + dy=y1-y2; + + /* Calc angle that the line is at + */ + if (dx==0) + if (dy<0) + ang=RAD(0); + else + ang=RAD(180); + else if (dy==0) + if (dx<0) + ang=RAD(90); + else + ang=RAD(270); + else + { + ang=atan((double)dx/(double)dy); + + if (dy>0) + ang-=RAD(180); + } + + MapLine(x1,y1,x2,y2,c); + + x=(int)(x2-sin(ang-RAD(25))*12.0); + y=(int)(y2-cos(ang-RAD(25))*12.0); + MapLine(x2,y2,x,y,c); + + x=(int)(x2-sin(ang+RAD(25))*12.0); + y=(int)(y2-cos(ang+RAD(25))*12.0); + MapLine(x2,y2,x,y,c); +} + + +void DrawGrid(void) +{ + int c; + + TRACE; + + if (!grid_onoff) + return; + + agrid=grid_size; + + while((agrid/scale)<8) + agrid*=2; + + c=YToMap(0); + + while(c%agrid) + c++; + + while(c>YToMap(SCRH-1)) + { + GFX_line(0,MapToY(c),SCRW-1,MapToY(c),GRIDCOL); + c-=agrid; + } + + c=ox; + while(c%agrid) + c--; + + while(c<XToMap(SCRW-1)) + { + GFX_line(MapToX(c),0,MapToX(c),SCRH-1,GRIDCOL); + c+=agrid; + } +} + + +void DrawMap(void) +{ + int f; + Object *o; + EditLine *l; + EditVert *v; + EditThing *t; + EditSect *s; + Iterator i; + int *sv; + + TRACE; + + for(f=0;f<MapSize(linedef);f++) + { + o=MapElem(linedef,f); + l=o->data; + + 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;f<MapSize(vertex);f++) + { + o=MapElem(vertex,f); + v=o->data; + + 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;f<MapSize(sector);f++) + { + o=MapElem(sector,f); + s=o->data; + 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;f<MapSize(thing);f++) + { + o=MapElem(thing,f); + t=o->data; + + if (t) + if ((edit_mode==THING_MODE)||(edit_mode==MULTI_MODE)) + { + if (PointOnDisplay(t->t.x,t->t.y,ThingRadius(t->t.type,NULL))) + DrawObject_THING(t,o->select); + } + else + if (PointOnDisplay(t->t.x,t->t.y,8)) + { + MapLine(t->t.x-8,t->t.y,t->t.x+8,t->t.y,THINGCOL); + MapLine(t->t.x,t->t.y-8,t->t.x,t->t.y+8,THINGCOL); + } + } +} + + +void DrawHeader(void) +{ +#ifdef DEBUG + static int chk=TRUE; + static int db=FALSE; +#endif + + TRACE; + + GFX_frect(0,0,SCRW,FH*2,BLUE); + + GFX_print(0,0,WHITE,"Mode: %-8s Pos: %d,%d", + edit_str[edit_mode],XToMap(ms.x),YToMap(ms.y)); + + if (grid_onoff) + GFX_print(SCRW/2,0,WHITE,"Scale: %-2d Lock: %-3s Grid : %d/%d", + scale,YESNO(grid_lock),grid_size,agrid); + else + GFX_print(SCRW/2,0,WHITE,"Scale: %-2d Lock: %-3s Grid : %d", + scale,YESNO(grid_lock),grid_size); + + DrawObjectHeader(); + +#ifdef DEBUG + + /* Debug + */ + if (chk) + { + if ((getenv("VIDOOM_VDEBUG"))&&(!strcmp(getenv("VIDOOM_VDEBUG"),"Y"))) + db=TRUE; + else + db=FALSE; + + chk=FALSE; + } + + if (db) + { + static char ds[128]; + int y; + Iterator i; + int *f; + + GFX_frect(0,FH*2,SCRW,FH*2,RED); + GFX_print(0,FH*2,WHITE,"ox=%d oy=%d " + "SectorHoldingPoint(%d,%d)=%d " + "ListSize(selected)=%d", + ox,oy, + XToMap(ms.x),YToMap(ms.y), + SectorHoldingPoint(XToMap(ms.x),YToMap(ms.y)), + ListSize(selected)); + + i=ListIterator(selected); + ds[0]=0; + y=FH*3; + + while(i) + { + f=IteratorData(i); + + if (strlen(ds)>70) + { + GFX_print(0,y,WHITE,ds); + ds[0]=0; + y+=FH; + } + + sprintf(ds+strlen(ds),"%d, ",*f); + + i=IteratorNext(i); + } + + strcat(ds,"<EOL>"); + GFX_print(0,y,WHITE,"%s",ds); + } +#endif +} + + +void FullRedraw(void) +{ + TRACE; + + GFX_mouse(&ms.x,&ms.y); + GFX_clear(BLACK); + + DrawGrid(); + DrawMap(); + DrawObjectInfo(); + DrawHeader(); +} + + +/* END OF FILE */ diff --git a/editevnt.c b/editevnt.c new file mode 100644 index 0000000..9593cf8 --- /dev/null +++ b/editevnt.c @@ -0,0 +1,1058 @@ +/* + + 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 <ctype.h> + +#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; + + 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;(f<MapSize(map))&&(current==-1);f++) + { + o=MapElem(map,f); + + if (o->data) + { + if (PositionOnObject(map_x,map_y,o->data)) + { + current=f; + if (o->select!=SELECT_SELECTED) + SetSelect(current,SELECT_OVER); + + DrawObject(o->data,o->select); + DrawObjectInfo(); + } + } + } + + /* Do selection box if shift pressed + */ + if ((ms.b&GFX_BUTLEFT)&&(ms.shift)) + { + GFXEvent e; + int x1,y1,x2,y2; + + GFX_set_XOR_mode(); + + do + { + int w,h; + + do + { + GFX_await_input_full(&e); + } while(e.type!=GFX_MOUSE_EVENT); + + w=e.mouse.x-ms.x; + h=e.mouse.y-ms.y; + + GFX_rect(ms.x,ms.y,w,h,WHITE); + GFX_redraw(); + GFX_rect(ms.x,ms.y,w,h,WHITE); + + } while(e.mouse.b&GFX_BUTLEFT); + + GFX_clear_XOR_mode(); + GFX_redraw(); + + x1=MIN(XToMap(ms.x),XToMap(e.mouse.x)); + y1=MIN(YToMap(ms.y),YToMap(e.mouse.y)); + x2=MAX(XToMap(ms.x),XToMap(e.mouse.x)); + y2=MAX(YToMap(ms.y),YToMap(e.mouse.y)); + + if (!(e.mouse.ctrl|ms.ctrl)) + ClearSelection(); + + SelectBox(x1,y1,x2,y2); + + memcpy(&ms,&e.mouse,sizeof(e.mouse)); + FullRedraw(); + } + else + /* Handle left (select) and right (menu) buttons + */ + { + if (ms.b&GFX_BUTLEFT) + if (current==-1) + { + if (!ms.ctrl) + { + ClearSelection(); + FullRedraw(); + } + } + else + { + if (ms.ctrl) + { + o=MapElem(map,current); + + if (o->select==SELECT_SELECTED) + { + if ((i=ListFindElem(selected,PredSelected,¤t))) + { + i=IteratorDelete(i); + i=IteratorClear(i); + } + + SetSelect(current,SELECT_NONE); + DrawObject(o->data,SELECT_NONE); + } + else + { + SetSelect(current,SELECT_SELECTED); + ListAppend(selected,¤t); + DrawObject(o->data,SELECT_SELECTED); + } + } + else + { + ClearSelectionLeaveCurrent(); + SetSelect(current,SELECT_SELECTED); + ListAppend(selected,¤t); + FullRedraw(); + } + } + + /* If the middle or right button is pressed over an object, check + adding the object to the selected list + */ + if ((ms.b&(GFX_BUTRIGHT|GFX_BUTMIDDLE))&&(current!=-1)) + { + /* If there is currently nothing selected then this object is + selected for the duration of the move or menu operation + */ + if (ListSize(selected)==0) + { + temp_select=TRUE; + ListAppend(selected,¤t); + o=MapElem(map,current); + SetSelect(current,SELECT_SELECTED); + DrawObject(o->data,o->select); + } + else if (hover_select!=HOVER_NONE) + { + o=MapElem(map,current); + + if (o->select!=SELECT_SELECTED) + { + if (hover_select==HOVER_SINGLE) + ClearSelectionLeaveCurrent(); + + o=MapElem(map,current); + SetSelect(current,SELECT_SELECTED); + ListAppend(selected,¤t); + FullRedraw(); + } + } + } + + + /* If the middle button is pressed move the object. This is provided as + a shortcut to the menu move option + */ + if ((ms.b&GFX_BUTMIDDLE)&&(ListSize(selected))) + MoveObject(); + + /* If the right button is pressed selected the editting options + */ + if (ms.b&GFX_BUTRIGHT) + if (ListSize(selected)) + ObjectMenu(); + else + switch(GUI_menu(typename,ms.x,ms.y,gen_menu,GUI_CANCEL)) + { + case TM_INSERT: + ObjectInsert(); + break; + + default: + break; + } + + if ((temp_select)&&(!new_selection)) + { + ClearSelection(); + FullRedraw(); + } + } +} + + +/* ---------------------------------------- INPUT HANDLERS +*/ +void SetEditMode(int mode) +{ + TRACE; + + ClearSelection(); + current=-1; + + edit_mode=mode; + + switch(mode) + { + case SECTOR_MODE: + typename="Sector"; + map=sector; + PositionOnObject=PositionOnObject_SECTOR; + SelectBox=SelectBox_SECTOR; + SelectByType=SelectByType_SECTOR; + DrawObject=DrawObject_SECTOR; + DrawObjectInfo=DrawObjectInfo_SECTOR; + DrawObjectHeader=DrawObjectHeader_SECTOR; + MoveObject=MoveObject_SECTOR; + RotateObject=RotateObject_SECTOR; + ScaleObject=ScaleObject_SECTOR; + SetTagObject=SetTagObject_SECTOR; + LocateObject=LocateObject_SECTOR; + ObjectMenu=ObjectMenu_SECTOR; + ObjectInsert=ObjectInsert_SECTOR; + ObjectDelete=ObjectDelete_SECTOR; + ObjectKey=ObjectKey_SECTOR; + ObjectHasTag=ObjectHasTag_SECTOR; + SetSelect=SetSelect_GENERIC; + 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; + + 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 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,"<EOL>"); + Debug(("%s\n",ds)); + } + + break; + + case 2: + { + static int i=0; + char p[10]; + + sprintf(p,"pic%d.bmp",i++); + GFX_save_screen(p); + + } + + break; + + default: + break; + } + + break; + } +#endif + + default: + break; + } +} + + +void HandleKey(GFXKey k) +{ + Object *o; + int f; + + TRACE; + + HandleMoveKey(k,TRUE); + ObjectKey(k); + + if (k.code!=GFX_ASCII) + switch(k.code) + { + case GFX_F1: + 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]); + FullRedraw(); + } + + GuiInfoBox("HELP (Mouse)","%s",general_help_mouse); + FullRedraw(); + break; + + case GFX_F2: + { + char s[128]; + + sprintf(s,"%s Mode Keys",typename); + GuiInfoBox(s,"%s",mode_help[edit_mode]); + FullRedraw(); + break; + } + + case GFX_TAB: + if (k.shift) + SetEditMode(PREV_MODE(edit_mode)); + else + SetEditMode(NEXT_MODE(edit_mode)); + break; + + case GFX_INSERT: + ObjectInsert(); + break; + + case GFX_DELETE: + ObjectDelete(); + break; + + case GFX_F9: + if (k.shift) + { + ListEmpty(selected); + + for(f=0;f<MapSize(map);f++) + { + o=MapElem(map,f); + + if (o->data) + 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;f<no;f++) + pick[f]=od[f].detail; + + pick[no]=NULL; + + sprintf(title,"Select overlapping %s object",typename); + + sel=GUI_picklist(title,pick); + + if (sel!=-1) + { + if (!k.alt) + ClearSelection(); + + if (!InIntList(selected,sel)) + { + SetSelect(od[sel].no,SELECT_SELECTED); + ListAppend(selected,&od[sel].no); + } + } + + Release(pick); + Release(od); + + FullRedraw(); + } + } + else + { + ClearSelection(); + + for(f=0;f<MapSize(map);f++) + { + o=MapElem(map,f); + + if (o->data) + { + 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;f<last_sel;f++) + i=IteratorNext(i); + + if ((n=IteratorData(i))) + { + o=MapElem(map,*n); + LocateObject(o->data); + } + + 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;f<MapSize(map);f++) + { + o=MapElem(map,f); + + if ((o->data)&&(ObjectHasTag(o->data,last_tag))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + + FullRedraw(); + } + } + else + { + static int last_tag=0; + int tmp; + + tmp=TmpAddCurrent(); + + tag_dialog[D_TAG].data.i=last_tag; + + if (ListSize(selected)) + { + if (GUI_dialog("Tag number",D_TAG_NO,tag_dialog)) + { + SetTagObject(last_tag=tag_dialog[D_TAG].data.i); + DrawObjectInfo(); + } + + if (tmp) + ListEmpty(selected); + } + } + break; + + case GFX_F8: + if (edit_mode!=MULTI_MODE) + { + static int last_no=0; + + objno_dialog[D_OBJNO].data.i=last_no; + + if (GUI_dialog("Object number",D_OBJNO_NO,objno_dialog)) + { + Object *o; + int f; + + f=objno_dialog[D_OBJNO].data.i; + o=MapElem(map,f); + + if ((o)&&(o->data)) + { + last_no=objno_dialog[D_OBJNO].data.i; + + if (k.shift) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + + LocateObject(o->data); + GenericCheckMouse(); + FullRedraw(); + } + else + { + GuiInfoBox("ERROR","Object does not exist"); + FullRedraw(); + } + } + } + break; + + case GFX_ESC: + quit=TRUE; + break; + + default: + break; + } + else + switch(toupper(k.ascii)) + { + case 'R': + FullRedraw(); + break; + + case 'S': + SetEditMode(SECTOR_MODE); + break; + + case 'L': + SetEditMode(LINEDEF_MODE); + break; + + case 'V': + SetEditMode(VERTEX_MODE); + break; + + case 'T': + SetEditMode(THING_MODE); + break; + + case 'C': + SetEditMode(MULTI_MODE); + break; + + case '[': + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + RotateObject(5.0); + + if (tmp) + ListEmpty(selected); + + FullRedraw(); + } + + break; + } + + case ']': + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + RotateObject(-5.0); + + if (tmp) + ListEmpty(selected); + + FullRedraw(); + } + + break; + } + + case '{': + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + ScaleObject(0.90); + + if (tmp) + ListEmpty(selected); + + FullRedraw(); + } + + break; + } + + case '}': + { + int tmp; + + tmp=TmpAddCurrent(); + + if (ListSize(selected)) + { + ScaleObject(1.10); + + if (tmp) + ListEmpty(selected); + + FullRedraw(); + } + + break; + } + + default: + break; + } +} + + +void HandleMouse(GFXMouse m) +{ + TRACE; + + memcpy(&ms,&m,sizeof(m)); + GenericCheckMouse(); + DrawHeader(); +} + + +/* END OF FILE */ diff --git a/editgui.c b/editgui.c new file mode 100644 index 0000000..afb922d --- /dev/null +++ b/editgui.c @@ -0,0 +1,470 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + General editor GUI routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "editvar.h" +#include "texture.h" +#include "sectors.h" + +#include <stdarg.h> + +#define TXTPMT(lr,ulm) "Pick " ulm " texture for " lr " sidedef" + + +/* ---------------------------------------- GUI FUNCTIONS +*/ +int GetTexture(char *t,DirName d) +{ + int f; + + TRACE; + + if ((f=GUI_image_picklist(t,texture_picklist,TXT_PICKDEFVAL)) + !=TXT_PICKDEFVAL) + { + strcpy(d,texture_picklist[f].text); + return(TRUE); + } + else + return(FALSE); +} + + +int GetFlat(char *t,DirName d) +{ + int f; + + TRACE; + + if ((f=GUI_image_picklist(t,flat_picklist,TXT_PICKDEFVAL)) + !=TXT_PICKDEFVAL) + { + strcpy(d,flat_picklist[f].text); + return(TRUE); + } + else + return(FALSE); +} + + + +int GetLinedefValues(int set_class, + int r_floor, int l_floor, int r_ceiling, int l_ceiling, + int *type,int *flag,int *two, + DirName sr_upper,DirName sr_middle,DirName sr_lower, + DirName sl_upper,DirName sl_middle,DirName sl_lower) + +{ + TRACE; + + if (set_class) + { + if ((*type=SelectLinedef())==LINEDEF_NULLID) + return(FALSE); + } + else + *type=0; + + if (ChooseLinedefType(flag,two)) + { + if (*two) + { + if (r_floor<l_floor) + { + if (!GetTexture(TXTPMT("RIGHT","LOWER"),sr_lower)) + return(FALSE); + } + else + strcpy(sr_lower,empty_texture); + + if (r_ceiling>l_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_floor<r_floor) + { + if (!GetTexture(TXTPMT("LEFT","LOWER"),sl_lower)) + return(FALSE); + } + else + strcpy(sl_lower,empty_texture); + + if (l_ceiling>r_ceiling) + { + if (!GetTexture(TXTPMT("LEFT","UPPER"),sl_upper)) + return(FALSE); + } + else + strcpy(sl_upper,empty_texture); + + if (ask_middle_on_2sided) + { + if (!GetTexture(TXTPMT("LEFT","MIDDLE"),sl_middle)) + return(FALSE); + } + else + strcpy(sl_middle,empty_texture); + } + else + { + strcpy(sr_upper,empty_texture); + strcpy(sr_lower,empty_texture); + + if (!GetTexture("Pick MIDDLE texture for RIGHT sidedef",sr_middle)) + return(FALSE); + } + + return(TRUE); + } + + return(FALSE); +} + + +int GetSectorValues(int *line_type, int *line_flag, int *two_sided, + int *floor, int *ceiling, int *light, + int in_floor, int in_ceiling, + int *style_flags, + DirName floor_t, DirName ceiling_t, + DirName sr_upper, DirName sr_middle, DirName sr_lower, + DirName sl_upper, DirName sl_middle, DirName sl_lower) +{ + TRACE; + + if ((*line_type=SelectLinedef())==LINEDEF_NULLID) + return(FALSE); + + sector_val_dialog[D_SVAL_LIGHT].data.i=*light; + sector_val_dialog[D_SVAL_FLOOR].data.i=*floor; + sector_val_dialog[D_SVAL_CEILING].data.i=*ceiling; + + if (!GUI_dialog("Values for sector",D_SECTOR_VAL_NO,sector_val_dialog)) + return(FALSE); + + *floor=sector_val_dialog[D_SVAL_FLOOR].data.i; + *ceiling=sector_val_dialog[D_SVAL_CEILING].data.i; + *light=sector_val_dialog[D_SVAL_LIGHT].data.i; + + if (!ChooseLinedefType(line_flag,two_sided)) + return(FALSE); + + if (NoSectorStyles()) + { + if (!ChooseSectorStyle(style_flags,sr_upper,sr_middle,sr_lower, + floor_t,ceiling_t)) + return(FALSE); + + if (*two_sided) + { + strcpy(sl_upper,sr_upper); + strcpy(sl_middle,sr_middle); + strcpy(sl_lower,sr_lower); + + if (*floor>=in_floor) + strcpy(sr_lower,empty_texture); + + if (*ceiling<=in_ceiling) + strcpy(sr_upper,empty_texture); + + if (!ask_middle_on_2sided) + strcpy(sr_middle,empty_texture); + + if (in_floor>=*floor) + strcpy(sl_lower,empty_texture); + + if (in_ceiling<=*ceiling) + strcpy(sl_upper,empty_texture); + + if (!ask_middle_on_2sided) + strcpy(sl_middle,empty_texture); + } + else + { + strcpy(sr_upper,empty_texture); + strcpy(sr_lower,empty_texture); + } + } + else + { + *style_flags=0; + + if (!GetFlat("Choose floor texture",floor_t)) + return(FALSE); + + if (!GetFlat("Choose ceiling texture",ceiling_t)) + return(FALSE); + + if (*two_sided) + { + if (*floor<in_floor) + { + if (!GetTexture(TXTPMT("RIGHT","LOWER"),sr_lower)) + return(FALSE); + } + else + strcpy(sr_lower,empty_texture); + + if (*ceiling>in_ceiling) + { + if (!GetTexture(TXTPMT("RIGHT","UPPER"),sr_upper)) + return(FALSE); + } + else + strcpy(sr_upper,empty_texture); + + if (ask_middle_on_2sided) + { + if (!GetTexture(TXTPMT("RIGHT","MIDDLE"),sr_middle)) + return(FALSE); + } + else + strcpy(sr_middle,empty_texture); + + if (in_floor<*floor) + { + if (!GetTexture(TXTPMT("LEFT","LOWER"),sl_lower)) + return(FALSE); + } + else + strcpy(sl_lower,empty_texture); + + if (in_ceiling>*ceiling) + { + if (!GetTexture(TXTPMT("LEFT","UPPER"),sl_upper)) + return(FALSE); + } + else + strcpy(sl_upper,empty_texture); + + if (ask_middle_on_2sided) + { + if (!GetTexture(TXTPMT("LEFT","MIDDLE"),sl_middle)) + return(FALSE); + } + else + strcpy(sl_middle,empty_texture); + } + else + { + strcpy(sr_upper,empty_texture); + strcpy(sr_lower,empty_texture); + + if (!GetTexture("Pick MIDDLE texture for RIGHT sidedef",sr_middle)) + return(FALSE); + } + } + + return(TRUE); +} + + +int PickPoint(char *p, int *x, int *y, void (*draw)(int *x,int *y), + void (*key)(GFXKey k), + void (*infobox)(char *p)) +{ + GFXEvent e; + int cx,cy; + int done; + int cancel; + + TRACE; + + draw_current_info=FALSE; + FullRedraw(); + + done=FALSE; + cancel=FALSE; + + cx=XToMap(ms.x); + cy=YToMap(ms.y); + + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + cx=SnapX(cx); + cy=SnapY(cy); + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + if (infobox) + infobox(p); + else + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,TRUE, + "Press button to select point|Press ESC to cancel"); + + GFX_redraw(); + + while(!done) + { + GFX_await_input_full(&e); + + switch(e.type) + { + case GFX_MOUSE_EVENT: + + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + memcpy(&ms,&e.mouse,sizeof(e.mouse)); + + if (ms.b) + done=TRUE; + + DrawHeader(); + cx=XToMap(ms.x); + cy=YToMap(ms.y); + + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + cx=SnapX(cx); + cy=SnapY(cy); + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + if (infobox) + infobox(p); + else + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,TRUE, + "Press button to select point|Press ESC to cancel"); + + GFX_redraw(); + + break; + + case GFX_KEY_EVENT: + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + HandleMoveKey(e.key,FALSE); + cx=SnapX(XToMap(ms.x)); + cy=SnapY(YToMap(ms.y)); + + if (key) + key(e.key); + + GFX_set_XOR_mode(); + + if (draw) + draw(&cx,&cy); + else + { + GFX_line(0,MapToY(cy),SCRW-1,MapToY(cy),WHITE); + GFX_line(MapToX(cx),0,MapToX(cx),SCRH-1,WHITE); + } + + GFX_clear_XOR_mode(); + + if (infobox) + infobox(p); + else + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,TRUE, + "Press button to select point|Press ESC to cancel"); + + GFX_redraw(); + + if (e.key.code==GFX_ESC) + { + done=TRUE; + cancel=TRUE; + } + + break; + + default: + break; + } + } + + draw_current_info=TRUE; + FullRedraw(); + + *x=cx; + *y=cy; + + return(!cancel); +} + + +int YesNo(char *fmt,...) +{ + static char s[512]; + va_list va; + + va_start(va,fmt); + vsprintf(s,fmt,va); + va_end(va); + + return(GUI_yesno(s)); +} + + +/* END OF FILE */ diff --git a/editilst.c b/editilst.c new file mode 100644 index 0000000..f7a6763 --- /dev/null +++ b/editilst.c @@ -0,0 +1,106 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor integer list routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" + + +/* ---------------------------------------- PRIVATE ROUTINES +*/ + + +/* ---------------------------------------- EXPORTED ROUTINES +*/ +int InIntList(List l, int i) +{ + Iterator li; + int *f; + + li=ListIterator(l); + + while(li) + { + f=IteratorData(li); + + if (*f==i) + { + IteratorClear(li); + return(TRUE); + } + + li=IteratorNext(li); + } + + return(FALSE); +} + + +void IntListUniqAdd(List l, int i) +{ + Iterator li; + int *f; + + li=ListIterator(l); + + while(li) + { + f=IteratorData(li); + + if (*f==i) + { + IteratorClear(li); + return; + } + + li=IteratorNext(li); + } + + ListAppend(l,&i); +} + + +void IntListRm(List l, int i) +{ + Iterator li; + int *f; + + li=ListIterator(l); + + while(li) + { + f=IteratorData(li); + + if (*f==i) + li=IteratorDelete(li); + else + li=IteratorNext(li); + } +} + + +/* END OF FILE */ diff --git a/editline.c b/editline.c new file mode 100644 index 0000000..6ec521e --- /dev/null +++ b/editline.c @@ -0,0 +1,3361 @@ +/* + + 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 <math.h> +#include <ctype.h> + +#include "editvar.h" +#include "sectors.h" +#include "texture.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)<MAX_STEPS) \ + { \ + p[*idx].x=X; \ + p[*idx].y=Y; \ + (*idx)++; \ + } \ + } \ + } while(0) + +/* ---------------------------------------- STEP CREATION SHARED DATA +*/ +#define MIN_STEPS 1 +#define MAX_STEPS 128 + +struct { + int x; + int y; + + EditLine *from; + EditLine *to; + int from_c; + int to_c; + int from_f; + int to_f; + + int swap; + Point vf[2]; + Point vt[2]; + + int no; + double step_f; + double step_c; + int circular; + int side; + + Point p[2][MAX_STEPS+2]; + } step; + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static void DrawLinedef(EditLine *l, int col) +{ + double dx,dy; + + TRACE; + + dx=((l->v[0]->v.x)-(l->v[1]->v.x))/2; + dy=((l->v[0]->v.y)-(l->v[1]->v.y))/2; + + MapLineD(l,col); + + MapLine((int)(l->v[0]->v.x-dx),(int)(l->v[0]->v.y-dy), + (int)(l->v[0]->v.x-dx-dy/6),(int)(l->v[0]->v.y-dy+dx/6),col); +} + + +static int SelColour(int selmode) +{ + switch(selmode) + { + case SELECT_OVER: + return(OVERCOL); + break; + case SELECT_SELECTED: + return(SELCOL); + break; + default: + if (edit_mode==SECTOR_MODE) + return(SECTCOL); + else + return(LINECOL); + break; + } +} + + +static void RemoveHighlights(List l) +{ + Iterator i; + Object *o; + int *n; + + i=ListIterator(l); + + while(i) + { + n=IteratorData(i); + + if ((o=MapElem(linedef,*n))) + DrawLinedef(o->data,SelColour(o->select)); + + i=IteratorNext(i); + } +} + + +static void LineSelectionCentre(int *x,int *y) +{ + int *f; + EditLine *l; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + min_x=MIN(l->min_x,min_x); + min_y=MIN(l->min_y,min_y); + max_x=MAX(l->max_x,max_x); + max_y=MAX(l->max_y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +static void DeleteLeftSidedef(EditLine *l) +{ + Object *o; + int n; + int del; + int side; + EditLine *cl; + + TRACE; + + if (l->l.left==-1) + return; + + l->sl=NULL; + side=l->l.left; + l->l.left=-1; + + /* Free up the sidedef if there is no other linedef + bound to it + */ + del=TRUE; + + for(n=0;(n<MapSize(linedef))&&(del);n++) + { + cl=GETLINE(n); + + if ((cl)&&((cl->l.left==side)||(cl->l.right==side))) + del=FALSE; + } + + if (del) + { + o=MapElem(sidedef,side); + Release(o->data); + o->data=NULL; + } +} + + +static void DeleteRightSidedef(EditLine *l) +{ + Object *o; + int n; + int del; + int side; + EditLine *cl; + + TRACE; + + if (l->l.right==-1) + return; + + l->sr=NULL; + side=l->l.right; + l->l.right=-1; + + /* Free up the sidedef if there is no other linedef + bound to it + */ + del=TRUE; + + for(n=0;(n<MapSize(linedef))&&(del);n++) + { + cl=GETLINE(n); + + if ((cl)&&((cl->l.left==side)||(cl->l.right==side))) + del=FALSE; + } + + if (del) + { + o=MapElem(sidedef,side); + Release(o->data); + o->data=NULL; + } +} + + +static void DeleteLinedef(int f) +{ + Object *o; + EditLine *l; + + TRACE; + + o=MapElem(linedef,f); + l=o->data; + DeleteLeftSidedef(l); + DeleteRightSidedef(l); + + IntListRm(l->v[0]->l,f); + IntListRm(l->v[1]->l,f); + + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; +} + + +static int SplitLinedef(int f) +{ + Object o; + EditLine *l,*nl; + Sidedef *nsl,*nsr; + EditVert *nv; + int n_nl,dx,dy,tw; + + TRACE; + + l=GETLINE(f); + + o.select=SELECT_NONE; + + /* Create copies of the original linedefs and sidedefs + */ + nl=Grab(sizeof(EditLine)); + memcpy(nl,l,sizeof(EditLine)); + o.data=nl; + n_nl=MapSize(linedef); + nl->no=n_nl; + MapAdd(linedef,n_nl,&o); + + nsr=Grab(sizeof(Sidedef)); + memcpy(nsr,l->sr,sizeof(Sidedef)); + o.data=nsr; + nl->l.right=MapSize(sidedef); + MapAdd(sidedef,nl->l.right,&o); + nl->sr=GETSIDE(nl->l.right); + + if (l->l.left!=-1) + { + nsl=Grab(sizeof(Sidedef)); + memcpy(nsl,l->sl,sizeof(Sidedef)); + o.data=nsl; + nl->l.left=MapSize(sidedef); + MapAdd(sidedef,nl->l.left,&o); + nl->sl=GETSIDE(nl->l.left); + } + else + nsl=NULL; + + /* Work out the middle of the current line and create the vertex there + */ + nv=Grab(sizeof(EditVert)); + nv->l=ListNew(sizeof(int)); + + dx=((l->v[1]->v.x)-(l->v[0]->v.x))/2; + dy=((l->v[1]->v.y)-(l->v[0]->v.y))/2; + + nv->v.x=l->v[0]->v.x+dx; + nv->v.y=l->v[0]->v.y+dy; + o.data=nv; + + /* Update the vertex map, and the from/to in the old/new linedefs + */ + nl->l.from=MapSize(vertex); + MapAdd(vertex,nl->l.from,&o); + + l->l.to=nl->l.from; + + l->v[1]=GETVERT(l->l.to); + nl->v[0]=GETVERT(nl->l.from); + + /* Update the vertex lists + */ + IntListRm(nl->v[1]->l,f); + IntListUniqAdd(nl->v[0]->l,f); + IntListUniqAdd(nl->v[0]->l,n_nl); + + /* Align textures + */ + tw=CalcTextureWidth(nsr->upper,nsr->middle,nsr->lower); + + if (tw) + nsr->x=(l->sr->x+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + else + nsr->x=0; + + if (nsl) + { + tw=CalcTextureWidth(nsl->upper,nsl->middle,nsl->lower); + if (tw) + nsl->x=(l->sl->x+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + else + nsl->x=0; + } + + /* New linedef no + */ + return(n_nl); +} + + +/* ---------------------------------------- STEP CREATION CODE CALCULATIONS +*/ +static void DoCalcLine (int x0,int y0,int x1,int y1, + Point p[],int step,int *idx,int *len) +{ + int dx,dy,ix,iy,incre,incrne,d,x,y,ymode; + int p1x,p1y,p2x,p2y; + + TRACE; + + p1x=x0; + p1y=y0; + p2x=x1; + p2y=y1; + + dx=p2x-p1x; + dy=p2y-p1y; + + ix=SGN(dx); + iy=SGN(dy); + + dx=ABS(dx); + dy=ABS(dy); + + if (dy>dx) + { + ymode=TRUE; + d=dx*2-dy; + incre=dx*2; + incrne=(dx-dy)*2; + } + else + { + ymode=FALSE; + d=dy*2-dx; + incre=dy*2; + incrne=(dy-dx)*2; + } + + x=p1x; + y=p1y; + + CHECKSTEP(x,y); + + if (ymode) + while(y!=p2y) + { + if (d<=0) + { + d+=incre; + y+=iy; + } + else + { + d+=incrne; + y+=iy; + x+=ix; + } + + CHECKSTEP(x,y); + } + else + while(x!=p2x) + { + if (d<=0) + { + d+=incre; + x+=ix; + } + else + { + d+=incrne; + y+=iy; + x+=ix; + } + + CHECKSTEP(x,y); + } +} + + +static void DoCalcSpline (int x0,int y0,int x1,int y1,int x2,int y2, + Point p[],int step,int *idx,int *len) +{ + int xa, ya, xb, yb, xc, yc, xp, yp; + + TRACE; + + if ((x0==x1==x2)&&(y0==y1==y2)) + { + CHECKSTEP(x0,y0); + return; + } + + if ((x0==x1)&&(y0==y1)) + { + if (p) + DoCalcLine(x1,y1,x2,y2,p,step,idx,len); + else + *len+=Len(x1,y1,x2,y2); + return; + } + + if ((x0==x2)&&(y0==y2)) + { + if (p) + DoCalcLine(x0,y0,x1,y1,p,step,idx,len); + else + *len+=Len(x0,y0,x1,y1); + return; + } + + if ((x1==x2)&&(y1==y2)) + { + if (p) + DoCalcLine(x0,y0,x2,y2,p,step,idx,len); + else + *len+=Len(x0,y0,x2,y2); + return; + } + + xa = ( x0 + x1 ) / 2; + ya = ( y0 + y1 ) / 2; + xc = ( x1 + x2 ) / 2; + yc = ( y1 + y2 ) / 2; + xb = ( xa + xc ) / 2; + yb = ( ya + yc ) / 2; + + xp = ( x0 + xb ) / 2; + yp = ( y0 + yb ) / 2; + + if ( ABS( xa - xp ) + ABS( ya - yp ) > SPLINE_THRESH ) + DoCalcSpline(x0,y0,xa,ya,xb,yb,p,step,idx,len); + else + if (p) + DoCalcLine(x0,y0,xb,yb,p,step,idx,len); + else + *len+=Len(x0,y0,xb,yb); + + xp = ( x2 + xb ) / 2; + yp = ( y2 + yb ) / 2; + if ( ABS( xc - xp ) + ABS( yc - yp ) > SPLINE_THRESH ) + DoCalcSpline(xb,yb,xc,yc,x2,y2,p,step,idx,len); + else + if (p) + DoCalcLine(xb,yb,x2,y2,p,step,idx,len); + else + *len+=Len(xb,yb,x2,y2); +} + + +static void Spline(int x0,int y0, int x1, int y1, int x2, int y2, + Point p[],int step) +{ + int len; + int idx; + + TRACE; + + len=0; + idx=0; + DoCalcSpline(x0,y0,x1,y1,x2,y2,p,step,&idx,&len); +} + + +static int SplineLen(int x0,int y0, int x1, int y1, int x2, int y2) +{ + int len; + + TRACE; + + len=0; + DoCalcSpline(x0,y0,x1,y1,x2,y2,NULL,0,NULL,&len); + return (len); +} + + +static void CalcSteps(void) +{ + double dx,dy; + int f,r; + int len; + + TRACE; + + step.step_f=((double)step.to_f-step.from_f)/(step.no+2); + step.step_c=((double)step.to_c-step.from_c)/(step.no+2); + + if (step.circular) + { + f=step.side; + + len=SplineLen(step.vf[f].x,step.vf[f].y,step.x,step.y, + step.vt[f].x,step.vt[f].y); + + len=(int)((double)len/((double)step.no+1.0)+1.0); + + if (len<1) + len=1; + + Spline(step.vf[f].x,step.vf[f].y,step.x,step.y, + step.vt[f].x,step.vt[f].y,&step.p[f][1],len); + + step.p[f][0].x=step.vf[f].x; + step.p[f][0].y=step.vf[f].y; + + step.p[f][step.no+1].x=step.vt[f].x; + step.p[f][step.no+1].y=step.vt[f].y; + } + else + for(f=0;f<2;f++) + { + dx=(double)(step.vt[f].x-step.vf[f].x)/(step.no+1); + dy=(double)(step.vt[f].y-step.vf[f].y)/(step.no+1); + + for(r=1;r<=step.no;r++) + { + step.p[f][r].x=(int)(step.vf[f].x+(dx*r)); + step.p[f][r].y=(int)(step.vf[f].y+(dy*r)); + } + + step.p[f][0].x=step.vf[f].x; + step.p[f][0].y=step.vf[f].y; + + step.p[f][step.no+1].x=step.vt[f].x; + step.p[f][step.no+1].y=step.vt[f].y; + } +} + + +int SectorInBox(Point tl, Point br) +{ + int x,y; + + x=tl.x+(br.x-tl.x)/2; + y=tl.y+(br.y-tl.y)/2; + + return (SectorHoldingPoint(x,y)); +} + + +/* ---------------------------------------- STEP CREATION CALLBACKS +*/ +static void PickDraw(int *x, int *y) +{ + int f; + + TRACE; + + step.x=*x; + step.y=*y; + + if (step.circular) + CalcSteps(); + + for(f=0;f<2;f++) + MapLine(step.p[f][0].x,step.p[f][0].y, + step.p[f][1].x,step.p[f][1].y,LINECOL); + + for(f=1;f<=step.no;f++) + { + MapLine(step.p[0][f].x,step.p[0][f].y, + step.p[1][f].x,step.p[1][f].y,LINECOL); + + MapLine(step.p[0][f].x,step.p[0][f].y, + step.p[0][f+1].x,step.p[0][f+1].y,LINECOL); + + MapLine(step.p[1][f].x,step.p[1][f].y, + step.p[1][f+1].x,step.p[1][f+1].y,LINECOL); + } +} + + +static void PickKey(GFXKey k) +{ + TRACE; + + if (k.code==GFX_ASCII) + switch(toupper(k.ascii)) + { + case 'C': + step.circular=!step.circular; + CalcSteps(); + break; + + case 'S': + step.side^=1; + CalcSteps(); + break; + + case 'R': + step.swap=!step.swap; + + if (!step.swap) + { + SetPoint(step.vf[0],step.from->v[0]); + SetPoint(step.vf[1],step.from->v[1]); + SetPoint(step.vt[0],step.to->v[0]); + SetPoint(step.vt[1],step.to->v[1]); + } + else + { + SetPoint(step.vf[0],step.from->v[0]); + SetPoint(step.vf[1],step.from->v[1]); + SetPoint(step.vt[0],step.to->v[1]); + SetPoint(step.vt[1],step.to->v[0]); + } + + CalcSteps(); + + if (step.circular) + { + step.side^=1; + CalcSteps(); + step.side^=1; + } + + break; + + case '+': + if (step.no<MAX_STEPS) + { + step.no++; + CalcSteps(); + + if (step.circular) + { + step.side^=1; + CalcSteps(); + step.side^=1; + } + } + break; + + case '-': + if (step.no>MIN_STEPS) + { + step.no--; + CalcSteps(); + + if (step.circular) + { + step.side^=1; + CalcSteps(); + step.side^=1; + } + } + break; + } +} + + +static void PickInfo(char *p) +{ + TRACE; + + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "No : %d|" + "Step (F) : %d|" + "Step (C) : %d|" + "Mode : %-s|" + "Side : %d", + step.no,ABS((int)step.step_f),ABS((int)step.step_c), + step.circular ? "Curve " : "Straight", + step.side); + + GuiDrawInfoBox(p,GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "+ - increase number of steps|" + "- - decrease number of steps|" + "C - change between straight/curve|" + "S - change wall being moved in curve mode|" + "R - swap vertex matching|" + " |" + "Press left button to complete. ESC to cancel"); +} + + +/* ---------------------------------------- STEP CREATION CODE +*/ +typedef struct + { + int line; + int apply; + } TextureMatch; + +static void ApplyTextureOffset(List li,int tw,int right) +{ + int off; + Iterator i; + TextureMatch *tm; + EditLine *l; + Sidedef *s; + + TRACE; + + i=ListIterator(li); + off=0; + + while(i) + { + tm=IteratorData(i); + + l=GETLINE(tm->line); + + if (tm->apply) + { + if (right) + s=l->sr; + else + s=l->sl; + + s->x=off; + } + + off=(off+Len(l->v[0]->v.x,l->v[0]->v.y,l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } +} + + +static int CreateSteps(int i_from, int i_to) +{ + EditSect *s; + EditLine *from,*to; + DirName upper,lower,middle,floor,ceiling; + int s_flag; + int type; + + TRACE; + + from=GETLINE(i_from); + to=GETLINE(i_to); + + if ((Len(from->v[0]->v.x,from->v[0]->v.y, + from->v[1]->v.x,from->v[1]->v.y)==0)|| + (Len(to->v[0]->v.x,to->v[0]->v.y,to->v[1]->v.x,to->v[1]->v.y)==0)) + { + GuiInfoBox("ERROR","Lines must be non-zero length"); + return(FALSE); + } + + if (((from->l.from==to->l.from)&&(to->l.to==to->l.to))|| + ((from->l.from==to->l.to)&&(to->l.to==to->l.from))) + { + GuiInfoBox("ERROR","Lines cannot share a vertex"); + return(FALSE); + } + + if (!(LinesCrossV(from->v[0],to->v[0],from->v[1],to->v[1]))) + { + step.swap=FALSE; + SetPoint(step.vf[0],from->v[0]); + SetPoint(step.vf[1],from->v[1]); + SetPoint(step.vt[0],to->v[0]); + SetPoint(step.vt[1],to->v[1]); + } + else + { + step.swap=TRUE; + SetPoint(step.vf[0],from->v[0]); + SetPoint(step.vf[1],from->v[1]); + SetPoint(step.vt[0],to->v[1]); + SetPoint(step.vt[1],to->v[0]); + } + + step.x=ms.x; + step.y=ms.y; + step.from=from; + step.to=to; + step.no=1; + step.circular=FALSE; + step.side=0; + + s=GETSECT(from->sr->sector); + step.from_c=s->s.ceiling; + step.from_f=s->s.floor; + + s=GETSECT(to->sr->sector); + step.to_c=s->s.ceiling; + step.to_f=s->s.floor; + + CalcSteps(); + + if ((PickPoint("Create steps",&step.x,&step.y,PickDraw,PickKey,PickInfo))&& + (ChooseSectorStyle(&s_flag,upper,middle,lower,floor,ceiling))&& + ((type=SelectSector())!=SECTOR_NULLID)) + { + Object o; + EditLine *el; + EditVert *ev[2][MAX_STEPS+2]; + EditSect *s; + Sidedef *ns; + TextureMatch tm; + List side_sl[2],side_sr[2]; + int n; + int v[2][MAX_STEPS+2]; + int do_ceiling; + double fh,ch; + int prev_fh,prev_ch; + int in_sect[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)fh<s->s.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_ch<step.to_c) + { + strcpy(el->sr->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_fh<step.to_f) + { + 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=prev_sect; + + o.data=ns; + o.select=SELECT_NONE; + + n=MapSize(sidedef); + MapAdd(sidedef,n,&o); + el->sl=ns; + el->l.left=n; + + /* Calculate the texture offsets for the walls + */ + for(f=0;f<2;f++) + { + ApplyTextureOffset(side_sl[f],tw,FALSE); + ApplyTextureOffset(side_sr[f],tw,TRUE); + + ListClear(side_sl[f]); + ListClear(side_sr[f]); + } + + SectorCalcContainingAll(); + + return(TRUE); + } + else + return(FALSE); +} + + +/* ---------------------------------------- LINEDEF VECTOR MAP UTILS +*/ + +/* Note this is repeated, rather than shared with the sector vector map to save + any unexpected later interactions +*/ +static int vno=0; +static char *vmap=NULL; + +static void InitVMAP(void) +{ + TRACE; + + if (vno<MapSize(vertex)) + vmap=ReGrab(vmap,MapSize(vertex)); + + memset(vmap,FALSE,MapSize(vertex)); +} + + +/* ---------------------------------------- SECTOR LINEDEF MAP UTILS +*/ +static int lno=0; +static char *lmap=NULL; + +static void InitLMAP(void) +{ + TRACE; + + if (lno<MapSize(linedef)) + lmap=ReGrab(lmap,MapSize(linedef)); + + memset(lmap,FALSE,MapSize(linedef)); +} + + +/* ---------------------------------------- LINEDEF TRACK FUNCTIONS +*/ +List TrackLinedef(int line_no) +{ + EditSect *s; + EditLine *l; + List ll; + Iterator i; + int sec_no; + int done; + int f; + int vert_no; + + TRACE; + + if (!(l=GETLINE(line_no))) + return(NULL); + + InitLMAP(); + + lmap[line_no]=TRUE; + + ll=ListNew(sizeof(int)); + ListAppend(ll,&line_no); + + sec_no=l->sr->sector; + + if (!(s=GETSECT(sec_no))) + return(ll); + + vert_no=l->l.to; + + /* If the start LINEDEF is 2-sided and wholy within the sector, we only + track along connected 2-sided lines in the same sector. + + If the start line is 1-sided then we allow both 1 and 2 sided LINEDEFs + in the resulting list, but only 2 sided LINEDEFs that just have this + sector on one side of the line. + + To make this easier we mark the LMAP entries for those lines we wish to + ignore before starting. + */ + if ((l->sl)&&(l->sl->sector==sec_no)) + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if (!l->sl) + lmap[l->no]=TRUE; + else + if (!((l->sl->sector==sec_no)&&(l->sr->sector==sec_no))) + lmap[l->no]=TRUE; + + i=IteratorNext(i); + } + } + else + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if ((l->sl)&&(l->sl->sector==sec_no)&&(l->sr->sector==sec_no)) + lmap[l->no]=TRUE; + + i=IteratorNext(i); + } + } + + done=FALSE; + + while(!done) + { + done=TRUE; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + f=l->no; + + if (!lmap[f]) + { + /* We need two seperate checks, as obviously left sidedefs + pointing into the sector will need TO, rather than FROM, + checking + */ + if ((l->sr->sector==sec_no)&&(l->l.from==vert_no)) + { + lmap[f]=TRUE; + ListAppend(ll,&f); + done=FALSE; + vert_no=l->l.to; + } + else if ((l->sl)&&(l->sl->sector==sec_no)&&(l->l.to==vert_no)) + { + lmap[f]=TRUE; + ListAppend(ll,&f); + done=FALSE; + vert_no=l->l.from; + } + } + + i=IteratorNext(i); + } + } + + return(ll); +} + + +/* ---------------------------------------- LINEDEF MERGING +*/ +void CheckMergeLinedef(EditVert *v) +{ + Iterator i; + int *f; + int r; + EditLine *ol,*cl; + int same_dir; + int merge; + + TRACE; + + i=ListIterator(v->l); + + while(i) + { + f=IteratorData(i); + + ol=GETLINE(*f); + + for(r=0;r<MapSize(linedef);r++) + if ((r!=*f)&&(cl=GETLINE(r))) + { + if (((cl->l.from==ol->l.from)&&(cl->l.to==ol->l.to))|| + ((cl->l.from==ol->l.to)&&(cl->l.to==ol->l.from))) + { + if ((cl->l.from==ol->l.from)&&(cl->l.to==ol->l.to)) + same_dir=TRUE; + else + same_dir=FALSE; + + if(merge_linedef==MERGE_ASK) + merge=YesNo("Linedefs %d and %d overlap. Merge?",*f,r); + else + merge=TRUE; + + if (merge) + { + if (same_dir) + { + if (cl->l.left!=-1) + { + DeleteLeftSidedef(ol); + ol->l.left=cl->l.left; + ol->sl=GETSIDE(ol->l.left); + ol->l.flags|=side2_mask; + + if (auto_block_linedefs) + ol->l.flags&=~block_mask; + } + } + else + { + DeleteLeftSidedef(ol); + ol->l.left=cl->l.right; + ol->sl=GETSIDE(ol->l.left); + ol->l.flags|=side2_mask; + + if (auto_block_linedefs) + ol->l.flags&=~block_mask; + } + + DeleteLinedef(r); + } + } + } + + i=IteratorNext(i); + } +} + + +/* ---------------------------------------- LINEDEF CREATION +*/ +int CreateNewLinedef(int from, int to, + int flags, int type, int tag, int two_sided, + int sr_ox, int sr_oy, int sr_sector, + DirName sr_upper, DirName sr_middle, DirName sr_lower, + int sl_ox, int sl_oy, int sl_sector, + DirName sl_upper, DirName sl_middle, DirName sl_lower) +{ + Object o; + EditLine *l; + Sidedef *s; + int ln,srn,sln; + + TRACE; + + ln=MapSize(linedef); + + srn=MapSize(sidedef); + + if (two_sided) + sln=srn+1; + else + sln=-1; + + o.select=SELECT_NONE; + + s=Grab(sizeof(Sidedef)); + s->x=sr_ox; + s->y=sr_oy; + s->sector=sr_sector; + strcpy(s->upper,sr_upper); + strcpy(s->middle,sr_middle); + strcpy(s->lower,sr_lower); + o.data=s; + MapAdd(sidedef,srn,&o); + + if (sln!=-1) + { + s=Grab(sizeof(Sidedef)); + s->x=sl_ox; + s->y=sl_oy; + s->sector=sl_sector; + strcpy(s->upper,sl_upper); + strcpy(s->middle,sl_middle); + strcpy(s->lower,sl_lower); + o.data=s; + MapAdd(sidedef,sln,&o); + } + + l=Grab(sizeof(EditLine)); + + l->no=ln; + + l->l.from=from; + l->l.to=to; + + l->l.flags=flags; + l->l.type=type; + l->l.tag=tag; + + l->v[0]=GETVERT(l->l.from); + l->v[1]=GETVERT(l->l.to); + + l->l.right=srn; + l->l.left=sln; + + l->sr=GETSIDE(srn); + + if (sln!=-1) + l->sl=GETSIDE(sln); + else + l->sl=NULL; + + if (edit_mode==LINEDEF_MODE) + switch(insert_select) + { + case HOVER_NONE: + o.select=SELECT_NONE; + break; + case HOVER_ADD: + case HOVER_SINGLE: + o.select=SELECT_SELECTED; + break; + } + else + o.select=SELECT_NONE; + + LineCalcBounding(l); + o.data=l; + MapAdd(linedef,ln,&o); + + if (edit_mode==LINEDEF_MODE) + switch(insert_select) + { + case HOVER_NONE: + break; + case HOVER_ADD: + ListAppend(selected,&ln); + break; + case HOVER_SINGLE: + ClearSelection(); + o.select=SELECT_SELECTED; + ListAppend(selected,&ln); + FullRedraw(); + break; + } + + return(ln); +} + + +/* ---------------------------------------- GENERIC LINEDEF FUNCS +*/ +int PositionOnObject_LINEDEF(int x,int y,void *data) +{ + EditLine *l; + + TRACE; + + l=data; + + /* + if (scale<4) + box=BOXBOUND_FUZZY(x,y,l->min_x,l->min_y,l->max_x,l->max_y,2); + else + box=BOXBOUND_FUZZY(x,y,l->min_x,l->min_y,l->max_x,l->max_y,scale/2); + + if (!box) + return(FALSE); + */ + + if(LinesCross(x-(scale*linedef_select),y,x+(scale*linedef_select),y, + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)) + return(TRUE); + + return(LinesCross(x,y-(scale*linedef_select),x,y+(scale*linedef_select), + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)); +} + + +void SelectBox_LINEDEF(int x1,int y1,int x2,int y2) +{ + Object *o; + EditLine *l; + int f; + + TRACE; + + for(f=0;f<MapSize(linedef);f++) + { + o=MapElem(linedef,f); + + if ((l=o->data)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(l->v[0]->v.x,l->v[0]->v.y,x1,y1,x2,y2))&& + (BOXBOUND(l->v[1]->v.x,l->v[1]->v.y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_LINEDEF(void) +{ + Object *o; + EditLine *l; + int id; + int f; + + if ((id=SelectLinedef())!=LINEDEF_NULLID) + { + ClearSelection(); + + for(f=0;f<MapSize(linedef);f++) + if ((o=MapElem(linedef,f))) + if ((l=o->data)&&(l->l.type==id)) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } +} + + +void DrawObject_LINEDEF(void *data, int selmode) +{ + static List hilite=NULL; + static int drawn=FALSE; + Iterator i; + EditLine *l; + EditLine *sl=NULL; + EditSect *s; + Object *o; + int f; + + TRACE; + + if (!hilite) + hilite=ListNew(sizeof(int)); + + l=data; + + /* If the current object has changed, remove the highlighted tag objects + */ + if ((current==-1)&&(drawn)) + { + drawn=FALSE; + RemoveHighlights(hilite); + ListEmpty(hilite); + } + + /* Draw tagged sectors + */ + if ((tag_highlight)&&(current==l->no)) + { + RemoveHighlights(hilite); + ListEmpty(hilite); + + if (l->l.tag) + { + drawn=TRUE; + + for(f=0;f<MapSize(sector);f++) + if ((s=GETSECT(f))) + if ((s->s.tag==l->l.tag)&&(SectorOnDisplay(s))) + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&sl,IteratorData(i),sizeof(sl)); + o=MapElem(linedef,sl->no); + + if (o->select==SELECT_NONE) + { + ListAppend(hilite,&(sl->no)); + DrawLinedef(sl,TAGCOL); + } + + i=IteratorNext(i); + } + } + } + + } + + /* Only draw the line if it's not been drawn tagged or is selected. + */ + if ((!tag_highlight)||(selmode==SELECT_SELECTED)|| + (!InIntList(hilite,l->no))) + DrawLinedef(data,SelColour(selmode)); +} + + +void DrawObjectInfo_LINEDEF(void) +{ + EditLine *l; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((l=GETLINE(current)))) + { + if (show_full_linedef_info) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Type [%4.4x]: %-35.35s|" + "Tag : %-5d", + current, + LinedefFlagText(l->l.flags), + l->l.type,LinedefName(l->l.type),l->l.tag); + else + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Type [%4.4x]: %-20.20s|" + "Tag : %-5d", + current, + LinedefFlagText(l->l.flags), + l->l.type,LinedefClass(l->l.type),l->l.tag); + + GuiDrawInfoBox("RIGHT SIDEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Offset : %d,%d|" + "Upper : %-10s|" + "Middle : %-10s|" + "Lower : %-10s|" + "Sector : %d", + l->sr->x,l->sr->y, + l->sr->upper,l->sr->middle,l->sr->lower, + l->sr->sector); + + if (l->sl) + GuiDrawInfoBox("LEFT SIDEDEF",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Offset : %d,%d|" + "Upper : %-10s|" + "Middle : %-10s|" + "Lower : %-10s|" + "Sector : %d", + l->sl->x,l->sl->y, + l->sl->upper,l->sl->middle,l->sl->lower, + l->sl->sector); + else + GuiDrawInfoBox("NO LEFT SIDEDEF",GUI_FLUSH_LEFT, + GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + } + else + { + if (show_full_linedef_info) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Type : %35s|" + "Tag : -",""); + else + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Type : %20s|" + "Tag : -",""); + + GuiDrawInfoBox("RIGHT SIDEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + + GuiDrawInfoBox("LEFT SIDEDEF",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + } +} + + +void DrawObjectHeader_LINEDEF(void) +{ + if (tag_highlight) + GFX_print(0,FH,WHITE,"Tag highlight: ON"); + else + GFX_print(0,FH,WHITE,"Tag highlight: OFF"); +} + + +void MoveObject_LINEDEF(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditLine *l; + List orig; + int *f,r; + Point p; + unsigned char *vmap; + int cancel; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + + vmap=Grab(MapSize(vertex)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + p.x=l->v[0]->v.x; + p.y=l->v[0]->v.y; + ListAppend(orig,&p); + p.x=l->v[1]->v.x; + p.y=l->v[1]->v.y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move LINEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + + l=GETLINE(*f); + + memcpy(&p,IteratorData(i2),sizeof(Point)); + l->v[0]->v.x=p.x; + l->v[0]->v.y=p.y; + i2=IteratorNext(i2); + + memcpy(&p,IteratorData(i2),sizeof(Point)); + l->v[1]->v.x=p.x; + l->v[1]->v.y=p.y; + i2=IteratorNext(i2); + + i=IteratorNext(i); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + for(r=0;r<MapSize(vertex);r++) + vmap[r]=FALSE; + + i=ListIterator(selected); + while(i) + { + f=IteratorData(i); + + l=GETLINE(*f); + + if (!vmap[l->l.from]) + { + l->v[0]->v.x+=dmx; + l->v[0]->v.y+=dmy; + vmap[l->l.from]=TRUE; + } + + if (!vmap[l->l.to]) + { + l->v[1]->v.x+=dmx; + l->v[1]->v.y+=dmy; + vmap[l->l.to]=TRUE; + } + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + Release(vmap); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_LINEDEF(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditLine *l; + + TRACE; + + InitVMAP(); + + LineSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + if (!vmap[l->l.from]) + { + vmap[l->l.from]=TRUE; + x=l->v[0]->v.x; + y=l->v[0]->v.y; + + Rotate(cx,cy,&x,&y,angle); + + l->v[0]->v.x=x; + l->v[0]->v.y=y; + } + + if (!vmap[l->l.to]) + { + vmap[l->l.to]=TRUE; + x=l->v[1]->v.x; + y=l->v[1]->v.y; + + Rotate(cx,cy,&x,&y,angle); + + l->v[1]->v.x=x; + l->v[1]->v.y=y; + } + + i=IteratorNext(i); + } +} + + +void ScaleObject_LINEDEF(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditLine *l; + + TRACE; + + LineSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + x=l->v[0]->v.x; + y=l->v[0]->v.y; + + Scale(cx,cy,&x,&y,scale); + + l->v[0]->v.x=x; + l->v[0]->v.y=y; + + x=l->v[1]->v.x; + y=l->v[1]->v.y; + + Scale(cx,cy,&x,&y,scale); + + l->v[1]->v.x=x; + l->v[1]->v.y=y; + + i=IteratorNext(i); + } +} + + +void SetTagObject_LINEDEF(int tag) +{ + int *f; + Iterator i; + EditLine *l; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + l->l.tag=tag; + i=IteratorNext(i); + } +} + + +void LocateObject_LINEDEF(void *obj) +{ + int cx,cy; + EditLine *l; + + TRACE; + + l=obj; + cx=l->min_x+(l->max_x-l->min_x)/2; + cy=l->min_y+(l->max_y-l->min_y)/2; + ox=cx-scale*SCRW/2; + oy=cy+scale*SCRH/2; +} + + +void ObjectInsert_LINEDEF(void) +{ + int type; + int fl,two; + DirName sr_upper,sr_lower,sr_middle; + DirName sl_upper,sl_lower,sl_middle; + int ok; + int from,to; + int nl; + EditVert *v; + + TRACE; + + if (MapSize(vertex)<2) + { + GuiInfoBox("ERROR","Need more that 2 vertices|to make a line"); + FullRedraw(); + } + else + { + vertex_dialog[D_VERTEX_FROM].data.i=MapSize(vertex)-2; + vertex_dialog[D_VERTEX_TO].data.i=MapSize(vertex)-1; + + ok=GUI_dialog("Create LINEDEF",D_VERTEX_NO,vertex_dialog); + + if (ok) + { + from=vertex_dialog[D_VERTEX_FROM].data.i; + to=vertex_dialog[D_VERTEX_TO].data.i; + + if ((from>=MapSize(vertex))||(from<0)||(!GETVERT(from))) + { + GuiInfoBox("ERROR","%d (from) is an invalid vertex",from); + FullRedraw(); + ok=FALSE; + } + else if ((to>=MapSize(vertex))||(to<0)||(!GETVERT(to))) + { + GuiInfoBox("ERROR","%d (to) is an invalid vertex",to); + FullRedraw(); + ok=FALSE; + } + } + + if (ok) + if (GetLinedefValues(TRUE,0,0,0,0, + &type,&fl,&two, + sr_upper,sr_middle,sr_lower, + sl_upper,sl_middle,sl_lower)) + { + nl=CreateNewLinedef(from,to, + fl,type,0,two, + 0,0,0, + sr_upper,sr_middle,sr_lower, + 0,0,0, + sl_upper,sl_middle,sl_lower); + + v=GETVERT(from); + IntListUniqAdd(v->l,from); + v=GETVERT(to); + IntListUniqAdd(v->l,from); + + FullRedraw(); + } + } +} + + +void ObjectDelete_LINEDEF(void) +{ + Iterator i; + int *f; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + DeleteLinedef(*f); + i=IteratorNext(i); + } + + SectorCalcContainingAll(); + ClearSelection(); + FullRedraw(); +} + + +void ObjectMenu_LINEDEF(void) +{ + static int ax=0; + static int ay=0; + EditLine *l; + int f,*s; + Iterator i; + int cancel; + int opt; + + TRACE; + + s=NULL; + cancel=FALSE; + GFX_redraw(); + + opt=GUI_menu("Linedef/sidedef",ms.x,ms.y,linedef_popup,GUI_CANCEL); + + switch(opt) + { + case TM_RIGHT_SIDE: + opt=GUI_menu("Right sidedef",ms.x,ms.y,right_popup,GUI_CANCEL); + break; + + case TM_LEFT_SIDE: + opt=GUI_menu("Left sidedef",ms.x,ms.y,left_popup,GUI_CANCEL); + break; + + default: + break; + } + + switch(opt) + { + case TM_TYPE: + { + f=SelectLinedef(); + + if (f!=LINEDEF_NULLID) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + l->l.type=f; + i=IteratorNext(i); + } + + FullRedraw(); + } + break; + } + + case TM_FLAGS: + l=SelHead(); + f=l->l.flags; + + if (GUI_multi_box("Flags",LinedefFlagArray(),&f)) + { + int new_side; + List new; + + new=ListNew(sizeof(int)); + new_side=FALSE; + + i=ListIterator(selected); + + while(i) + { + int new_f; + + new_f=f; + s=IteratorData(i); + l=GETLINE(*s); + + /* If the line was 2 sided, and is now one - removed the + left sidedef + */ + if ((l->l.flags&side2_mask)&&(!(new_f&side2_mask))) + { + DeleteLeftSidedef(l); + + if (auto_block_linedefs) + new_f|=block_mask; + } + + /* If the line was 1 sided, and is now two - add the + left sidedef + */ + if ((!(l->l.flags&side2_mask))&&(new_f&side2_mask)) + { + Object o; + Sidedef *ns; + int n; + + ns=Grab(sizeof(Sidedef)); + ns->x=0; + ns->y=0; + strcpy(ns->upper,empty_texture); + strcpy(ns->middle,empty_texture); + strcpy(ns->lower,empty_texture); + ns->sector=-1; + + o.data=ns; + o.select=SELECT_NONE; + + n=MapSize(sidedef); + MapAdd(sidedef,n,&o); + l->sl=ns; + l->l.left=n; + + new_side=TRUE; + + ListAppend(new,s); + + if (auto_block_linedefs) + new_f&=~block_mask; + } + + l->l.flags=new_f; + i=IteratorNext(i); + } + + if (new_side) + switch(new_2sided_select) + { + case NEWSELECT_NEVER: + GuiInfoBox("NOTICE","Left SIDEDEFS have been added|" + "to some or all LINEDEFS"); + break; + + /* WARNING: This case cascades into the following + one + */ + case NEWSELECT_ASK: + if (!YesNo("New left SIDEDEFS created. " + "Select those LINEDEFS?")) + break; + case NEWSELECT_SELECT: + { + Object *o; + + new_selection=TRUE; + ClearSelection(); + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + ListAppend(selected,s); + i=IteratorNext(i); + } + break; + } + } + + ListClear(new); + + FullRedraw(); + } + + break; + + case TM_SWAP_SIDES: + { + int tmp; + Sidedef *tmp_s; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (l->l.left!=-1) + { + tmp=l->l.left; + tmp_s=l->sl; + + l->sl=l->sr; + l->l.left=l->l.right; + + l->sr=tmp_s; + l->l.right=tmp; + + tmp=l->l.from; + l->l.from=l->l.to; + l->l.to=tmp; + + l->v[0]=GETVERT(l->l.from); + l->v[1]=GETVERT(l->l.to); + } + + i=IteratorNext(i); + } + + SectorCalcContainingAll(); + FullRedraw(); + + break; + } + + case TM_SPLIT_LINE: + { + List new; + int no; + Object *o; + + new=ListNew(sizeof(int)); + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + no=SplitLinedef(*s); + ListAppend(new,&no); + i=IteratorNext(i); + } + + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + + ListAppend(selected,s); + i=IteratorNext(i); + } + + ListClear(new); + SectorCalcContainingAll(); + FullRedraw(); + + break; + } + + case TM_TRACK_LINE: + { + List new; + Object *o; + + i=ListIterator(selected); + + *s=MapSize(linedef)+1; + + while(i) + { + s=IteratorData(i); + i=IteratorNext(i); + } + + if ((new=TrackLinedef(*s))) + { + ClearSelection(); + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + ListAppend(selected,s); + + i=IteratorNext(i); + } + + ListClear(new); + new_selection=TRUE; + FullRedraw(); + } + + break; + } + + case TM_STEPS: + if (ListSize(selected)!=2) + GuiInfoBox("ERROR","Just select 2 linedefs|for this function"); + else + { + int *l1,*l2; + + i=ListIterator(selected); + l1=IteratorData(i); + i=IteratorNext(i); + l2=IteratorData(i); + IteratorClear(i); + + cancel=CreateSteps(*l1,*l2); + } + + FullRedraw(); + break; + + + case TM_OFFSET_R: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=l->sr->x; + offset_dialog[D_OFFSET_OFFY].data.i=l->sr->y; + + if (GUI_dialog("Right offset",D_OFFSET_NO,offset_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + { + l->sr->x=offset_dialog[D_OFFSET_OFFX].data.i; + l->sr->y=offset_dialog[D_OFFSET_OFFY].data.i; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_ADJUST_R: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=ax; + offset_dialog[D_OFFSET_OFFY].data.i=ay; + + if (GUI_dialog("Right offset adjustment",D_OFFSET_NO,offset_dialog)) + { + ax=offset_dialog[D_OFFSET_OFFX].data.i; + ay=offset_dialog[D_OFFSET_OFFY].data.i; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + { + l->sr->x+=ax; + l->sr->y+=ay; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_SECTOR_R: + l=SelHead(); + + sectorn_dialog[D_SECTORN_SECNO].data.i=l->sr->sector; + + if (GUI_dialog("Right sector",D_SECTORN_NO,sectorn_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + l->sr->sector=sectorn_dialog[D_SECTORN_SECNO].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + SectorCalcContainingAll(); + FullRedraw(); + } + + break; + + case TM_UPPER_T_R: + { + DirName d; + + if ((GetTexture("Upper Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->upper,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_MIDDLE_T_R: + { + DirName d; + + if ((GetTexture("Middle Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->middle,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_LOWER_T_R: + { + DirName d; + + if ((GetTexture("Lower Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->lower,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_ALIGN_R: + { + int tw; + int ox; + + l=SelHead(); + + tw=CalcTextureWidth(l->sr->upper,l->sr->middle,l->sr->lower); + + if (tw==0) + { + GuiInfoBox("ERROR","First selected linedef has no texture"); + FullRedraw(); + } + else + { + ox=l->sr->x; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + + l=GETLINE(*s); + + l->sr->x=ox; + + ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } + + FullRedraw(); + } + + } + break; + + + case TM_OFFSET_L: + l=SelHead(); + + if (l->sl) + { + offset_dialog[D_OFFSET_OFFX].data.i=l->sl->x; + offset_dialog[D_OFFSET_OFFY].data.i=l->sl->y; + } + + if (GUI_dialog("Left offset",D_OFFSET_NO,offset_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + { + l->sl->x=offset_dialog[D_OFFSET_OFFX].data.i; + l->sl->y=offset_dialog[D_OFFSET_OFFY].data.i; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_ADJUST_L: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=ax; + offset_dialog[D_OFFSET_OFFY].data.i=ay; + + if (GUI_dialog("Left offset adjustment",D_OFFSET_NO,offset_dialog)) + { + ax=offset_dialog[D_OFFSET_OFFX].data.i; + ay=offset_dialog[D_OFFSET_OFFY].data.i; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + { + l->sl->x+=ax; + l->sl->y+=ay; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_SECTOR_L: + l=SelHead(); + + if (l->sl) + sectorn_dialog[D_SECTORN_SECNO].data.i=l->sl->sector; + + if (GUI_dialog("Left sector",D_SECTORN_NO,sectorn_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + l->sl->sector=sectorn_dialog[D_SECTORN_SECNO].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + SectorCalcContainingAll(); + FullRedraw(); + } + + break; + + case TM_UPPER_T_L: + { + DirName d; + + if ((GetTexture("Upper Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->upper,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_MIDDLE_T_L: + { + DirName d; + + if ((GetTexture("Middle Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->middle,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_LOWER_T_L: + { + DirName d; + + if ((GetTexture("Lower Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->lower,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_ALIGN_L: + { + int tw; + int ox; + int ok; + + ok=TRUE; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (!(l->sl)) + ok=FALSE; + + i=IteratorNext(i); + } + + if (!ok) + { + GuiInfoBox("ERROR","Some linedefs with no left sidedef"); + FullRedraw(); + } + else + { + l=SelHead(); + + tw=CalcTextureWidth(l->sl->upper,l->sl->middle,l->sl->lower); + + if (tw==0) + { + GuiInfoBox("ERROR","First selected linedef has no texture"); + FullRedraw(); + } + else + { + ox=l->sl->x; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + + l=GETLINE(*s); + + l->sl->x=ox; + + ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } + + FullRedraw(); + } + } + + } + break; + + + case TM_TAG: + l=SelHead(); + tag_dialog[D_TAG].data.i=l->l.tag; + + if (GUI_dialog("Tag",D_TAG_NO,tag_dialog)) + { + SetTagObject_LINEDEF(tag_dialog[D_TAG].data.i); + FullRedraw(); + } + + break; + + case TM_DELETE: + ObjectDelete_LINEDEF(); + break; + + case TM_MOVE: + MoveObject_LINEDEF(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(!new_selection)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } +} + + +void ObjectKey_LINEDEF(GFXKey k) +{ + char s[128]; + EditLine *l; + int f; + int change; + List li; + Iterator i; + EditSect *sr,*sl; + DirName d; + Object *o; + int apply; + + TRACE; + + switch(k.code) + { + case GFX_F12: + li=ListNew(sizeof(int)); + + change=FALSE; + + if (ListSize(selected)==0) + { + GuiInfoBox("ERROR","No linedefs selected"); + FullRedraw(); + return; + } + + i=ListIterator(selected); + + while(i) + { + memcpy(&f,IteratorData(i),sizeof(f)); + + if ((l=GETLINE(f))) + { + TRACE; + if (check_1side_lower) + if ((!l->sl)&&(strcmp(l->sr->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with a " + "lower texture. Remove?",f))) + { + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + + TRACE; + if (check_1side_middle) + if ((!l->sl)&&(!strcmp(l->sr->middle,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with no " + "middle texture. Add?",f))) + { + sprintf(s,"Pick MIDDLE texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->middle,d); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if (check_1side_upper) + if ((!l->sl)&&(strcmp(l->sr->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with a " + "upper texture. Remove?",f))) + { + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + + TRACE; + if ((check_2side_lower)&&(l->sl)&&(l->sl->sector!=-1)&& + (l->sr->sector!=-1)) + { + sr=GETSECT(l->sr->sector); + sl=GETSECT(l->sl->sector); + + if ((sr->s.floor<sl->s.floor)&& + (!strcmp(l->sr->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "lower texture. Add?",f))) + { + sprintf(s,"Pick LOWER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->lower,d); + strcpy(l->sl->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.floor>sl->s.floor)&& + (!strcmp(l->sl->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "lower texture. Add?",f))) + { + sprintf(s,"Pick LOWER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sl->lower,d); + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.floor==sl->s.floor)&& + ((strcmp(l->sl->lower,empty_texture))|| + (strcmp(l->sr->lower,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with pointless " + "lower texture. Remove?",f))) + { + strcpy(l->sl->lower,empty_texture); + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_middle)&&(l->sl)&&(l->sl->sector!=-1)) + { + if (((strcmp(l->sr->middle,empty_texture))|| + (strcmp(l->sl->middle,empty_texture)))&& + (l->sl->sector!=l->sr->sector)) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with a " + "middle texture. Remove?",f))) + { + strcpy(l->sr->middle,empty_texture); + strcpy(l->sl->middle,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_upper)&&(l->sl)&&(l->sl->sector!=-1)&& + (l->sr->sector!=-1)) + { + sr=GETSECT(l->sr->sector); + sl=GETSECT(l->sl->sector); + + if ((sr->s.ceiling>sl->s.ceiling)&& + (!strcmp(l->sr->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "upper texture. Add?",f))) + { + sprintf(s,"Pick UPPER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->upper,d); + strcpy(l->sl->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.ceiling<sl->s.ceiling)&& + (!strcmp(l->sl->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "upper texture. Add?",f))) + { + sprintf(s,"Pick UPPER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sl->upper,d); + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.ceiling==sl->s.ceiling)&& + ((strcmp(l->sl->upper,empty_texture))|| + (strcmp(l->sr->upper,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with pointless " + "upper texture. Remove?",f))) + { + strcpy(l->sl->upper,empty_texture); + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_same_sector)&&(l->sl)&&(l->sl->sector!=-1)) + { + if ((l->sl->sector==l->sr->sector)&& + ((strcmp(l->sr->lower,empty_texture))|| + (strcmp(l->sr->middle,empty_texture))|| + (strcmp(l->sr->upper,empty_texture))|| + (strcmp(l->sl->lower,empty_texture))|| + (strcmp(l->sl->middle,empty_texture))|| + (strcmp(l->sl->upper,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided within a " + "sector and is textured. Remove all?",f))) + { + strcpy(l->sr->lower,empty_texture); + strcpy(l->sl->lower,empty_texture); + strcpy(l->sr->middle,empty_texture); + strcpy(l->sl->middle,empty_texture); + strcpy(l->sr->upper,empty_texture); + strcpy(l->sl->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + } + + i=IteratorNext(i); + } + + if (change) + { + if (YesNo("Select altered LINEDEFs?")) + { + ClearSelection(); + i=ListIterator(li); + + while(i) + { + memcpy(&f,IteratorData(i),sizeof(int)); + o=MapElem(linedef,f); + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + i=IteratorNext(i); + } + + FullRedraw(); + } + } + else + { + GuiInfoBox("NOTICE","No problems found"); + FullRedraw(); + } + + ListClear(li); + break; + + default: + + case GFX_ASCII: + switch(toupper(k.ascii)) + { + case 'H': + tag_highlight=!tag_highlight; + FullRedraw(); + break; + + default: + break; + } + break; + } +} + + +int ObjectHasTag_LINEDEF(void *obj, int tag) +{ + EditLine *l; + + return ((l=obj)&&(l->l.tag==tag)); +} + + +ObjDesc *ObjectOverlaid_LINEDEF(int x, int y, int *no) +{ + int n; + EditLine *l; + ObjDesc *od; + int f; + + TRACE; + + od=NULL; + + n=0; + + for(f=0;f<MapSize(linedef);f++) + { + l=GETLINE(f); + + if ((l)&&(PositionOnObject_LINEDEF(x,y,l))) + { + n++; + od=ReGrab(od,sizeof(ObjDesc)*n); + od[n-1].no=f; + + sprintf(od[n-1].detail,"%5d - %s (Tag %d)",f, + TrimStr(LinedefName(l->l.type),60), + l->l.tag); + } + } + + *no=n; + return(od); +} + + +/* END OF FILE */ diff --git a/editmrg.c b/editmrg.c new file mode 100644 index 0000000..7aaa10b --- /dev/null +++ b/editmrg.c @@ -0,0 +1,567 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Merging of WAD maps + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" +#include "gui.h" +#include "wad.h" + + +/* ---------------------------------------- LOCAL DATA +*/ +static WadMap *wad; +static int min_x; +static int min_y; +static int max_x; +static int max_y; +static int cx; +static int cy; +static int ang; + + +/* ---------------------------------------- CO-ORD FUNCS +*/ +static void MergeCoord(int *x, int *y) +{ + if (ang) + { + Rotate(min_x,min_y,x,y,(double)ang); + + *x=cx-min_x+(*x); + *y=cy-min_y+(*y); + } + else + { + *x=cx-min_x+(*x); + *y=cy-min_y+(*y); + } +} + +/* ---------------------------------------- PickPoint() CALLBACKS +*/ +static void PickDraw(int *x,int *y) +{ + Map lm,vm; + Linedef *l; + Vertex *v1,*v2; + int x1,y1,x2,y2; + int f; + + cx=*x=SnapX(*x); + cy=*y=SnapY(*y); + + lm=wad->linedef; + vm=wad->vertex; + + for(f=0;f<MapSize(lm);f++) + { + l=MapElem(lm,f); + + v1=MapElem(vm,l->from); + v2=MapElem(vm,l->to); + + x1=v1->x; + y1=v1->y; + MergeCoord(&x1,&y1); + x1=MapToX(x1); + y1=MapToY(y1); + + x2=v2->x; + y2=v2->y; + MergeCoord(&x2,&y2); + x2=MapToX(x2); + y2=MapToY(y2); + + GFX_line(x1,y1,x2,y2,WHITE); + } +} + + +static void PickKey(GFXKey k) +{ + TRACE; + + if (k.code==GFX_ASCII) + switch(k.ascii) + { + case '.': + if (--ang<0) + ang=359; + break; + + case ',': + ang=(ang+1)%360; + break; + + case '>': + if ((ang-=10)<0) + ang+=360; + break; + + case '<': + ang=(ang+10)%360; + break; + + default: + break; + } +} + + +static void PickInfo(char *p) +{ + TRACE; + + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE,"Angle : %3d|",ang); + + GuiDrawInfoBox(p,GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + ", - rotate left 1 deg |" + ". - rotate right 1 deg |" + "< - rotate left 10 deg |" + "> - rotate right 10 deg|" + " |" + "Press left button to complete. ESC to cancel"); +} + + +/* ---------------------------------------- WAD MERGEING +*/ +void MergeWad(void) +{ + Object o; + Linedef *l; + Sector *s=NULL; + Thing *t; + Vertex *v; + Sidedef *si; + EditVert *ev; + EditLine *el; + EditSect *es; + EditThing *et; + char *name; + int f; + int unbound; + int n_thing; + int n_line; + int n_side; + int n_vert; + int n_sect; + int n_tag; + int tmp_wad; + char *tmp_n; + char *wadf; + int *secmap; + int x,y; + + if (level_style==DOOM_2_LEVELS) + tmp_n="MAP01"; + else + tmp_n="E1M1"; + + if ((tmp_wad=YesNo("Load a new PWAD and read %s from it?",tmp_n))) + { + if (!(wadf=GUI_fsel("Pick PWAD to merge map from",PWAD_dir,".WAD"))) + return; + + if (AddPWAD(wadf)!=WAD_OK) + { + GuiInfoBox("ERROR","AddPWAD(%s): %s",wadf,WadErrorString()); + FullRedraw(); + Release(wadf); + return; + } + + name=tmp_n; + } + else + { + wadf=NULL; + + if (!(name=GuiPickLevel("Pick map to merge"))) + return; + } + + GuiDrawInfoBox("Loading...",GUI_CENTRE,GUI_CENTRE,TRUE, + "Loading level %s",name); + if (!(wad=LoadMap(name))) + { + GuiInfoBox("ERROR","LoadMap(%s): %s",name,WadErrorString()); + FullRedraw(); + + if (tmp_wad) + { + if (CloseWad(wadf)!=WAD_OK) + GuiInfoBox("ERROR","CloseWad(%s)|%s",wadf,WadErrorString()); + + Release(wadf); + } + + return; + } + + if (MapSize(wad->linedef)==0) + { + GuiInfoBox("ERROR","No LINEDEFS in %s",name); + ClearMap(wad); + FullRedraw(); + + if (tmp_wad) + { + if (CloseWad(wadf)!=WAD_OK) + GuiInfoBox("ERROR","CloseWad(%s)|%s",wadf,WadErrorString()); + + Release(wadf); + } + + return; + } + + FullRedraw(); + + /* Get top left hand corner of map and see if there are unbound left + sidedefs + */ + ang=0; + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + for(f=0;f<MapSize(wad->vertex);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;(f<MapSize(wad->linedef))&&(!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;f<MapSize(wad->vertex);f++) + { + v=MapElem(wad->vertex,f); + x=v->x; + y=v->y; + MergeCoord(&x,&y); + v->x=x; + v->y=y; + } + + for(f=0;f<MapSize(wad->thing);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;f<MapSize(wad->linedef);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;f<MapSize(wad->sector);f++) + { + s=MapElem(wad->sector,f); + + if (min>s->floor) + min=s->floor; + } + + diff=min-es->s.floor; + + for(f=0;f<MapSize(wad->sector);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;f<MapSize(wad->sector);f++) + { + s=MapElem(wad->sector,f); + + if ((s->ceiling!=es->s.ceiling)&&(s->floor<es->s.ceiling)) + s->ceiling=es->s.ceiling; + } + } + } + else + secmap=NULL; + + /* Renumber tags? + */ + n_tag=0; + + if (YesNo("Renumber tags?")) + { + for(f=0;f<MapSize(linedef);f++) + if ((el=GETLINE(f))) + n_tag=MAX(n_tag,el->l.tag); + + for(f=0;f<MapSize(sector);f++) + if ((es=GETSECT(f))) + n_tag=MAX(n_tag,es->s.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;f<MapSize(wad->vertex);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;f<MapSize(wad->sidedef);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;f<MapSize(wad->linedef);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;f<MapSize(wad->sector);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;f<MapSize(wad->thing);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..180b894 --- /dev/null +++ b/editmult.c @@ -0,0 +1,680 @@ +/* + + 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; + + TRACE; + + f=IteratorData(*i); + m=GETMULTI(*f); + + switch(m->type) + { + case VERTEX: + *v=GETVERT(m->i); + break; + case THING: + *t=GETTHING(m->i); + break; + } + + *i=IteratorNext(*i); + + if (mr) + *mr=m; + + return(m->type); +} + + +static int GetType(MultiObj *m,EditVert **v,EditThing **t) +{ + TRACE; + + switch(m->type) + { + case VERTEX: + *v=GETVERT(m->i); + break; + case THING: + *t=GETTHING(m->i); + break; + } + + return(m->type); +} + + +static void SelectionCentre(int *x,int *y) +{ + int *f; + MultiObj *m; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + m=GETMULTI(*f); + + min_x=MIN(m->x,min_x); + min_y=MIN(m->y,min_y); + max_x=MAX(m->x,max_x); + max_y=MAX(m->y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +static void ApplySelectionCoords(void) +{ + MultiObj *m; + Iterator i; + EditVert *v; + EditThing *t; + + TRACE; + + i=ListIterator(selected); + + while(i) + switch(GetIterType(&i,&m,&v,&t)) + { + case THING: + t->t.x=m->x; + t->t.y=m->y; + break; + + case VERTEX: + v->v.x=m->x; + v->v.y=m->y; + break; + } +} + + +/* ---------------------------------------- EXPORTED UTILS +*/ +void GenerateMultiMap(void) +{ + MultiObj *m; + EditVert *v; + EditThing *t; + Object o; + int f; + + TRACE; + + if (!multimap) + multimap=MapNew(sizeof(MultiObj)); + else + { + for(f=0;f<MapSize(multimap);f++) + { + memcpy(&o,MapElem(multimap,f),sizeof(Object)); + + if (o.data) + Release(o.data); + } + + multimap=MapEmpty(multimap); + } + + for(f=0;f<MapSize(vertex);f++) + if ((v=GETVERT(f))) + { + m=Grab(sizeof(MultiObj)); + m->type=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;f<MapSize(thing);f++) + if ((t=GETTHING(f))) + { + m=Grab(sizeof(MultiObj)); + m->type=THING; + m->i=f; + m->x=t->t.x; + m->y=t->t.y; + o.data=m; + o.select=SELECT_NONE; + MapAdd(multimap,-1,&o); + } +} + +/* ---------------------------------------- GENERIC THING FUNCS +*/ +int PositionOnObject_MULTI(int x,int y,void *data) +{ + EditVert *v; + EditThing *t; + + TRACE; + + switch(GetType(data,&v,&t)) + { + case VERTEX: + return (PositionOnObject_VERTEX(x,y,v)); + break; + case THING: + return (PositionOnObject_THING(x,y,t)); + break; + } + + return (FALSE); +} + + +void SelectBox_MULTI(int x1,int y1,int x2,int y2) +{ + Object *o; + MultiObj *m; + int f; + + TRACE; + + for(f=0;f<MapSize(multimap);f++) + { + o=MapElem(multimap,f); + + if ((m=o->data)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(m->x,m->y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_MULTI(void) +{ + TRACE; + return; +} + + +void DrawObject_MULTI(void *data, int selmode) +{ + MultiObj *m; + + TRACE; + m=data; + + switch(m->type) + { + case VERTEX: + DrawObject_VERTEX(GETVERT(m->i),selmode); + break; + case THING: + DrawObject_THING(GETTHING(m->i),selmode); + break; + default: + break; + } +} + + +void DrawObjectInfo_MULTI(void) +{ + MultiObj *m; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((m=GETMULTI(current)))) + GuiDrawInfoBox("MULTI MODE",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Object type : %s|" + "Number : %d", + (m->type == VERTEX ? "VERTEX" : "THING "), + m->i); + else + GuiDrawInfoBox("MULTI MODE",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Object type : |" + "Number : -"); +} + + +void DrawObjectHeader_MULTI(void) +{ + TRACE; +} + + +void MoveObject_MULTI(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + MultiObj *m; + List orig; + int *f; + Point p; + int cancel=FALSE; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + m=GETMULTI(*f); + p.x=m->x; + p.y=m->y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move Multiple Objects", + GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + memcpy(&p,IteratorData(i2),sizeof(Point)); + m=GETMULTI(*f); + m->x=p.x; + m->y=p.y; + + i=IteratorNext(i); + i2=IteratorNext(i2); + } + + ApplySelectionCoords(); + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + i=ListIterator(selected); + while(i) + { + f=IteratorData(i); + + m=GETMULTI(*f); + + m->x+=dmx; + m->y+=dmy; + + i=IteratorNext(i); + } + + ApplySelectionCoords(); + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_MULTI(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + MultiObj *m; + + TRACE; + + SelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + m=GETMULTI(*f); + + x=m->x; + y=m->y; + + Rotate(cx,cy,&x,&y,angle); + + m->x=x; + m->y=y; + + i=IteratorNext(i); + } + + ApplySelectionCoords(); +} + + +void ScaleObject_MULTI(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + MultiObj *m; + + TRACE; + + SelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + m=GETMULTI(*f); + + x=m->x; + y=m->y; + + Scale(cx,cy,&x,&y,scale); + + m->x=x; + m->y=y; + + i=IteratorNext(i); + } + + ApplySelectionCoords(); +} + + +void SetTagObject_MULTI(int tag) +{ + TRACE; +} + + +void LocateObject_MULTI(void *obj) +{ + MultiObj *m; + + TRACE; + + m=obj; + + ox=m->x-scale*SCRW/2; + oy=m->y+scale*SCRH/2; + +} + + +void ObjectInsert_MULTI(void) +{ + TRACE; +} + + +void ObjectDelete_MULTI(void) +{ + TRACE; +} + + +void ObjectMenu_MULTI(void) +{ + static double last_rot=0.0; + static double last_scale=0.0; + int cancel; + + TRACE; + + cancel=FALSE; + + switch(GUI_menu("Mutlimode",ms.x,ms.y,multi_popup,GUI_CANCEL)) + { + 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) +{ + TRACE; +} + + +int ObjectHasTag_MULTI(void *obj, int tag) +{ + TRACE; + return(FALSE); +} + + +void SetSelect_MULTI(int i, int mode) +{ + Object *o; + MultiObj *m; + Map om; + + TRACE; + o=MapElem(multimap,i); + + if ((m=o->data)) + { + o->select=mode; + + if (m->type==VERTEX) + om=vertex; + else + om=thing; + + o=MapElem(om,m->i); + o->select=mode; + } +} + + + +ObjDesc *ObjectOverlaid_MULTI(int x, int y, int *no) +{ + int n; + MultiObj *m; + EditThing *t; + EditVert *v; + ObjDesc *od; + int f; + + TRACE; + + od=NULL; + + n=0; + + for(f=0;f<MapSize(multimap);f++) + { + m=GETMULTI(f); + + if ((m)&&(PositionOnObject_MULTI(x,y,m))) + { + n++; + od=ReGrab(od,sizeof(ObjDesc)*n); + od[n-1].no=f; + + switch(GetType(m,&v,&t)) + { + case VERTEX: + sprintf(od[n-1].detail,"Vertex %-5d - %d,%d", + f,v->v.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..d9085c5 --- /dev/null +++ b/editsect.c @@ -0,0 +1,1612 @@ +/* + + 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 "util.h" + +#include <ctype.h> +#include <math.h> + + +/* This is the data shared between the PickPoint() callback functions and the + Create function +*/ +typedef struct + { + int cx; + int cy; + Point p[64]; + int dx; + int dy; + int r; + double ai; + int sides; + } PickData; + +static PickData pick; + +/* This shows which LINEDEFs are drawn tagged +*/ +static List hilite=NULL; + + +/* ---------------------------------------- PickPoint() CALLBACKS +*/ +static void DrawVertSet(int *x, int *y) +{ + double ang; + int dx,dy; + int f; + + TRACE; + + pick.dx=*x; + pick.dy=*y; + + dx=pick.cx-pick.dx; + dy=pick.cy-pick.dy; + + /* Calc angle that the line is at + */ + if (dx==0) + if (dy<0) + ang=RAD(0); + else + ang=RAD(180); + else if (dy==0) + if (dx<0) + ang=RAD(90); + else + ang=RAD(270); + else + { + ang=atan((double)dx/(double)dy); + + if (dy>0) + ang-=RAD(180); + } + + /* Calc line len + */ + pick.r=Len(pick.cx,pick.cy,pick.dx,pick.dy); + + for(f=0;f<pick.sides;f++) + { + pick.p[f].x=(int)(pick.cx+(pick.r*sin(ang))); + pick.p[f].y=(int)(pick.cy+(pick.r*cos(ang))); + pick.p[f].x=SnapX(pick.p[f].x); + pick.p[f].y=SnapY(pick.p[f].y); + ang+=pick.ai; + } + + for(f=0;f<pick.sides;f++) + GFX_line(MapToX(pick.p[f].x),MapToY(pick.p[f].y), + MapToX(pick.p[(f+1)%pick.sides].x), + MapToY(pick.p[(f+1)%pick.sides].y),WHITE); +} + + +/* ---------------------------------------- GENERATE VERTEX LIST FROM PICKDATA +*/ +static List GenVertList(void) +{ + Object o; + EditVert *v; + List l; + int f,r,n; + int match; + + for(f=0;f<pick.sides;f++) + { + match=TRUE; + + while(match) + for(match=FALSE,r=0;(r<pick.sides)&&(!match);r++) + if (r!=f) + if ((pick.p[r].x==pick.p[f].x)&& + (pick.p[r].y==pick.p[f].y)) + { + for(n=r;n<(pick.sides-1);n++) + { + pick.p[n].x=pick.p[n+1].x; + pick.p[n].y=pick.p[n+1].y; + } + + pick.sides=MAX(pick.sides-1,0); + + match=TRUE; + } + } + + if (pick.sides<3) + return(NULL); + + l=ListNew(sizeof(int)); + + for(f=0;f<pick.sides;f++) + { + v=Grab(sizeof(EditVert)); + v->v.x=pick.p[f].x; + v->v.y=pick.p[f].y; + v->l=ListNew(sizeof(int)); + + n=MapSize(vertex); + + o.select=SELECT_NONE; + o.data=v; + + MapAdd(vertex,n,&o); + ListAppend(l,&n); + } + + return(l); +} + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static int SelectColour(int selmode) +{ + TRACE; + + switch(selmode) + { + case SELECT_OVER: + return(OVERCOL); + break; + case SELECT_SELECTED: + return(SELCOL); + break; + default: + return(SECTCOL); + break; + } +} + + +void DrawSector(EditSect *s, int col, int check_tag) +{ + Iterator i; + EditLine *l; + + TRACE; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if (!(check_tag)||(!tag_highlight)||(!InIntList(hilite,l->no))) + MapLineD(l,col); + + i=IteratorNext(i); + } +} + + +static void RemoveHighlights(void) +{ + Iterator i; + Object *o; + EditLine *l; + int *n; + + i=ListIterator(hilite); + + while(i) + { + n=IteratorData(i); + + if ((l=GETLINE(*n))) + { + if (l->sr->sector>=0) + if ((o=MapElem(sector,l->sr->sector))) + DrawSector(o->data,SelectColour(o->select),FALSE); + + if ((l->sl)&&(l->sl->sector>=0)) + if ((o=MapElem(sector,l->sl->sector))) + DrawSector(o->data,SelectColour(o->select),FALSE); + } + + i=IteratorNext(i); + } +} + + +static void SectorSelectionCentre(int *x,int *y) +{ + int *f; + EditSect *s; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + min_x=MIN(s->min_x,min_x); + min_y=MIN(s->min_y,min_y); + max_x=MAX(s->max_x,max_x); + max_y=MAX(s->max_y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +/* ---------------------------------------- SECTOR VECTOR MAP UTILS +*/ +static int vno=0; +static char *vmap=NULL; + +static void InitVMAP(void) +{ + if (vno<MapSize(vertex)) + vmap=ReGrab(vmap,MapSize(vertex)); + + memset(vmap,FALSE,MapSize(vertex)); +} + + +/* ---------------------------------------- SECTOR LINEDEF MAP UTILS +*/ +static int lno=0; +static char *lmap=NULL; + +static void InitLMAP(void) +{ + if (lno<MapSize(linedef)) + lmap=ReGrab(lmap,MapSize(linedef)); + + memset(lmap,FALSE,MapSize(linedef)); +} + + +/* ---------------------------------------- SECTOR CONTAINER ROUTINES +*/ + +/* Returns -1 for no sector +*/ +int SectorHoldingPoint(int x,int y) +{ + Object *o; + int f; + + TRACE; + + for(f=0;f<MapSize(sector);f++) + { + o=MapElem(sector,f); + + if ((o->data)&&(PositionOnObject_SECTOR(x,y,o->data))) + return(f); + } + + return(-1); +} + + +void SectorCalcContaining(int no,EditSect *s) +{ + int f; + EditLine *l; + int match; + + TRACE; + + ListEmpty(s->v); + ListEmpty(s->sr); + ListEmpty(s->sl); + ListEmpty(s->all); + InitVMAP(); + + for(f=0;f<MapSize(linedef);f++) + { + match=FALSE; + l=GETLINE(f); + + if (l) + { + if ((l->sr)&&(l->sr->sector==no)) + { + ListAppend(s->sr,&l); + ListAppend(s->all,&l); + match=TRUE; + } + + if ((l->sl)&&(l->sl->sector==no)) + { + if (!match) + ListAppend(s->all,&l); + + ListAppend(s->sl,&l); + match=TRUE; + } + + if (match) + { + if (!vmap[l->l.from]) + { + ListAppend(s->v,&(l->l.from)); + vmap[l->l.from]=TRUE; + } + + if (!vmap[l->l.to]) + { + ListAppend(s->v,&(l->l.to)); + vmap[l->l.to]=TRUE; + } + } + } + } +} + + +void SectorCalcContainingAll(void) +{ + int f; + EditSect *s; + + TRACE; + + for(f=0;f<MapSize(sector);f++) + { + s=GETSECT(f); + SectorCalcContaining(f,s); + } +} + + +/* ---------------------------------------- SECTOR STYLING FUNCS +*/ +static void ApplySectorStyle(EditSect *s, int flag, + DirName upper, DirName middle, DirName lower, + DirName floor, DirName ceiling) +{ + EditLine *l; + List track; + Iterator i,ti; + int ox,tw; + int *n; + + TRACE; + + tw=CalcTextureWidth(upper,middle,lower); + + InitLMAP(); + + /* Dispose of two-sided linedefs wholly within the sector + */ + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if ((l->sl)&&(l->sl->sector==s->no)&&(l->sr->sector==s->no)) + lmap[l->no]=TRUE; + + i=IteratorNext(i); + } + + /* Set the floor and ceiling + */ + strcpy(s->s.floor_t,floor); + strcpy(s->s.ceiling_t,ceiling); + + /* Now draw a trail through the linedefs, aligning textures as we go along + */ + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if (!lmap[l->no]) + { + track=TrackLinedef(l->no); + ox=0; + ti=ListIterator(track); + + while(ti) + { + n=IteratorData(ti); + + l=GETLINE(*n); + + if (((l->sr->sector==s->no)&&(flag&SSTYLE_FACING_IN))|| + ((l->sr->sector!=s->no)&&(flag&SSTYLE_FACING_OUT))) + { + if (strcmp(l->sr->upper,empty_texture)) + { + strcpy(l->sr->upper,upper); + + if (flag&SSTYLE_UPPER_PEG) + l->l.flags|=upper_peg_mask; + else if (!(flag&SSTYLE_LEAVE_PEG)) + l->l.flags&=~upper_peg_mask; + } + + if (strcmp(l->sr->middle,empty_texture)) + strcpy(l->sr->middle,middle); + + if (strcmp(l->sr->lower,empty_texture)) + { + strcpy(l->sr->lower,lower); + + if (flag&SSTYLE_LOWER_PEG) + l->l.flags|=lower_peg_mask; + else if (!(flag&SSTYLE_LEAVE_PEG)) + l->l.flags&=~lower_peg_mask; + } + + l->sr->x=ox; + lmap[l->no]=TRUE; + } + + if ((l->sl)&& + (((l->sl->sector==s->no)&&(flag&SSTYLE_FACING_IN))|| + ((l->sl->sector!=s->no)&&(flag&SSTYLE_FACING_OUT)))) + { + if (strcmp(l->sl->upper,empty_texture)) + { + strcpy(l->sl->upper,upper); + + if (flag&SSTYLE_UPPER_PEG) + l->l.flags|=upper_peg_mask; + else if (!(flag&SSTYLE_LEAVE_PEG)) + l->l.flags&=~upper_peg_mask; + } + + if (strcmp(l->sl->middle,empty_texture)) + strcpy(l->sl->middle,middle); + + if (strcmp(l->sl->lower,empty_texture)) + { + strcpy(l->sl->lower,lower); + + if (flag&SSTYLE_LOWER_PEG) + l->l.flags|=lower_peg_mask; + else if (!(flag&SSTYLE_LEAVE_PEG)) + l->l.flags&=~lower_peg_mask; + } + + l->sl->x=ox; + lmap[l->no]=TRUE; + } + + ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + + ti=IteratorNext(ti); + } + + ListClear(track); + } + + i=IteratorNext(i); + } +} + + +/* ---------------------------------------- GENERIC SECTOR FUNCS +*/ +int PositionOnObject_SECTOR(int x,int y,void *data) +{ + int cross; + EditSect *s; + EditLine *l; + Vertex *vi,*vj; + Iterator i; + + TRACE; + + s=data; + + if (BOXBOUND(x,y,s->min_x,s->min_y,s->max_x,s->max_y)) + { + cross=FALSE; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + /* Linedefs that have a right and left sidedef pointing at the + same sector are not counted + */ + if (!((l->sr)&&(l->sl)&&(l->sl->sector==l->sr->sector))) + { + vi=&(l->v[0]->v); + vj=&(l->v[1]->v); + + /* This code is taken from comp.graphics.algorithms FAQ 2.03 + */ + if ((((vi->y<=y) && (y<vj->y)) || + ((vj->y<=y) && (y<vi->y))) && + (x < (vj->x - vi->x) * (y - vi->y) / + (vj->y - vi->y) + vi->x)) + cross=!cross; + } + + i=IteratorNext(i); + } + + return(cross); + } + else + return(FALSE); +} + + +/* This code is kept as a semi-working base if the routine based on the + comp.graphics.algorithm FAQ fails (this could be as I don't do it on a list + of ordered vertexes as the original does - doing on a line basis should be + the same though). +*/ +int OLD_PositionOnObject_SECTOR(int x,int y,void *data) +{ + int x_no; + int y_no; + EditSect *s; + EditLine *l; + Iterator i; + + TRACE; + + s=data; + + if (BOXBOUND(x,y,s->min_x,s->min_y,s->max_x,s->max_y)) + { + x_no=0; + y_no=0; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + /* Linedefs that have a right and left sidedef pointing at the + same sector are not counted + */ + if (!((l->sr)&&(l->sl)&&(l->sl->sector==l->sr->sector))) + { + /* This is a bit (understatement) kludgy, but we do 2 line + crossing checks, one in X and one in the Y direction. This + way we can omit a lot of extra checking for lines bisecting + shared vertexes and the like. + */ + if (LinesCross(s->min_x,y,x,y, + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)) + x_no++; + + if (LinesCross(x,s->min_y,x,y, + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)) + y_no++; + } + + i=IteratorNext(i); + } + + /* Odd number of crossed lines means we're in the sector + */ + return((x_no%2)||(y_no%2)); + } + else + return(FALSE); +} + + +void SelectBox_SECTOR(int x1,int y1,int x2,int y2) +{ + Object *o; + EditSect *s; + int f; + + TRACE; + + for(f=0;f<MapSize(sector);f++) + { + o=MapElem(sector,f); + + if ((s=o->data)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(s->min_x,s->min_y,x1,y1,x2,y2))&& + (BOXBOUND(s->max_x,s->max_y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_SECTOR(void) +{ + Object *o; + EditSect *s; + int id; + int f; + + if ((id=SelectSector())!=SECTOR_NULLID) + { + ClearSelection(); + + for(f=0;f<MapSize(sector);f++) + if ((o=MapElem(sector,f))) + if ((s=o->data)&&(s->s.special==id)) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } +} + + +void DrawObject_SECTOR(void *data, int selmode) +{ + static int drawn=FALSE; + Object *o; + EditSect *s; + EditLine *l; + int sel; + int f; + + TRACE; + + if (!hilite) + hilite=ListNew(sizeof(int)); + + s=data; + + /* If the current object has changed, remove the highlighted tag objects + */ + if ((current==-1)&&(drawn)) + { + drawn=FALSE; + RemoveHighlights(); + ListEmpty(hilite); + } + + /* Draw tagged linedefs + */ + if ((tag_highlight)&&(current==s->no)) + { + RemoveHighlights(); + ListEmpty(hilite); + + if (s->s.tag) + { + drawn=TRUE; + + for(f=0;f<MapSize(linedef);f++) + if ((l=GETLINE(f))) + if ((l->l.tag==s->s.tag)&&(LineOnDisplay(l))) + { + sel=FALSE; + + if (l->sr->sector>=0) + if ((o=MapElem(sector,l->sr->sector))) + sel=(o->select!=SELECT_NONE); + + if ((l->sl)&&(l->sl->sector>=0)) + if ((o=MapElem(sector,l->sl->sector))) + sel|=(o->select!=SELECT_NONE); + + if (!sel) + { + IntListUniqAdd(hilite,f); + MapLineD(l,TAGCOL); + } + } + } + + } + + DrawSector(s,SelectColour(selmode),TRUE); +} + + +void DrawObjectInfo_SECTOR(void) +{ + EditSect *s; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((s=GETSECT(current)))) + GuiDrawInfoBox("SECTOR",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Sector Number : %-5d|" + "Floor : %-5d|" + "Ceiling : %-5d|" + "Height : %-5d|" + "Light : %-5d|" + "Floor texture : %-10s|" + "Ceiling texture : %-10s|" + "Sector Type : %-30s|" + "Tag : %-5d", + current, + s->s.floor, + s->s.ceiling, + s->s.ceiling-s->s.floor, + s->s.light, + s->s.floor_t, + s->s.ceiling_t, + SectorName(s->s.special), + s->s.tag); + else + GuiDrawInfoBox("SECTOR",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Sector Number : -|" + "Floor : -|" + "Ceiling : -|" + "Height : -|" + "Light : -|" + "Floor texture : -|" + "Ceiling texture : -|" + "Sector Type : %-30s|" + "Tag : -","-"); +} + + +void DrawObjectHeader_SECTOR(void) +{ + if (tag_highlight) + GFX_print(0,FH,WHITE,"Tag highlight: ON"); + else + GFX_print(0,FH,WHITE,"Tag highlight: OFF"); + + switch(sector_move) + { + case MOVE_ALL: + GFX_print(SCRW/2,FH,WHITE,"Move mode: ALL"); + break; + case MOVE_LEFT: + GFX_print(SCRW/2,FH,WHITE,"Move mode: LEFT"); + break; + case MOVE_RIGHT: + GFX_print(SCRW/2,FH,WHITE,"Move mode: RIGHT"); + break; + } +} + + +void MoveObject_SECTOR(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditSect *s; + EditLine *l; + EditVert *v; + List orig; + int *f; + Point p; + List vert; + int cancel; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + vert=ListNew(sizeof(EditVert *)); + + InitVMAP(); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + switch(sector_move) + { + case MOVE_ALL: + i2=ListIterator(s->all); + break; + + case MOVE_LEFT: + i2=ListIterator(s->sl); + break; + + case MOVE_RIGHT: + default: + i2=ListIterator(s->sr); + break; + } + + while(i2) + { + memcpy(&l,IteratorData(i2),sizeof(l)); + + if (!vmap[l->l.from]) + { + v=GETVERT(l->l.from); + ListAppend(vert,&v); + p.x=l->v[0]->v.x; + p.y=l->v[0]->v.y; + ListAppend(orig,&p); + vmap[l->l.from]=TRUE; + } + + if (!vmap[l->l.to]) + { + v=GETVERT(l->l.to); + ListAppend(vert,&v); + p.x=l->v[1]->v.x; + p.y=l->v[1]->v.y; + ListAppend(orig,&p); + vmap[l->l.to]=TRUE; + } + + i2=IteratorNext(i2); + } + + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move SECTOR",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(vert); + i2=ListIterator(orig); + + while(i2) + { + memcpy(&v,IteratorData(i),sizeof(v)); + + memcpy(&p,IteratorData(i2),sizeof(Point)); + v->v.x=p.x; + v->v.y=p.y; + + i2=IteratorNext(i2); + i=IteratorNext(i); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + i=ListIterator(vert); + while(i) + { + memcpy(&v,IteratorData(i),sizeof(v)); + + v->v.x+=dmx; + v->v.y+=dmy; + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + ListClear(vert); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_SECTOR(double angle) +{ + int cx,cy; + int x,y; + int *f; + Short *r; + Iterator i,i2; + EditSect *s; + EditVert *v; + + TRACE; + + InitVMAP(); + + SectorSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + i2=ListIterator(s->v); + + while(i2) + { + r=IteratorData(i2); + v=GETVERT(*r); + + if (!vmap[*r]) + { + vmap[*r]=TRUE; + + x=v->v.x; + y=v->v.y; + + Rotate(cx,cy,&x,&y,angle); + + v->v.x=x; + v->v.y=y; + } + + i2=IteratorNext(i2); + } + + i=IteratorNext(i); + } +} + + +void ScaleObject_SECTOR(double scale) +{ + int cx,cy; + int x,y; + int *f; + Short *r; + Iterator i,i2; + EditSect *s; + EditVert *v; + + TRACE; + + InitVMAP(); + + SectorSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + i2=ListIterator(s->v); + + while(i2) + { + r=IteratorData(i2); + v=GETVERT(*r); + + if (!vmap[*r]) + { + vmap[*r]=TRUE; + + x=v->v.x; + y=v->v.y; + + Scale(cx,cy,&x,&y,scale); + + v->v.x=x; + v->v.y=y; + } + + i2=IteratorNext(i2); + } + + i=IteratorNext(i); + } +} + + +void SetTagObject_SECTOR(int tag) +{ + int *f; + Iterator i; + EditSect *s; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.tag=tag; + i=IteratorNext(i); + } +} + + +void LocateObject_SECTOR(void *obj) +{ + int cx,cy; + EditSect *s; + + TRACE; + + s=obj; + cx=s->min_x+(s->max_x-s->min_x)/2; + cy=s->min_y+(s->max_y-s->min_y)/2; + ox=cx-scale*SCRW/2; + oy=cy+scale*SCRH/2; +} + + +void ObjectInsert_SECTOR(void) +{ +# define SM_UNBOUND 1 +# define SM_POLY 2 + + static PLAT_MENU sector_insert_menu[]= + { + {"Create unbound sector",SM_UNBOUND}, + {"Create polygon",SM_POLY}, + {NULL,GUI_CANCEL} + }; + + TRACE; + + switch(GUI_menu("Sector",ms.x,ms.y,sector_insert_menu,GUI_CANCEL)) + { + case SM_UNBOUND: + { + int sec; + + sec=CreateUnboundSector(normal_sector,default_floor_height, + default_ceiling_height,default_light_level, + 0,empty_texture,empty_texture); + + GuiInfoBox("NOTICE","A sector number %d has been created.|" + "SIDEDEFS will have to bound to the sector " + "before it|becomes visible and edittable.",sec); + + FullRedraw(); + break; + } + + case SM_POLY: + { + static int last_sides=4; + List sel; + + nosides_dialog[D_NOSIDES].data.i=last_sides; + + if (GUI_dialog("Create sector",D_NOSIDES_NO,nosides_dialog)) + { + pick.sides=nosides_dialog[D_NOSIDES].data.i; + + if ((pick.sides<3)||(pick.sides>64)) + { + GuiInfoBox("ERROR","Only enter a value between 3 and 64"); + FullRedraw(); + break; + } + else + if (PickPoint("Select centre of new sector", + &pick.cx,&pick.cy,NULL,NULL,NULL)) + { + pick.ai=RAD(360.0/pick.sides); + + if (PickPoint("Select the width and rotation " + "of the sector",&pick.dx,&pick.dy, + DrawVertSet,NULL,NULL)) + { + /* Merge identical vertices from the list and + check that the vertices will not be dubious + */ + if ((sel=GenVertList())) + { + if (!CreateSector(sel)) + { + Iterator i; + Object *o; + EditVert *v; + int *n; + + i=ListIterator(sel); + + while(i) + { + n=IteratorData(i); + o=MapElem(vertex,*n); + v=o->data; + + ListClear(v->l); + Release(v); + o->data=NULL; + + i=IteratorNext(i); + } + } + else + { + FullRedraw(); + last_sides=pick.sides; + } + + ListClear(sel); + } + else + { + GuiInfoBox("ERROR","Shape makes no sense"); + FullRedraw(); + break; + } + } + } + } + + break; + } + + default: + break; + } +} + + +void ObjectDelete_SECTOR(void) +{ + TRACE; + + GuiInfoBox("NOTICE","Sector not deleted| |" + "Sectors are automatically deleted|" + "when saving the map if no LINEDEFs|" + "are bound to it."); + FullRedraw(); +} + + +void ObjectMenu_SECTOR(void) +{ + Iterator i; + EditSect *s; + int *f; + int cancel; + + TRACE; + + cancel=FALSE; + + switch(GUI_menu("Sector",ms.x,ms.y,sector_popup,GUI_CANCEL)) + { + case TM_FLOOR: + s=SelHead(); + sector_fl_dialog[D_SECTOR_FLOOR].data.i=s->s.floor; + + if (GUI_dialog("Floor height",D_SECTOR_FL_NO,sector_fl_dialog)) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.floor=sector_fl_dialog[D_SECTOR_FLOOR].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + break; + + case TM_CEILING: + s=SelHead(); + sector_ce_dialog[D_SECTOR_CEILING].data.i=s->s.ceiling; + + if (GUI_dialog("Ceiling height",D_SECTOR_CE_NO,sector_ce_dialog)) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.ceiling=sector_ce_dialog[D_SECTOR_CEILING].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + break; + + case TM_LIGHT: + s=SelHead(); + sector_li_dialog[D_SECTOR_LIGHT].data.i=s->s.light; + + if (GUI_dialog("Light level",D_SECTOR_LI_NO,sector_li_dialog)) + { + i=ListIterator(selected); + + sector_li_dialog[D_SECTOR_LIGHT].data.i= + MIN(255,MAX(sector_li_dialog[D_SECTOR_LIGHT].data.i,0)); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.light=sector_li_dialog[D_SECTOR_LIGHT].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + break; + + case TM_TAG: + s=SelHead(); + tag_dialog[D_TAG].data.i=s->s.tag; + + if (GUI_dialog("Tag",D_TAG_NO,tag_dialog)) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.tag=tag_dialog[D_TAG].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + break; + + case TM_FLOOR_T: + { + DirName d; + + if ((GetFlat("Floor texture",d))) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + strcpy(s->s.floor_t,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_CEILING_T: + { + DirName d; + + if ((GetFlat("Ceiling texture",d))) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + strcpy(s->s.ceiling_t,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_TYPE: + { + int id; + + id=SelectSector(); + + if (id!=SECTOR_NULLID) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + s->s.special=id; + i=IteratorNext(i); + } + + FullRedraw(); + } + break; + } + + case TM_STYLE: + { + int flag; + DirName upper,middle,lower,floor,ceiling; + + if (ChooseSectorStyle(&flag,upper,middle,lower,floor,ceiling)) + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + ApplySectorStyle(s,flag,upper,middle,lower,floor,ceiling); + i=IteratorNext(i); + } + } + + break; + } + + case TM_MOVE: + MoveObject_SECTOR(); + break; + + case TM_DELETE: + ObjectDelete_SECTOR(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } +} + + +void ObjectKey_SECTOR(GFXKey k) +{ + Iterator i; + EditSect *s; + int tmpsel; + int *f; + + /* Check keys that need no objects + */ + if (k.code==GFX_ASCII) + switch(toupper(k.ascii)) + { + case 'H': + tag_highlight=!tag_highlight; + FullRedraw(); + break; + + case 'M': + if (sector_move==MOVE_ALL) + sector_move=MOVE_RIGHT; + else if (sector_move==MOVE_RIGHT) + sector_move=MOVE_LEFT; + else if (sector_move==MOVE_LEFT) + sector_move=MOVE_ALL; + + DrawHeader(); + GFX_redraw(); + break; + + default: + break; + } + + tmpsel=TmpAddCurrent(); + + if (ListSize(selected)==0) + return; + + if (k.code!=GFX_ASCII) + switch(k.code) + { + default: + break; + } + else + { + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + s=GETSECT(*f); + + switch(toupper(k.ascii)) + { + case ',': + s->s.floor-=8; + if (s->s.floor>s->s.ceiling) + s->s.floor+=8; + break; + + case '.': + s->s.floor+=8; + if (s->s.floor>s->s.ceiling) + s->s.floor-=8; + break; + + case '<': + s->s.ceiling-=8; + if (s->s.ceiling<s->s.floor) + s->s.ceiling+=8; + break; + + case '>': + s->s.ceiling+=8; + if (s->s.ceiling<s->s.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; + + TRACE; + + od=NULL; + + n=0; + + for(f=0;f<MapSize(sector);f++) + { + s=GETSECT(f); + + if ((s)&&(PositionOnObject_SECTOR(x,y,s))) + { + n++; + od=ReGrab(od,sizeof(ObjDesc)*n); + od[n-1].no=f; + + sprintf(od[n-1].detail,"%5d - %s (Tag %d)",f, + TrimStr(SectorName(s->s.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..7c64ece --- /dev/null +++ b/editsel.c @@ -0,0 +1,133 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor selection definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" + + + +/* After all that hard work of making the Object type the only thing that + the top level selection code needs to worry about, the Multi edit mode + goes and throws a spanner in the works.... +*/ +void SetSelect_GENERIC(int i, int mode) +{ + Object *o; + + o=MapElem(map,i); + o->select=mode; +} + + +int TmpAddCurrent(void) +{ + if ((ListSize(selected)==0)&&(current!=-1)) + { + ListAppend(selected,¤t); + return(TRUE); + } + else + return(FALSE); +} + + +void ClearSelection(void) +{ + int *n; + Iterator i; + + TRACE; + + if (map) + { + if (current!=-1) + SetSelect(current,SELECT_NONE); + + i=ListIterator(selected); + + while(i) + { + n=IteratorData(i); + SetSelect(*n,SELECT_NONE); + i=IteratorNext(i); + } + } + + selected=ListEmpty(selected); + current=-1; +} + + +void ClearSelectionLeaveCurrent(void) +{ + int *n; + Iterator i; + + TRACE; + + if (map) + { + i=ListIterator(selected); + + while(i) + { + n=IteratorData(i); + SetSelect(*n,SELECT_NONE); + i=IteratorNext(i); + } + } + + selected=ListEmpty(selected); +} + + +void *SelHead(void) +{ + Iterator i; + int *f; + Object *o; + void *p; + + TRACE; + + i=ListIterator(selected); + p=NULL; + + if ((f=IteratorData(i))) + { + o=MapElem(map,*f); + p=o->data; + } + + IteratorClear(i); + + return(p); +} + + +/* END OF FILE */ diff --git a/editsrot.c b/editsrot.c new file mode 100644 index 0000000..b6764d1 --- /dev/null +++ b/editsrot.c @@ -0,0 +1,76 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor scale and rotation routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" +#include "editvar.h" + +#include <math.h> + + +/* ---------------------------------------- ROTATION ROUTINES +*/ +void Rotate(int cx,int cy,int *x,int *y, double ang) +{ + double r,t; + + TRACE; + + ang=RAD(ang); + + *x-=cx; + *y-=cy; + + r=hypot((double)*x,(double)*y); + t=atan2((double)*y,(double)*x); + + *x=(int)(r*cos(t+ang)+0.5); + *y=(int)(r*sin(t+ang)+0.5); + + *x+=cx; + *y+=cy; +} + + +/* ---------------------------------------- SCALE ROUTINES +*/ +void Scale(int cx,int cy,int *x,int *y, double sc) +{ + TRACE; + + *x-=cx; + *y-=cy; + + *x=(int)((*x)*sc); + *y=(int)((*y)*sc); + + *x+=cx; + *y+=cy; +} + + +/* END OF FILE */ diff --git a/editthng.c b/editthng.c new file mode 100644 index 0000000..44bc787 --- /dev/null +++ b/editthng.c @@ -0,0 +1,670 @@ +/* + + 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 "util.h" + +#include "editvar.h" + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static void ThingSelectionCentre(int *x,int *y) +{ + int *f; + EditThing *t; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + + min_x=MIN(t->t.x,min_x); + min_y=MIN(t->t.y,min_y); + max_x=MAX(t->t.x,max_x); + max_y=MAX(t->t.y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +/* ---------------------------------------- GENERIC THING FUNCS +*/ +int PositionOnObject_THING(int x,int y,void *data) +{ + EditThing *t; + int r; + + TRACE; + + t=data; + r=ThingRadius(t->t.type,NULL); + + return (RADBOUND(x,y,t->t.x,t->t.y,r)); +} + + +void SelectBox_THING(int x1,int y1,int x2,int y2) +{ + Object *o; + EditThing *t; + int f; + + TRACE; + + for(f=0;f<MapSize(thing);f++) + { + o=MapElem(thing,f); + + if ((t=o->data)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(t->t.x,t->t.y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_THING(void) +{ + Object *o; + EditThing *t; + int id; + int f; + + if ((id=SelectThing())!=THING_NULLID) + { + ClearSelection(); + + for(f=0;f<MapSize(thing);f++) + if ((o=MapElem(thing,f))) + if ((t=o->data)&&(t->t.type==id)) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } +} + + +void DrawObject_THING(void *data, int selmode) +{ + EditThing *t; + int a; + int lx,ly; + int r; + int col; + + TRACE; + t=data; + + a=((t->t.ang+22)/45%8); + r=ThingRadius(t->t.type,&col); + + switch(selmode) + { + case SELECT_OVER: + col=OVERCOL; + break; + case SELECT_SELECTED: + col=SELCOL; + break; + default: + break; + } + + lx=t->t.x+(t_arrow[a].x*r); + ly=t->t.y+(t_arrow[a].y*r); + + MapCircle(t->t.x,t->t.y,r,col); + DrawArrow(t->t.x,t->t.y,lx,ly,col); +} + + +void DrawObjectInfo_THING(void) +{ + EditThing *ti; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((ti=GETTHING(current)))) + GuiDrawInfoBox("THING",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Thing No : %d|" + "Thing Id : %d|" + "Angle : %s (%d)|" + "Flags : %s (0x%.2x)|" + "Name : %-60s", + current, + ti->t.type, + ANGLESTR(ti->t.ang),ti->t.ang, + ThingFlagText((int)ti->t.opt),ti->t.opt, + ThingName(ti->t.type)); + else + GuiDrawInfoBox("THING",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Thing No : -|" + "Thing Id : -|" + "Angle : -|" + "Flags : - (-)|" + "Name : %-60s",""); +} + + +void DrawObjectHeader_THING(void) +{ +} + + +void MoveObject_THING(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditThing *t; + List orig; + int *f; + Point p; + int cancel=FALSE; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + p.x=t->t.x; + p.y=t->t.y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move THING",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + memcpy(&p,IteratorData(i2),sizeof(Point)); + t=GETTHING(*f); + t->t.x=p.x; + t->t.y=p.y; + + i=IteratorNext(i); + i2=IteratorNext(i2); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + i=ListIterator(selected); + while(i) + { + f=IteratorData(i); + + t=GETTHING(*f); + + t->t.x+=dmx; + t->t.y+=dmy; + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_THING(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditThing *t; + + TRACE; + + ThingSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + + x=t->t.x; + y=t->t.y; + + Rotate(cx,cy,&x,&y,angle); + + t->t.x=x; + t->t.y=y; + + i=IteratorNext(i); + } +} + + +void ScaleObject_THING(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditThing *t; + + TRACE; + + ThingSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + t=GETTHING(*f); + + x=t->t.x; + y=t->t.y; + + Scale(cx,cy,&x,&y,scale); + + t->t.x=x; + t->t.y=y; + + i=IteratorNext(i); + } +} + + +void SetTagObject_THING(int tag) +{ + TRACE; +} + + +void LocateObject_THING(void *obj) +{ + EditThing *t; + + TRACE; + + t=obj; + + ox=t->t.x-scale*SCRW/2; + oy=t->t.y+scale*SCRH/2; +} + + +void ObjectInsert_THING(void) +{ + Object o; + EditThing *t; + int f; + + TRACE; + + t=Grab(sizeof(EditThing)); + memcpy(&t->t,&ed_thing,sizeof(Thing)); + t->t.x=SnapX(XToMap(ms.x)); + t->t.y=SnapY(YToMap(ms.y)); + + f=MapSize(thing); + + switch(insert_select) + { + case HOVER_NONE: + o.select=SELECT_NONE; + break; + case HOVER_ADD: + case HOVER_SINGLE: + o.select=SELECT_SELECTED; + break; + } + + o.data=t; + DrawObject_THING(t,o.select); + MapAdd(thing,f,&o); + + switch(insert_select) + { + case HOVER_NONE: + break; + case HOVER_ADD: + ListAppend(selected,&f); + break; + case HOVER_SINGLE: + ClearSelection(); + ListAppend(selected,&f); + FullRedraw(); + break; + } +} + + +void ObjectDelete_THING(void) +{ + Iterator i; + Object *o; + int *f; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + + o=MapElem(thing,*f); + + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; + + i=IteratorNext(i); + } + + ClearSelection(); + FullRedraw(); +} + + +void ObjectMenu_THING(void) +{ + EditThing *t; + int f,*s; + Iterator i; + int cancel; + int redraw=FALSE; + + TRACE; + + cancel=FALSE; + GFX_redraw(); + + switch(GUI_menu("Thing",ms.x,ms.y,thing_popup,GUI_CANCEL)) + { + case TM_TYPE: + { + Short id; + + id=(Short)SelectThing(); + + if (id!=THING_NULLID) + { + ed_thing.type=id; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.type=id; + i=IteratorNext(i); + } + + redraw=TRUE; + } + } + break; + + case TM_ANGLE: + { + int a; + + t=SelHead(); + a=t->t.ang; + + if ((a=GUI_radio_box + ("Angle",thing_angle,a,GUI_CANCEL))!=GUI_CANCEL) + { + ed_thing.ang=a; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.ang=a; + i=IteratorNext(i); + } + } + + redraw=TRUE; + } + break; + + case TM_FLAGS: + i=ListIterator(selected); + s=IteratorData(i); + t=GETTHING(*s); + f=t->t.opt; + + if (GUI_multi_box("Flags",ThingFlagArray(),&f)) + { + ed_thing.opt=f; + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.opt=ed_thing.opt; + i=IteratorNext(i); + } + + redraw=TRUE; + } + break; + + case TM_SNAP: + { + int orig_lock; + + orig_lock=grid_lock; + grid_lock=TRUE; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + t=GETTHING(*s); + t->t.x=SnapX(t->t.x); + t->t.y=SnapX(t->t.y); + i=IteratorNext(i); + } + + grid_lock=orig_lock; + redraw=TRUE; + + break; + } + + case TM_DELETE: + ObjectDelete_THING(); + break; + + case TM_MOVE: + MoveObject_THING(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } + else if (redraw) + FullRedraw(); +} + + +void ObjectKey_THING(GFXKey k) +{ +} + + +int ObjectHasTag_THING(void *obj, int tag) +{ + return(FALSE); +} + + +ObjDesc *ObjectOverlaid_THING(int x, int y, int *no) +{ + int n; + EditThing *t; + ObjDesc *od; + int f; + + TRACE; + + od=NULL; + + n=0; + + for(f=0;f<MapSize(thing);f++) + { + t=GETTHING(f); + + if ((t)&&(PositionOnObject_THING(x,y,t))) + { + n++; + od=ReGrab(od,sizeof(ObjDesc)*n); + od[n-1].no=f; + sprintf(od[n-1].detail,"%5d - %s (%s)",f, + TrimStr(ThingName(t->t.type),29), + TrimStr(ThingFlagText(t->t.opt),19)); + } + } + + *no=n; + return(od); +} + + +/* END OF FILE */ diff --git a/editvar.c b/editvar.c new file mode 100644 index 0000000..2734f4d --- /dev/null +++ b/editvar.c @@ -0,0 +1,396 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor global varaiable definitions + + Note that the lindefs, vertices, etc here are copied from the WadMap + loaded prior to editting. They are then reconverted back to the WadMap + for saving. + + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "editvar.h" + + +/* ---------------------------------------- EDIT TYPES +*/ + +char *edit_str[]={"Sector","Linedef","Vertex","Thing","Multimode"}; + + +/* ---------------------------------------- EDIT VARS +*/ + +void HandleMoveKey(GFXKey k,int check_mouse); + +int edit_mode=SECTOR_MODE; + +Map vertex=NULL; +Map linedef=NULL; +Map sidedef=NULL; +Map sector=NULL; +Map thing=NULL; +Map multimap=NULL; + +int SCRW; +int SCRH; +int FH; + +int scale=5; +int ox; +int oy; + +GFXMouse ms; + +int quit; + +int agrid; + +int current=-1; +List selected=NULL; + +/* This variable should be set to try by any actions in the generic object + routines that have generated a new selection list. +*/ +int new_selection=FALSE; + +Thing ed_thing={0,0,0,1,0x07}; + +/* This variable stops the DrawObjectInfo() routine being called on redraws +*/ +int draw_current_info=TRUE; + +/* ---------------------------------------- USED AS GENERIC FUNCTIONS AND VALUES +*/ + +/* Data in all these functions is the Object.data pointer +*/ +int (*PositionOnObject)(int x, int y, void *data); +void (*SelectBox)(int x1, int y1, int x2, int y2); +void (*SelectByType)(void); +void (*DrawObject)(void *data, int selmode); +void (*DrawObjectInfo)(void); +void (*DrawObjectHeader)(void); +void (*MoveObject)(void); +void (*RotateObject)(double angle); +void (*ScaleObject)(double scale); +void (*SetTagObject)(int tag); +void (*LocateObject)(void *obj); +void (*ObjectMenu)(void); +void (*ObjectInsert)(void); +void (*ObjectDelete)(void); +void (*ObjectKey)(GFXKey k); +int (*ObjectHasTag)(void *obj, int tag); +void (*SetSelect)(int i, int mode); +ObjDesc *(*ObjectOverlaid)(int x,int y,int *no); + +char *typename; +Map map; + + +/* ---------------------------------------- MENUS AND DIALOGS +*/ +PLAT_MENU thing_popup[]={ + {"Change type",TM_TYPE}, + {"Change angle",TM_ANGLE}, + {"Change flags",TM_FLAGS}, + {"Snap selected things",TM_SNAP}, + {"Move",TM_MOVE}, + {"Delete",TM_DELETE}, + {NULL,GUI_CANCEL} + }; + +PLAT_RADIO thing_angle[]={ + {"N",90}, + {"NE",45}, + {"E",0}, + {"SE",315}, + {"S",270}, + {"SW",225}, + {"W",180}, + {"NW",135}, + {NULL,GUI_CANCEL} + }; + +PLAT_MENU vertex_popup[]={ + {"Chain selected vertices",TM_CHAIN}, + {"Chain selected vertices " + "into a sector",TM_CHAIN_SECTOR}, + {"Merge selected vertices",TM_MERGE}, + {"Snap selected vertices",TM_SNAP}, + {"Move",TM_MOVE}, + {"Delete",TM_DELETE}, + {NULL,GUI_CANCEL} + }; + +PLAT_MENU right_popup[]= + { + {"Change upper texture",TM_UPPER_T_R}, + {"Change middle texture",TM_MIDDLE_T_R}, + {"Change lower texture",TM_LOWER_T_R}, + {"Change texture offset",TM_OFFSET_R}, + {"Adjust texture offset",TM_ADJUST_R}, + {"Change sector",TM_SECTOR_R}, + {"Align textures",TM_ALIGN_R}, + + {NULL,GUI_CANCEL} + }; + +PLAT_MENU left_popup[]= + { + {"Change upper texture",TM_UPPER_T_L}, + {"Change middle texture",TM_MIDDLE_T_L}, + {"Change lower texture",TM_LOWER_T_L}, + {"Change texture offset",TM_OFFSET_L}, + {"Adjust texture offset",TM_ADJUST_L}, + {"Change sector",TM_SECTOR_L}, + {"Align textures",TM_ALIGN_L}, + + {NULL,GUI_CANCEL} + }; + +PLAT_MENU linedef_popup[]= + { + {"Change linedef flags",TM_FLAGS}, + {"Change linedef type",TM_TYPE}, + {"Swap sides",TM_SWAP_SIDES}, + {"Split line",TM_SPLIT_LINE}, + {"Select trail from this linedef",TM_TRACK_LINE}, + {"Join linedefs with steps",TM_STEPS}, + + {"Right sidedef =>",TM_RIGHT_SIDE}, + {"Left sidedef =>",TM_LEFT_SIDE}, + + {"Change tag",TM_TAG}, + {"Move",TM_MOVE}, + {"Delete",TM_DELETE}, + {NULL,GUI_CANCEL} + }; + +PLAT_MENU sector_popup[]= + { + {"Change floor height",TM_FLOOR}, + {"Change ceiling height",TM_CEILING}, + {"Change light level",TM_LIGHT}, + {"Change tag",TM_TAG}, + {"Change floor",TM_FLOOR_T}, + {"Change ceiling",TM_CEILING_T}, + {"Change type",TM_TYPE}, + {"Paint sector in style",TM_STYLE}, + + {"Move",TM_MOVE}, + {"Delete",TM_DELETE}, + {NULL,GUI_CANCEL} + }; + +PLAT_MENU multi_popup[]= + { + {"Move",TM_MOVE}, + {"Rotate",TM_ROTATE}, + {"Scale",TM_SCALE}, + {NULL,GUI_CANCEL} + }; + + +PLAT_DIALOG offset_dialog[D_OFFSET_NO]= + { + {"X-offset",PLAT_DIAL_INTEGER,{0}}, + {"Y-offset",PLAT_DIAL_INTEGER,{0}} + }; + +PLAT_DIALOG sectorn_dialog[D_OFFSET_NO]= + { + {"Sector no",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG coord_dialog[D_COORD_NO]= + { + {"X",PLAT_DIAL_INTEGER,{0}}, + {"Y",PLAT_DIAL_INTEGER,{0}} + }; + +PLAT_DIALOG vertex_dialog[D_VERTEX_NO]= + { + {"Vertex from",PLAT_DIAL_INTEGER,{0}}, + {"Vertex to",PLAT_DIAL_INTEGER,{0}} + }; + +PLAT_DIALOG sector_fl_dialog[D_SECTOR_FL_NO]= + { + {"Floor height",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG sector_ce_dialog[D_SECTOR_CE_NO]= + { + {"Ceiling height",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG sector_li_dialog[D_SECTOR_LI_NO]= + { + {"Light level",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG sector_val_dialog[D_SECTOR_VAL_NO]= + { + {"Light level",PLAT_DIAL_INTEGER,{0}}, + {"Floor height",PLAT_DIAL_INTEGER,{0}}, + {"Ceiling height",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG tag_dialog[D_TAG_NO]= + { + {"Tag",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG scale_dialog[D_SCALE_NO]= + { + {"Scale",PLAT_DIAL_DOUBLE,{0}}, + }; + +PLAT_DIALOG rotate_dialog[D_ROTATE_NO]= + { + {"Angle",PLAT_DIAL_DOUBLE,{0}}, + }; + +PLAT_DIALOG objno_dialog[D_OBJNO_NO]= + { + {"Object number",PLAT_DIAL_INTEGER,{0}}, + }; + +PLAT_DIALOG nosides_dialog[D_NOSIDES_NO]= + { + {"Number of sides",PLAT_DIAL_INTEGER,{0}}, + }; + + +/* ---------------------------------------- DRAWING TABLES +*/ +Point t_arrow[8]={{1,0}, + {1,1}, + {0,1}, + {-1,1}, + {-1,0}, + {-1,-1}, + {0,-1}, + {1,-1}}; + +char *angle_str[8]={"E","NE","N","NW","W","SW","S","SE"}; + + +/* ---------------------------------------- HELP PAGES +*/ +char *general_help_keys[]= + { + "F1 - general help |" + "F2 - edit mode help |" + "Escape - finish editting |" + "Cursor keys - move |" + "Shift + Cursor keys - move quickly |" + "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 ", + + "DELETE - delete selected objects |" + "INSERT - insert new object |" + "F3 - merge a PWAD map |" + "F4 - move selected objects |" + "F5 - rotate selected objects |" + "[ - rotate 5 degrees left |" + "] - rotate 5 degrees right |" + "F6 - scale selected objects |" + "{ - scale by 90% |" + "} - scale by 110% |" + "F7 - set tag (if applicable) |" + "Shift + F7 - select objects with tag |" + "F8 - locate an object number |" + "Shift + F8 - locate and select object number|" + "R - redraw [useful if selected |" + " sectors look unselected] |" + " |" + "Note: Grid lock not honoured on rotate or scale ", + + 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 + */ + "No additional key functions", + + /* MULTI + */ + "No additional key functions" + }; + + +/* END OF FILE */ diff --git a/editvar.h b/editvar.h new file mode 100644 index 0000000..f2e53bc --- /dev/null +++ b/editvar.h @@ -0,0 +1,633 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor global variable definitions + + $Id$ + +*/ + +#ifndef _EDITVAR_H + +#define _EDITVAR_H + +#include "things.h" +#include "linedefs.h" +#include "wad.h" +#include "map.h" +#include "list.h" +#include "platgui.h" +#include "gui.h" +#include "mem.h" + +#define MAXLEN 1024 + + +/* ---------------------------------------- EDIT COLOURS +*/ +#define GRIDCOL V_RGB(0x20,0x20,0x80) + +#define LINECOL V_RGB(0xa0,0x9a,0x90) + +#define SECTCOL V_RGB(0xc0,0x00,0x00) + +#define VERTCOL V_RGB(0xff,0xff,0xff) +#define VERTBOXCOL V_RGB(0x60,0x60,0x60) + +#define THINGCOL V_RGB(0xa0,0x10,0x10) +#define SELCOL V_RGB(0xff,0xff,0x00) +#define OVERCOL V_RGB(0xc0,0xc0,0x00) + +#define TAGCOL V_RGB(0xff,0xe0,0xe0) + + +/* ---------------------------------------- EDIT TYPES +*/ + +#define SECTOR_MODE 0 +#define LINEDEF_MODE 1 +#define VERTEX_MODE 2 +#define THING_MODE 3 +#define MULTI_MODE 4 + +#define NEXT_MODE(m) ((m == MULTI_MODE) ? SECTOR_MODE : m+1) +#define PREV_MODE(m) ((m == SECTOR_MODE) ? MULTI_MODE : m-1) + +extern char *edit_str[]; + +#define SELECT_NONE 0 +#define SELECT_OVER 1 +#define SELECT_SELECTED 2 + + +typedef struct + { + int x,y; + } Point; + +/* Edittable types of the lumps from the WAD +*/ +typedef struct + { + Vertex v; + List l; + } EditVert; + +typedef struct + { + int no; + Linedef l; + Sidedef *sr; + Sidedef *sl; + EditVert *v[2]; + int min_x; + int min_y; + int max_x; + int max_y; + } EditLine; + +typedef struct + { + int no; + Sector s; + int min_x; + int min_y; + int max_x; + int max_y; + List v; + List sr; + List sl; + List all; + } EditSect; + +typedef struct + { + Thing t; + } EditThing; + +typedef struct + { + int type; + int i; + int x,y; + } MultiObj; + +typedef struct + { + int select; + void *data; + } Object; + +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 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 + + +extern PLAT_MENU thing_popup[]; + +extern PLAT_RADIO thing_angle[]; + +extern PLAT_MENU vertex_popup[]; + +extern PLAT_MENU right_popup[]; +extern PLAT_MENU left_popup[]; +extern PLAT_MENU linedef_popup[]; + +extern PLAT_MENU sector_popup[]; + +extern PLAT_MENU multi_popup[]; + +#define NO_FIELDS(x) (sizeof(x)/sizeof(x[0])) + +#define D_OFFSET_NO 2 +#define D_OFFSET_OFFX 0 +#define D_OFFSET_OFFY 1 +extern PLAT_DIALOG offset_dialog[D_OFFSET_NO]; + + +#define D_SECTORN_NO 1 +#define D_SECTORN_SECNO 0 +extern PLAT_DIALOG sectorn_dialog[D_OFFSET_NO]; + + +#define D_COORD_NO 2 +#define D_COORD_X 0 +#define D_COORD_Y 1 +extern PLAT_DIALOG coord_dialog[D_COORD_NO]; + + +#define D_VERTEX_NO 2 +#define D_VERTEX_FROM 0 +#define D_VERTEX_TO 1 +extern PLAT_DIALOG vertex_dialog[D_VERTEX_NO]; + + +#define D_SECTOR_FL_NO 1 +#define D_SECTOR_FLOOR 0 +extern PLAT_DIALOG sector_fl_dialog[D_SECTOR_FL_NO]; + + +#define D_SECTOR_CE_NO 1 +#define D_SECTOR_CEILING 0 +extern PLAT_DIALOG sector_ce_dialog[D_SECTOR_CE_NO]; + + +#define D_SECTOR_LI_NO 1 +#define D_SECTOR_LIGHT 0 +extern PLAT_DIALOG sector_li_dialog[D_SECTOR_LI_NO]; + + +#define D_SECTOR_VAL_NO 3 +#define D_SVAL_LIGHT 0 +#define D_SVAL_FLOOR 1 +#define D_SVAL_CEILING 2 +extern PLAT_DIALOG sector_val_dialog[D_SECTOR_VAL_NO]; + + +#define D_TAG_NO 1 +#define D_TAG 0 +extern PLAT_DIALOG tag_dialog[D_TAG_NO]; + + +#define D_SCALE_NO 1 +#define D_SCALE 0 +extern PLAT_DIALOG scale_dialog[D_SCALE_NO]; + + +#define D_ROTATE_NO 1 +#define D_ROTATE 0 +extern PLAT_DIALOG rotate_dialog[D_ROTATE_NO]; + + +#define D_OBJNO_NO 1 +#define D_OBJNO 0 +extern PLAT_DIALOG objno_dialog[D_OBJNO_NO]; + + +#define D_NOSIDES_NO 1 +#define D_NOSIDES 0 +extern PLAT_DIALOG nosides_dialog[D_NOSIDES_NO]; + + + +/* ---------------------------------------- DRAWING TABLES +*/ +extern Point t_arrow[8]; + +extern char *angle_str[8]; + +#define ANGLESTR(a) (angle_str[(((a)+22)/45%8)]) + +/* ---------------------------------------- MACROS +*/ +#define PI_VAL 3.14159265358979323846 + +#define RAD(a) (PI_VAL/180.0*(a)) + +#define XToMap(x) (ox+((x)*scale)) +#define YToMap(y) (oy-((y)*scale)) + +#define MapToX(x) (((x)-ox)/scale) +#define MapToY(y) ((oy-(y))/scale) + +#define MapRect(x,y,w,h,c) \ + GFX_rect(MapToX(x),MapToY(y),(w)/scale,(h)/scale,c) + +#define MapLine(x1,y1,x2,y2,c) \ + GFX_line(MapToX(x1),MapToY(y1),MapToX(x2),MapToY(y2),c) + +#define MapLineD(l,c) GFX_line(MapToX((l)->v[0]->v.x), \ + MapToY((l)->v[0]->v.y), \ + MapToX((l)->v[1]->v.x), \ + MapToY((l)->v[1]->v.y),c) + +#define MapPlot(x,y,c) GFX_plot(MapToX(x),MapToY(y),c) + +#define MapCircle(x,y,r,c) \ + GFX_circle(MapToX(x),MapToY(y),(r)/scale,c) + +#define BOXBOUND(tx,ty,x1,y1,x2,y2) \ + (((tx)>=(x1))&&((tx)<=(x2))&&((ty)>=(y1))&&((ty)<=(y2))) +#define BOXBOUND_FUZZY(tx,ty,x1,y1,x2,y2,f) \ + (((tx)>=(x1-(f)))&&((tx)<=(x2+(f)))&&((ty)>=(y1-(f)))&&((ty)<=(y2+(f)))) + +#define ROUGHLY(a,b) (((a)>=(b)-0.01)&&((a)<=(b)+0.01)) + +#define RADBOUND(tx,ty,x,y,r) \ + (((tx)>=(x)-(r))&&((tx)<=(x)+(r))&& \ + ((ty)>=(y)-(r))&&((ty)<=(y)+(r))) + + +#define GETVERT(n) ((EditVert *)(((Object *)MapElem(vertex,(n)))->data)) +#define VERTFROM(m,n) ((EditVert *)(((Object *)MapElem((m),(n)))->data)) +#define GETLINE(n) ((EditLine *)(((Object *)MapElem(linedef,(n)))->data)) +#define GETSIDE(n) ((Sidedef *)(((Object *)MapElem(sidedef,(n)))->data)) +#define SIDEFROM(m,n) ((Sidedef *)(((Object *)MapElem((m),(n)))->data)) +#define GETSECT(n) ((EditSect *)(((Object *)MapElem(sector,(n)))->data)) +#define GETTHING(n) ((EditThing *)(((Object *)MapElem(thing,(n)))->data)) +#define GETMULTI(n) ((MultiObj *)(((Object *)MapElem(multimap,(n)))->data)) + +#define YESNO(x) ((x) ? "Yes":"No") + +/* ------------------------------ HELP PAGES +*/ +extern char *general_help_keys[]; +extern char *general_help_mouse; +extern char *mode_help[]; + + +/* ------------------------------ FUNCTION PROTOTYPES FOR ALL EDIT ROUTINES +*/ +void SectorCalcContaining(int no,EditSect *s); +void SectorCalcContainingAll(void); +int SnapX(int x); +int SnapY(int y); +int Len(int x1,int y1,int x2,int y2); +int LinesCross(int x1_1,int y1_1,int x1_2,int y1_2, + int x2_1,int y2_1,int x2_2,int y2_2); +int CalcTextureWidth(DirName u,DirName m,DirName l); +void LineCalcBounding(EditLine *l); +void SectorCalcBounding(EditSect *s); +int LineOnDisplay(EditLine *l); +int SectorOnDisplay(EditSect *s); +int PointOnDisplay(int x,int y,int r); +void DrawArrow(int x1,int y1,int x2,int y2,int c); +void DrawGrid(void); +void DrawMap(void); +void DrawHeader(void); +void FullRedraw(void); + +void SetSelect_GENERIC(int i, int mode); +int TmpAddCurrent(void); +void ClearSelection(void); +void ClearSelectionLeaveCurrent(void); +void *SelHead(void); + +int InIntList(List l, int i); +void IntListUniqAdd(List l, int i); +void IntListRm(List l, int i); + + +/* If set_class is TRUE then *type is set from the classes loaded in the + config file. + + The floor and ceiling values are used to decide which if the lower, middle + and upper textures to ask for. If the selected linedef style is not two + sided these values are ignored anyway and only the middle one on the right + sidedef is requested. +*/ +int GetLinedefValues(int set_class, + int r_floor,int l_floor,int r_ceiling,int l_ceiling, + int *type,int *flag,int *two, + DirName sr_upper,DirName sr_middle,DirName sr_lower, + DirName sl_upper,DirName sl_middle,DirName sl_lower); + +/* This supercedes the above function when creating sectors. + + THe floor, ceiling and light levels are in/out. The displayed dialog is + loaded with the values sent in and any changes are reflected on return. + + The in_floor and in_ceiling values are used to decide which of the + lower, middle and upper textures set up. If the selected linedef style + is not two sided these values are ignored anyway and only the middle + one on the right sidedef is set to non-empty. When doing comparisons it + is assumed that the in_ values are on the left of the linedefs. + + Note that for this routine rather than being individually requested the + linedef textures are obtained from the defined sector styles (unless there + are no sector styles). Style flags is also set to the flags for sector + style (unless there is no styles, in which case it's zero). + + Note the the sector flags for the style indicating if just the inward + or outward facing sidedefs have the textures applied will be ignored, ie. + both the right and left texture values will have the style applied. + + Returns FALSE if at any point the selections are cancelled. +*/ +int GetSectorValues(int *line_type, int *line_flag, int *two_sided, + int *floor, int *ceiling, int *light, + int in_floor, int in_ceiling, + int *style_flags, + DirName floor_t, DirName ceiling_t, + DirName sr_upper, DirName sr_middle, DirName sr_lower, + DirName sl_upper, DirName sl_middle, DirName sl_lower); + +void GenericCheckMouse(void); +int GetTexture(char *t,DirName d); +int GetFlat(char *t,DirName d); +int YesNo(char *fmt,...); + +/* If draw is not NULL it will be used to draw the selection thing. Note that + the x an y coming into the draw will NOT be snapped. They can be updated + by the drawing mechanism if snapping is requried. + + If key is not NULL any keys read will be passed to the key reoutine (after + being passed to HandleMoveKey()). + + Finally if infobox is not NULL this function is used to draw the describing + infobox, rather than PickPoint()s default one. The prompt (p) PickPoint() + was called with will be passed to the infobox routine. +*/ +int PickPoint(char *p,int *x,int *y,void (*draw)(int *x,int *y), + void (*key)(GFXKey k), + void (*infobox)(char *p)); + +void SetEditMode(int mode); +void HandleMoveKey(GFXKey k, int check_mouse); +void HandleKey(GFXKey k); +void HandleMouse(GFXMouse m); + +void MergeWad(void); + +void Rotate(int cx,int cy,int *x,int *y, double ang); +void Scale(int cx,int cy,int *x,int *y, double sc); + +int PositionOnObject_VERTEX(int x,int y,void *data); +void SelectBox_VERTEX(int x1,int y1,int x2,int y2); +void SelectByType_VERTEX(void); +void DrawObject_VERTEX(void *data, int selmode); +void DrawObjectInfo_VERTEX(void); +void DrawObjectHeader_VERTEX(void); +void MoveObject_VERTEX(void); +void RotateObject_VERTEX(double angle); +void ScaleObject_VERTEX(double scale); +void SetTagObject_VERTEX(int tag); +void LocateObject_VERTEX(void *obj); +void ObjectInsert_VERTEX(void); +void ObjectDelete_VERTEX(void); +void ObjectMenu_VERTEX(void); +void ObjectKey_VERTEX(GFXKey k); +int ObjectHasTag_VERTEX(void *obj, int tag); +ObjDesc *ObjectOverlaid_VERTEX(int x,int y,int *no); + +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); + +#endif + +/* END OF FILE */ diff --git a/editvert.c b/editvert.c new file mode 100644 index 0000000..b11c96b --- /dev/null +++ b/editvert.c @@ -0,0 +1,840 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor VERTEX definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "editvar.h" + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static void VertexSelectionCentre(int *x,int *y) +{ + int *f; + EditVert *v; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + min_x=MIN(v->v.x,min_x); + min_y=MIN(v->v.y,min_y); + max_x=MAX(v->v.x,max_x); + max_y=MAX(v->v.y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +static void MergeVertex(int new,int old) +{ + Object *o; + EditVert *v; + EditLine *l; + int f; + + o=MapElem(vertex,old); + v=o->data; + ListClear(v->l); + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; + + v=GETVERT(new); + + for(f=0;f<MapSize(linedef);f++) + if ((l=GETLINE(f))) + { + if (l->l.from==old) + { + l->l.from=new; + l->v[0]=v; + IntListUniqAdd(v->l,f); + } + + if (l->l.to==old) + { + l->l.to=new; + l->v[1]=v; + IntListUniqAdd(v->l,f); + } + } + + if (merge_linedef!=MERGE_NEVER) + { + v=GETVERT(new); + CheckMergeLinedef(v); + } +} + +/* ---------------------------------------- GENERIC VERTEX FUNCS +*/ +int PositionOnObject_VERTEX(int x,int y,void *data) +{ + EditVert *v; + + TRACE; + + v=data; + return (RADBOUND(x,y,v->v.x,v->v.y,vertex_rad)); +} + + +void SelectBox_VERTEX(int x1,int y1,int x2,int y2) +{ + Object *o; + EditVert *v; + int f; + + TRACE; + + for(f=0;f<MapSize(vertex);f++) + { + o=MapElem(vertex,f); + + if ((v=o->data)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(v->v.x,v->v.y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_VERTEX(void) +{ + return; +} + + +void DrawObject_VERTEX(void *data, int selmode) +{ + EditVert *v; + int col; + + TRACE; + v=data; + + MapPlot(v->v.x,v->v.y,VERTCOL); + + switch(selmode) + { + case SELECT_OVER: + col=OVERCOL; + break; + case SELECT_SELECTED: + col=SELCOL; + break; + default: + col=VERTBOXCOL; + break; + } + + MapRect(v->v.x-vertex_rad,v->v.y+vertex_rad,vertex_rad*2,vertex_rad*2,col); +} + + +void DrawObjectInfo_VERTEX(void) +{ + EditVert *v; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((v=GETVERT(current)))) + GuiDrawInfoBox("VERTEX",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Vertex No : %10d|" + "X : %10d|" + "Y : %10d", + current, + v->v.x,v->v.y); + else + GuiDrawInfoBox("VERTEX",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Vertex No : - |" + "X : - |" + "Y : - "); +} + + +void DrawObjectHeader_VERTEX(void) +{ +} + + +void MoveObject_VERTEX(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditVert *v,*v2; + List orig; + int *f; + int r; + Point p; + int cancel; + int done_merge; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + done_merge=FALSE; + orig=ListNew(sizeof(Point)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + p.x=v->v.x; + p.y=v->v.y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move VERTEX",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + memcpy(&p,IteratorData(i2),sizeof(Point)); + v=GETVERT(*f); + v->v.x=p.x; + v->v.y=p.y; + + i=IteratorNext(i); + i2=IteratorNext(i2); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + i=ListIterator(selected); + while(i) + { + f=IteratorData(i); + + v=GETVERT(*f); + + v->v.x+=dmx; + v->v.y+=dmy; + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + + if (!cancel) + { + int ask; + int ok; + + ask=TRUE; + ok=TRUE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + + for(r=0;(r<MapSize(vertex))&&(ok);r++) + if (r!=*f) + { + v=GETVERT(*f); + v2=GETVERT(r); + + if ((v)&&(v2)) + if ((v->v.x==v2->v.x)&&(v->v.y==v2->v.y)) + { + if (ask) + { + ok=YesNo("Merge overlapping vertexes?"); + ask=FALSE; + } + + if (ok) + { + MergeVertex(*f,r); + done_merge=TRUE; + } + } + } + + i=IteratorNext(i); + } + + if (done_merge) + SectorCalcContainingAll(); + } + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_VERTEX(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditVert *v; + + TRACE; + + VertexSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + x=v->v.x; + y=v->v.y; + + Rotate(cx,cy,&x,&y,angle); + + v->v.x=x; + v->v.y=y; + + i=IteratorNext(i); + } +} + + +void ScaleObject_VERTEX(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditVert *v; + + TRACE; + + VertexSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + x=v->v.x; + y=v->v.y; + + Scale(cx,cy,&x,&y,scale); + + v->v.x=x; + v->v.y=y; + + i=IteratorNext(i); + } +} + + +void SetTagObject_VERTEX(int tag) +{ + TRACE; +} + + +void LocateObject_VERTEX(void *obj) +{ + EditVert *v; + + TRACE; + + v=obj; + + ox=v->v.x-scale*SCRW/2; + oy=v->v.y+scale*SCRH/2; +} + + +void ObjectInsert_VERTEX(void) +{ + Object o; + EditVert *v; + int f; + + TRACE; + + v=Grab(sizeof(EditVert)); + v->v.x=SnapX(XToMap(ms.x)); + v->v.y=SnapY(YToMap(ms.y)); + v->l=ListNew(sizeof(int)); + + f=MapSize(vertex); + + switch(insert_select) + { + case HOVER_NONE: + o.select=SELECT_NONE; + break; + case HOVER_ADD: + case HOVER_SINGLE: + o.select=SELECT_SELECTED; + break; + } + + o.data=v; + DrawObject_VERTEX(v,o.select); + MapAdd(vertex,f,&o); + + switch(insert_select) + { + case HOVER_NONE: + break; + case HOVER_ADD: + ListAppend(selected,&f); + break; + case HOVER_SINGLE: + ClearSelection(); + ListAppend(selected,&f); + FullRedraw(); + break; + } +} + + +void ObjectDelete_VERTEX(void) +{ + Iterator i; + Object *o; + EditVert *v; + int *f; + int bound; + + TRACE; + + i=ListIterator(selected); + bound=FALSE; + + while(i) + { + f=IteratorData(i); + + o=MapElem(vertex,*f); + v=o->data; + + if (ListSize(v->l)) + bound=TRUE; + else + { + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; + } + + i=IteratorNext(i); + } + + ClearSelection(); + FullRedraw(); + + if (bound) + { + GuiInfoBox("WARNING","1 or more VERTEX found still bound to LINEDEF|" + "These have not been deleted"); + + FullRedraw(); + } +} + + +void ObjectMenu_VERTEX(void) +{ + Iterator i; + int from; + int to; + int first; + int type; + int flag; + int two; + int wr,wl; + int oxr,oxl; + DirName sr_upper,sr_middle,sr_lower; + DirName sl_upper,sl_middle,sl_lower; + EditVert *v1=NULL,*v2=NULL; + int cancel=FALSE; + int redraw=FALSE; + int in_sector; + int loop; + int nl; + + TRACE; + + GFX_redraw(); + + switch(GUI_menu("Vertex",ms.x,ms.y,vertex_popup,GUI_CANCEL)) + { + case TM_CHAIN: + cancel=TRUE; + + if (ListSize(selected)<2) + { + GuiInfoBox("ERROR","Need 2 or more vertices|to chain a line"); + redraw=TRUE; + } + else + { + if (GetLinedefValues(TRUE,0,0,0,0, + &type,&flag,&two, + sr_upper,sr_middle,sr_lower, + sl_upper,sl_middle,sl_lower)) + { + if (ListSize(selected)>2) + loop=YesNo("Join last vertex to first one?"); + else + loop=FALSE; + + oxr=0; + oxl=0; + + wr=CalcTextureWidth(sr_upper,sr_middle,sr_lower); + + if (two) + wl=CalcTextureWidth(sl_upper,sl_middle,sl_lower); + else + wl=0; + + i=ListIterator(selected); + + memcpy(&to,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + first=to; + + while(i) + { + from=to; + memcpy(&to,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + + v1=GETVERT(from); + v2=GETVERT(to); + + in_sector=SectorHoldingPoint(v1->v.x,v1->v.y); + + nl=CreateNewLinedef(from,to, + flag,type,0,two, + oxr,0,in_sector, + sr_upper,sr_middle,sr_lower, + oxl,0,in_sector, + sl_upper,sl_middle,sl_lower); + + IntListUniqAdd(v1->l,nl); + IntListUniqAdd(v2->l,nl); + + if (wr) + oxr=(oxr+Len(v1->v.x,v1->v.y,v2->v.x,v2->v.y))%wr; + + if ((two)&&(wl)) + oxl=(oxl+Len(v1->v.x,v1->v.y,v2->v.x,v2->v.y))%wl; + } + + in_sector=SectorHoldingPoint(v2->v.x,v2->v.y); + + if (loop) + { + v1=GETVERT(to); + v2=GETVERT(first); + + nl=CreateNewLinedef(to,first, + flag,type,0,two, + oxr,0,in_sector, + sr_upper,sr_middle,sr_lower, + oxl,0,in_sector, + sl_upper,sl_middle,sl_lower); + + IntListUniqAdd(v1->l,nl); + IntListUniqAdd(v2->l,nl); + } + + cancel=FALSE; + redraw=TRUE; + + SectorCalcContainingAll(); + } + } + + break; + + case TM_CHAIN_SECTOR: + if (CreateSector(selected)) + redraw=TRUE; + else + cancel=TRUE; + break; + + case TM_MERGE: + if (ListSize(selected)<2) + { + GuiInfoBox("ERROR","Need 2 or more vertices|to merge them"); + redraw=TRUE; + cancel=TRUE; + } + else + { + redraw=TRUE; + i=ListIterator(selected); + memcpy(&first,IteratorData(i),sizeof(int)); + i=IteratorNext(i); + + while(i) + { + memcpy(&to,IteratorData(i),sizeof(int)); + MergeVertex(first,to); + i=IteratorNext(i); + } + + SectorCalcContainingAll(); + } + break; + + case TM_SNAP: + { + int orig_lock; + int *f; + EditVert *v; + + orig_lock=grid_lock; + grid_lock=TRUE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + v=GETVERT(*f); + + v->v.x=SnapX(v->v.x); + v->v.y=SnapX(v->v.y); + + i=IteratorNext(i); + } + + grid_lock=orig_lock; + redraw=TRUE; + + break; + } + + case TM_DELETE: + ObjectDelete_VERTEX(); + break; + + case TM_MOVE: + MoveObject_VERTEX(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } + else if (redraw) + FullRedraw(); +} + + +void ObjectKey_VERTEX(GFXKey k) +{ + int f; + int n; + Object *o; + EditVert *v; + + switch(k.code) + { + case GFX_F12: + ClearSelection(); + n=0; + + for(f=0;f<MapSize(vertex);f++) + { + o=MapElem(vertex,f); + + if (o->data) + { + v=o->data; + + if (ListSize(v->l)==0) + { + ListClear(v->l); + Release(o->data); + o->data=NULL; + n++; + } + } + } + + GuiInfoBox("NOTICE","Deleted %d vertices",n); + FullRedraw(); + + break; + + default: + break; + } +} + + +int ObjectHasTag_VERTEX(void *obj, int tag) +{ + return(FALSE); +} + + +ObjDesc *ObjectOverlaid_VERTEX(int x, int y, int *no) +{ + int n; + EditVert *v; + ObjDesc *od; + int f; + + TRACE; + + od=NULL; + + n=0; + + for(f=0;f<MapSize(vertex);f++) + { + v=GETVERT(f); + + if ((v)&&(PositionOnObject_VERTEX(x,y,v))) + { + n++; + od=ReGrab(od,sizeof(ObjDesc)*n); + od[n-1].no=f; + sprintf(od[n-1].detail,"%5d - %d,%d",f,v->v.x,v->v.y); + } + } + + *no=n; + return(od); +} + + +/* END OF FILE */ @@ -0,0 +1,58 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + File system interfaces + + $Id$ + + +*/ + +#ifndef _FILE_H + +#define _FILE_H + +/* Return current working directory +*/ +char *Pwd(void); + +/* Change directory +*/ +void Cd(char *path); + +/* Dirname portion of a path +*/ +char *Dirname(char *path); + +/* Basename portion of a path +*/ +char *Basename(char *path); + +/* Returns TRUE if file exists +*/ +int FileExists(char *path); + +/* Returns TRUE if the the two paths point to the same file +*/ +int FilenamesEqual(char *path1, char *path2); + +#endif @@ -0,0 +1,314 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides a skin of graphics and input functions (in case of future + ports). + + Assumes these features: + + - A true, or hicolor, display + - A Fixed font + - Default origin is in the top left of the display, with X positve + along and Y positive down + - A buffered display. The screen contents should not change until + GFX_redraw() is called. If not honoured viDOOM should still work up + to a point, but it's use of the XOR mode may not be apparent to the + user. + + $Id$ + +*/ +#ifndef _GFX_H + +#define _GFX_H + +/* Opaque type to define a bitmap object and the public creator type, along + with the picklist data providers. Note that the bitmap object is assumed + to have a maximum of 256 unique colours. +*/ +typedef void *GFX_IMAGE; + +#define MAX_GFXBM_W 256 +#define MAX_GFXBM_H 256 + +typedef struct + { + int w; /* Width */ + int h; /* Height */ + int pal[256]; /* Palette */ + unsigned char *data; /* Accessed as data+(x)+(y)*(width) */ + } GFX_BITMAP; + +/* Key press structure +*/ +typedef struct + { + int type; /* Event type (for GFX_await_input()) */ + int shift; /* Is shift pressed? */ + int ctrl; /* Is control pressed? */ + int alt; /* Is ALT pressed? */ + char ascii; /* ASCII code for the char. If zero ... */ + int code; /* ... this holds a special code defined below */ + } GFXKey; + + +/* Special non-ASCII keys that can be returned +*/ +#define GFX_ASCII 0 /* Not a special key - just ASCII */ + +#define GFX_F1 1001 +#define GFX_F2 1002 +#define GFX_F3 1003 +#define GFX_F4 1004 +#define GFX_F5 1005 +#define GFX_F6 1006 +#define GFX_F7 1007 +#define GFX_F8 1008 +#define GFX_F9 1009 +#define GFX_F10 1010 +#define GFX_F11 1011 +#define GFX_F12 1012 + +#define GFX_ESC 1021 +#define GFX_INSERT 1022 +#define GFX_HOME 1023 +#define GFX_PGUP 1024 +#define GFX_DELETE 1025 +#define GFX_END 1026 +#define GFX_PGDN 1027 + +#define GFX_UP 1028 +#define GFX_DOWN 1029 +#define GFX_LEFT 1030 +#define GFX_RIGHT 1031 + +#define GFX_ENTER 1032 +#define GFX_BACKSPACE 1033 +#define GFX_TAB 1034 + + +/* Mouse buttons +*/ +#define GFX_BUTLEFT 0x01 +#define GFX_BUTRIGHT 0x02 +#define GFX_BUTMIDDLE 0x04 + + +/* Event structs for GFX_await_input(). +*/ +#define GFX_KEY_EVENT 1 /* Key pressed */ +#define GFX_MOUSE_EVENT 2 /* Mouse button pressed or mouse moved */ + +typedef struct GFXMouse + { + int type; /* Event type (for GFX_await_input()) */ + int shift; /* Is shift pressed? */ + int ctrl; /* Is control pressed? */ + int alt; /* Is ALT pressed? */ + int x; /* Mouse X co-ord */ + int y; /* Mouse X co-ord */ + int b; /* Mouse button mask */ + } GFXMouse; + +typedef union GFXEvent + { + int type; + GFXKey key; + GFXMouse mouse; + } GFXEvent; + + + +/* Assume an intensity of 0-255 for each RGB component. The library assumes + that colours are represented as an RGB triplet in that order. +*/ +#define V_RGB(r,g,b) ((r)<<16|(g)<<8|(b)) + +#define BLACK 0x000000 +#define WHITE 0xffffff +#define RED 0xff0000 +#define GREEN 0x00ff00 +#define BLUE 0x0000ff +#define GREY(l) V_RGB(l,l,l) + +/* Initialise graphics. This is pretty much called the first thing called. + After calling this it must be that the following functions at least are + operational: + + GFX_close() + GFX_open() + GFX_exit() + GFX_create_image() + + The platform GFX driver can assume no drawing primitives are called till + the screen is opended. + +*/ +void GFX_init(void); + + +/* Closedown for clean, non-error exits. See GFX_exit() for error exits +*/ +void GFX_close(void); + + +/* Create a GFX_IMAGE for the passed GFX_BITMAP. Returns NULL on failure. +*/ +GFX_IMAGE GFX_create_image(GFX_BITMAP *bm); + +/* Destory a bitmap +*/ +void GFX_destroy_image(GFX_IMAGE img); + +/* Draw an image +*/ +void GFX_draw_image(GFX_IMAGE i,int x,int y); + + +/* Fill the screen with an image. Not really crucial as it's just used for + the splash screen. If it cannot be honoured properly just drawing the + GFX_IMAGE centred in the screen should be adequate +*/ +void GFX_fill_screen(GFX_IMAGE i); + + +/* Open a screen/window/whatever. Expected to be true colour, or an + approximation of. Should exit cleanly on failure. +*/ +void GFX_open(int width, int height); + + +/* Clear the screen to a colour +*/ +void GFX_clear(int col); + + +/* It is assumed by viDOOM that what has been drawn will NOT appear on screen + till this is called. +*/ +void GFX_redraw(void); + + +/* Draw a line +*/ +void GFX_line(int x1, int y1, int x2, int y2, int col); + + +/* Plot a point +*/ +void GFX_plot(int x, int y, int col); + + +/* Draw a circle (and filled version) +*/ +void GFX_circle(int x, int y, int radius, int col); +void GFX_fcircle(int x, int y, int radius, int col); + + +/* Draw a rectangle (and filled version). Note that zero and negative width + and heights must be allowed. +*/ +void GFX_rect(int x, int y, int w, int h, int col); +void GFX_frect(int x, int y, int w, int h, int col); + + +/* Sets and clears XOR mode (used for rubber bands, etc). +*/ +void GFX_set_XOR_mode(void); +void GFX_clear_XOR_mode(void); + + +/* printf() text at x,y. The baseline is assumed to be the top left corner of + the box enclosing the text and text is assumed to be transparent +*/ +void GFX_print(int x, int y, int col, char *fmt, ...); + + +/* Return the dimension of the (fixed width!) font used for printing +*/ +int GFX_fh(void); +int GFX_fw(void); + + +/* Return the number of mouse buttons. Should be at least 2. +*/ +int GFX_mouse_buttons(void); + + +/* Sample the current state of the mouse. Return is the button mask. If X or + Y is NULL that position is not returned. +*/ +int GFX_mouse(int *x, int *y); + + +/* Wait for a key to be pressed. key can be NULL if you're not interested in + the key. +*/ +void GFX_waitkey(GFXKey *key); + + +/* Check for a key to be pressed. Returns TRUE or FALSE accordingly and sets + the GFXKey struct up. +*/ +int GFX_key(GFXKey *key); + + +/* If this platform is not event driven, this call should wait kill all keys + and mouse buttons have been released. On event driven ones this may clear + any outstanding input events. +*/ +void GFX_bounce(void); + + +/* Await for any sort of input from the keyboard or mouse buttons. This is + included in the platform specific so that event driven environs (eg. X11) + can work naturally, while non-event driven environments (eg. DOS) can have + the busy polling loop here, rather than in the generic code. +*/ +void GFX_await_input(GFXEvent *ev); + + +/* This works like the above call, but returns mouse movement events (as a + GFX_MOUSE_EVENT) as well. +*/ +void GFX_await_input_full(GFXEvent *ev); + + +/* Tidy up the graphics (switch them off, release mem, etc), print the + supplied error message and then exit with the return code. +*/ +void GFX_exit(int code,char *fmt,...); + + +/* This interface _really_ does not have to do anything. It is just on the + development system so that grabs could be made for the docs. + + If you feel the urge though this should save a snap shot of the current + screen in the passed file. +*/ +void GFX_save_screen(char *path); + + +#endif + + +/* END OF FILE */ diff --git a/gfxtest.c b/gfxtest.c new file mode 100644 index 0000000..3feebc9 --- /dev/null +++ b/gfxtest.c @@ -0,0 +1,468 @@ +/* + + 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 <stdio.h> +#include <ctype.h> +#include "gfx.h" +#include "editvar.h" +#include "mem.h" + +#define SCRW 640 +#define SCRH 480 + +#define RND(x) (rand()%(x)) +#define RCOL V_RGB(RND(255),RND(255),RND(255)) + +void TestPrint(void) +{ + int f; + + GFX_clear(BLACK); + + GFX_print(0,0,WHITE,"Top left"); + GFX_print(0,SCRH-GFX_fh(),WHITE,"Bottom left"); + GFX_print(SCRW-GFX_fw()*strlen("Top right"),0,WHITE,"Top right"); + GFX_print(SCRW-GFX_fw()*strlen("Bottom right"), + SCRH-GFX_fh(),WHITE,"Bottom right"); + + for(f=1;f<4;f++) + GFX_print(0,100+f*GFX_fh(),WHITE,"Row %d",f); + + GFX_redraw(); + GFX_waitkey(NULL); +} + + +void TestMouse(void) +{ + GFXEvent e; + int q; + int f; + + GFX_clear(BLACK); + + q=FALSE; + + while(!q) + { + GFX_redraw(); + GFX_await_input_full(&e); + + switch(e.type) + { + case GFX_KEY_EVENT: + if (e.key.code==GFX_ESC) + q=TRUE; + + if (e.key.code==GFX_ENTER) + GFX_clear(BLACK); + break; + + case GFX_MOUSE_EVENT: + f=0; + if (e.mouse.b&GFX_BUTLEFT) + f|=0xff0000; + if (e.mouse.b&GFX_BUTMIDDLE) + f|=0xff00; + if (e.mouse.b&GFX_BUTRIGHT) + f|=0xff; + + if (f==0) + f=0x808080; + + GFX_frect(0,0,SCRW,GFX_fh(),BLACK); + GFX_print(0,0,WHITE,"x:%-4d y:%-4d b:%c%c%c", + e.mouse.x,e.mouse.y, + e.mouse.b&GFX_BUTLEFT ? 'L':' ', + e.mouse.b&GFX_BUTMIDDLE ? 'M':' ', + e.mouse.b&GFX_BUTRIGHT ? 'R':' '); + + GFX_plot(e.mouse.x,e.mouse.y,f); + break; + } + } +} + + +void TestRect(void) +{ + int f,w; + int ox,oy; + + ox=20; + oy=100; + + for(w=3;w>-4;w--) + { + GFX_clear(BLACK); + + GFX_print(0,0,WHITE,"Width/height %d",w); + + for(f=0;f<5;f++) + { + GFX_plot(ox+f*20,oy+20,WHITE); + GFX_rect(ox+f*20+10,oy+20,w,w,WHITE); + + GFX_plot(ox+f*20,oy+40,WHITE); + GFX_frect(ox+f*20+10,oy+40,w,w,WHITE); + + GFX_plot(ox+f*20,oy+60,WHITE); + GFX_rect(ox+f*20+10,oy+60,w,w*2,WHITE); + + GFX_plot(ox+f*20,oy+80,WHITE); + GFX_frect(ox+f*20+10,oy+80,w,w*2,WHITE); + + GFX_plot(ox+f*20,oy+100,WHITE); + GFX_rect(ox+f*20+10,oy+100,w*2,w,WHITE); + + GFX_plot(ox+f*20,oy+120,WHITE); + GFX_frect(ox+f*20+10,oy+120,w*2,w,WHITE); + } + + GFX_redraw(); + GFX_waitkey(NULL); + } +} + + +void TestRotate(void) +{ + GFXEvent e; + int q; + int x1,y1,x2,y2; + + GFX_clear(BLACK); + + q=FALSE; + x1=200; + y1=0; + x2=0; + y2=-190; + + while(!q) + { + GFX_redraw(); + GFX_await_input_full(&e); + + switch(e.type) + { + case GFX_KEY_EVENT: + if (e.key.code==GFX_ESC) + q=TRUE; + + if (e.key.code==GFX_ENTER) + GFX_clear(BLACK); + break; + + case GFX_MOUSE_EVENT: + Rotate(0,0,&x1,&y1,10.0); + Rotate(0,0,&x2,&y2,-10.0); + + GFX_plot(e.mouse.x+x1,e.mouse.y+y1,RCOL); + GFX_plot(e.mouse.x+x2,e.mouse.y+y2,RCOL); + break; + } + } +} + + +void TestScale(void) +{ + GFXEvent e; + int q; + int f; + int x,y; + + GFX_clear(BLACK); + + q=FALSE; + x=10; + y=10; + f=0; + + while(!q) + { + GFX_redraw(); + GFX_await_input_full(&e); + + switch(e.type) + { + case GFX_KEY_EVENT: + if (e.key.code==GFX_ESC) + q=TRUE; + + if (e.key.code==GFX_ENTER) + GFX_clear(BLACK); + break; + + case GFX_MOUSE_EVENT: + if (((f++)%20)>10) + Scale(0,0,&x,&y,0.9); + else + Scale(0,0,&x,&y,1.1); + + GFX_plot(e.mouse.x+x,e.mouse.y+y,RCOL); + break; + } + } +} + + +void TestDim(void) +{ + GFX_clear(BLACK); + + GFX_line(0,0,SCRW-1,0,WHITE); + GFX_line(0,SCRH-1,SCRW-1,SCRH-1,WHITE); + + GFX_line(0,0,0,SCRH-1,WHITE); + GFX_line(SCRW-1,0,SCRW-1,SCRH-1,WHITE); + + GFX_line(0,0,SCRW-1,SCRH-1,WHITE); + GFX_line(SCRW-1,0,0,SCRH-1,WHITE); + + GFX_print(20,SCRH/2,WHITE,"GFX_line()"); + + GFX_redraw(); + GFX_waitkey(NULL); + + GFX_clear(BLACK); + + GFX_rect(0,0,SCRW,SCRH,WHITE); + GFX_print(20,SCRH/2,WHITE,"GFX_rect()"); + + GFX_redraw(); + GFX_waitkey(NULL); + + GFX_clear(BLACK); + + GFX_frect(0,0,SCRW,SCRH,RED); + GFX_print(20,SCRH/2,WHITE,"GFX_frect()"); + + GFX_redraw(); + GFX_waitkey(NULL); +} + + +void TestCol(void) +{ + GFX_clear(BLACK); + + GFX_frect(0,0,SCRW,10,WHITE); + GFX_print(0,10,WHITE,"WHITE"); + + GFX_frect(0,20,SCRW,10,RED); + GFX_print(0,30,RED,"RED"); + + GFX_frect(0,40,SCRW,10,BLUE); + GFX_print(0,50,BLUE,"BLUE"); + + GFX_frect(0,60,SCRW,10,GREEN); + GFX_print(0,70,GREEN,"GREEN"); + + GFX_frect(0,80,SCRW,10,GREY(128)); + GFX_print(0,90,GREY(128),"GREY(128)"); + + GFX_redraw(); + GFX_waitkey(NULL); +} + +static void TestDraw(void) +{ + int f; + + GFX_clear(BLACK); + + for(f=0;f<100;f++) + GFX_plot(f,10,WHITE); + GFX_print(0,22,WHITE,"GFX_plot()"); + + GFX_line(0,40,99,40,WHITE); + GFX_print(0,42,WHITE,"GFX_line()"); + + GFX_rect(0,60,100,10,WHITE); + GFX_print(0,70,WHITE,"GFX_rect()"); + + GFX_frect(0,80,100,10,WHITE); + GFX_print(0,90,WHITE,"GFX_frect()"); + + GFX_circle(50,150,50,WHITE); + GFX_print(50,150,WHITE,"GFX_circle()"); + + GFX_fcircle(50,250,50,GREEN); + GFX_print(50,250,WHITE,"GFX_fircle()"); + + for(f=101;f>=99;f--) + { + GFX_line(f,0,f,100,RED); + GFX_redraw(); + GFX_waitkey(NULL); + } +} + + +static void TestBm(void) +{ + static unsigned char data[64]= + { + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,1,2,2,0,0,1,0, + 0,1,2,2,0,0,1,1, + 0,1,0,0,2,2,1,1, + 0,1,0,0,2,2,1,0, + 0,1,1,1,1,1,1,0, + 0,0,0,1,1,0,0,0, + }; + GFX_IMAGE i; + GFX_BITMAP bm; + int f; + + bm.w=8; + bm.h=8; + bm.pal[0]=BLACK; + bm.pal[1]=RED; + bm.pal[2]=WHITE; + bm.data=data; + + i=GFX_create_image(&bm); + GFX_clear(GREEN); + + for(f=0;f<100;f++) + { + GFX_draw_image(i,f,f); + GFX_redraw(); + } + + GFX_waitkey(NULL); + GFX_fill_screen(i); + GFX_redraw(); + GFX_waitkey(NULL); + + GFX_destroy_image(i); +} + + +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; + } + } +} + + +int viDOOM(int argc,char *argv[]) +{ + static struct + { + char *t; + char k; + void (*func)(void); + } test[]= { + {"Test printing",'P',TestPrint}, + {"Test mouse",'M',TestMouse}, + {"Test rectangles",'B',TestRect}, + {"Test screen dimensions",'D',TestDim}, + {"Test EDIT Rotate",'R',TestRotate}, + {"Test EDIT Scale",'S',TestScale}, + {"Test colours",'C',TestCol}, + {"Test drawing",'G',TestDraw}, + {"Test bitmap",'X',TestBm}, + {"Test keyboard",'K',TestKey}, + {NULL,0,NULL} + }; + + GFXKey k; + int quit; + int f; + + GFX_init(); + GFX_open(SCRW,SCRH); + + quit=FALSE; + + while(!quit) + { + GFX_clear(BLACK); + GFX_print(0,0,RED,"Select (ESC quit):"); + + f=0; + while(test[f].t) + { + GFX_print(0,GFX_fh()*(f+2),WHITE,"%c - %s",test[f].k,test[f].t); + f++; + } + + GFX_redraw(); + GFX_waitkey(&k); + + if (k.code==GFX_ESC) + quit=TRUE; + else + { + f=0; + while(test[f].t) + { + if (toupper(k.ascii)==test[f].k) + test[f].func(); + f++; + } + } + } + + return(EXIT_SUCCESS); +} diff --git a/globals.c b/globals.c new file mode 100644 index 0000000..0eb0ad7 --- /dev/null +++ b/globals.c @@ -0,0 +1,983 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Global data + + All the stuff from INI file and from the config files. Note this object + also drives other objects so that the list of things they maintain is + initialised. + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "ini.h" +#include "gfx.h" +#include "texture.h" +#include "things.h" +#include "linedefs.h" +#include "sectors.h" + + +/* Constants +*/ +#define MAXLEN 1024 + +#define M_NONE -1 +#define M_THING_TYPES 0 +#define M_SECTOR_TYPES 1 +#define M_LINEDEF_FLAGS 2 +#define M_INCLUDE 3 +#define M_THING_FLAGS 4 +#define M_LINEDEF_TYPES 5 +#define M_LINEDEF_DEFAULTS 6 +#define M_SECTOR_STYLES 7 +#define M_LINEDEF_FLAGS_EXTRA 8 +#define M_EMPTY_TEXTURE_NAME 9 +#define M_THING_CLASSES 10 +#define M_LINEDEF_CLASSES 11 +#define M_SECTOR_CLASSES 12 +#define M_NORMAL_TYPES 13 +#define M_LINEDEF_CHECK_DEFAULT 14 + + +/* INI sections +*/ +#define GAME_INI "Game" +#define EDITOR_INI "Editor" +#define VIDOOM_INI "viDOOM" +#define CLINEDEF_INI "Check LINEDEF" +#define BUILD_INI "Node Builder" + +#define DOOM_INI "Doom" +#define ULT_DOOM_INI "Ultimate Doom" +#define DOOM2_INI "Doom 2" +#define FINAL_TNT_INI "TNT:Evilution" +#define FINAL_PLUT_INI "Plutonia Experiment" +#define ZDOOM_INI "ZDoom" + +/* ------------------------------ Game type +*/ +GameType game=DOOM_2; +LevelStyle level_style=DOOM_2_LEVELS; +int ask_for_game_type=FALSE; +char *game_name="Doom 2 - Hell on Earth"; + + +/* ------------------------------ Paths +*/ +char IWAD_path[PATH_MAX+1]="." DIRSEP "DOOM2.WAD"; +char PWAD_dir[PATH_MAX+1]="." DIRSEP; +char PWAD_preload[MAX_PRELOAD_LEN]=""; +static char config_file[PATH_MAX+1]="doom2.cfg"; + + +/* ------------------------------ Editor configuration +*/ +int disp_width=640; +int disp_height=480; +int grid_onoff=TRUE; +int grid_lock=TRUE; +int grid_size=64; +double gfx_brighten=1.0; +int vertex_rad=5; +Hover hover_select=HOVER_NONE; +int clear_on_move=TRUE; +int clear_on_menu=FALSE; +Hover insert_select=HOVER_NONE; +SectorMoveMode sector_move=MOVE_RIGHT; +int ask_middle_on_2sided=TRUE; +int default_light_level=200; +int default_floor_height=0; +int default_ceiling_height=256; +NewSelect new_2sided_select=NEWSELECT_ASK; +LinedefMerge merge_linedef=MERGE_ASK; +int auto_block_linedefs=TRUE; +int default_scale=10; +DefaultEdit default_edit_mode=EDIT_SECTOR; +int linedef_select=2; +int tag_highlight=TRUE; +int show_full_linedef_info=FALSE; + + +/* ------------------------------ viDOOM configuration +*/ +int sort_textures=TRUE; +int sort_flats=TRUE; +int show_titlepic=TRUE; +int load_textures=TRUE; +int load_flats=TRUE; +int load_sprites=TRUE; +int map_warn=TRUE; +int map_exit_warn=TRUE; +int initial_empty_map=FALSE; +int overwrite_warning=TRUE; + +/* ------------------------------ Linedef flags bit and mask +*/ +int side2_bit=-1; +int side2_mask; +int block_bit=-1; +int block_mask; +int lower_peg_bit=-1; +int lower_peg_mask; +int upper_peg_bit=-1; +int upper_peg_mask; + +/* ------------------------------ Normal values +*/ +int normal_linedef=0; +int normal_sector=0; + +/* ------------------------------ LINEDEF checking +*/ +int check_line_assume_yes=FALSE; +int check_1side_lower=TRUE; +int check_1side_middle=TRUE; +int check_1side_upper=TRUE; +int check_2side_lower=TRUE; +int check_2side_middle=TRUE; +int check_2side_same_sector=TRUE; +int check_2side_upper=TRUE; + +/* ------------------------------ Node Builder config +*/ +int use_build=FALSE; +char build_cmd[PATH_MAX+1]="bsp.exe"; +char build_ignore[PATH_MAX+1]=""; +char build_in[PATH_MAX+1]="%"; +char build_out[PATH_MAX+1]="%"; +int build_in_before_out=TRUE; +int build_always_view=TRUE; + + + +/* ------------------------------ Texture names +*/ +char empty_texture[256]="-"; +char linedef_check_default[256]="-"; + + +/* ------------------------------ INI tables to data +*/ + +#define INI_FOR_GAME(g) { \ + INI_STR, g, "iwad", \ + IWAD_path, NULL \ + }, \ + { \ + INI_STR, g, "pwad_dir", \ + PWAD_dir, NULL \ + }, \ + { \ + INI_TOK, g, "level_style", \ + &level_style, level_style_tok \ + }, \ + { \ + INI_STR, g, "preload", \ + PWAD_preload, NULL \ + }, \ + { \ + INI_STR, g, "vidoom_config", \ + config_file, NULL \ + } + + +static TokenTable game_type_tok[]= + { + {"Doom",DOOM}, + {"Ultimate Doom",ULTIMATE_DOOM}, + {"Doom 2",DOOM_2}, + {"TNT:Evilution",FINAL_TNT}, + {"Plutonia Experiment",FINAL_PLUTONIA}, + {"ZDoom",ZDOOM}, + {NULL,0} + }; + +static TokenTable level_style_tok[]= + { + {"Doom",DOOM_LEVELS}, + {"Ultimate Doom",ULTIMATE_DOOM_LEVELS}, + {"Doom 2",DOOM_2_LEVELS}, + {NULL,0} + }; + +static TokenTable hover_type_tok[]= + { + {"none",HOVER_NONE}, + {"add",HOVER_ADD}, + {"single",HOVER_SINGLE}, + {NULL,0} + }; + +static TokenTable smove_type_tok[]= + { + {"all",MOVE_ALL}, + {"left",MOVE_LEFT}, + {"right",MOVE_RIGHT}, + {NULL,0} + }; + +static TokenTable new_select_tok[]= + { + {"never",NEWSELECT_NEVER}, + {"ask",NEWSELECT_ASK}, + {"select",NEWSELECT_SELECT}, + {NULL,0} + }; + +static TokenTable merge_mode_tok[]= + { + {"never",MERGE_NEVER}, + {"ask",MERGE_ASK}, + {"always",MERGE_ALWAYS}, + {NULL,0} + }; + +static TokenTable edit_mode_tok[]= + { + {"sector",EDIT_SECTOR}, + {"vertex",EDIT_VERTEX}, + {"linedef",EDIT_LINEDEF}, + {"thing",EDIT_THING}, + {"multi",EDIT_MULTI}, + {NULL,0} + }; + + +static INI_Table part1_ini[]= + { + /* Game type + */ + { + INI_TOK, GAME_INI, "game", + &game, game_type_tok + }, + { + INI_TOK, GAME_INI, "ask", + &ask_for_game_type, ini_yesno + }, + { + INI_INT, EDITOR_INI, "width", + &disp_width, NULL + }, + { + INI_INT, EDITOR_INI, "height", + &disp_height, NULL + }, + }; + +static INI_Table part2_ini[]= + { + /* Editor + */ + { + INI_TOK, EDITOR_INI, "grid", + &grid_onoff, ini_yesno + }, + { + INI_TOK, EDITOR_INI, "grid_lock", + &grid_lock, ini_yesno + }, + { + INI_INT, EDITOR_INI, "grid_size", + &grid_size, NULL + }, + { + INI_DOUBLE, EDITOR_INI, "bright", + &gfx_brighten, NULL + }, + { + INI_INT, EDITOR_INI, "vertex_radius", + &vertex_rad, NULL + }, + { + INI_TOK, EDITOR_INI, "hover_select", + &hover_select, hover_type_tok + }, + { + INI_TOK, EDITOR_INI, "clear_on_move", + &clear_on_move, ini_yesno + }, + { + INI_TOK, EDITOR_INI, "clear_on_menu", + &clear_on_menu, ini_yesno + }, + { + INI_TOK, EDITOR_INI, "insert_select", + &insert_select, hover_type_tok + }, + { + INI_TOK, EDITOR_INI, "sector_move", + §or_move, smove_type_tok + }, + { + INI_TOK, EDITOR_INI, "ask_middle_on_2sided", + &ask_middle_on_2sided, ini_yesno + }, + { + INI_INT, EDITOR_INI, "default_light_level", + &default_light_level, NULL + }, + { + INI_INT, EDITOR_INI, "default_floor_height", + &default_floor_height, NULL + }, + { + INI_INT,EDITOR_INI,"default_ceiling_height", + &default_ceiling_height, NULL + }, + { + INI_TOK, EDITOR_INI, "new_2sided_select", + &new_2sided_select, new_select_tok + }, + { + INI_TOK, EDITOR_INI, "merge_linedef", + &merge_linedef, merge_mode_tok + }, + { + INI_TOK, EDITOR_INI, "auto_block_linedefs", + &auto_block_linedefs, ini_yesno + }, + { + INI_INT, EDITOR_INI, "default_scale", + &default_scale, NULL + }, + { + INI_TOK, EDITOR_INI, "default_edit_mode", + &default_edit_mode, edit_mode_tok + }, + { + INI_INT, EDITOR_INI, "linedef_select", + &linedef_select, NULL + }, + { + INI_TOK, EDITOR_INI,"tag_highlight", + &tag_highlight, ini_yesno + }, + { + INI_TOK,EDITOR_INI,"show_full_linedef_info", + &show_full_linedef_info, ini_yesno + }, + + /* viDOOM + */ + { + INI_TOK, VIDOOM_INI, "sort_texture_names", + &sort_textures, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "sort_flat_names", + &sort_flats, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "show_titlepic", + &show_titlepic, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "load_textures", + &load_textures, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "load_flats", + &load_flats, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "load_sprites", + &load_sprites, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "map_clear_warning", + &map_warn, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "map_exit_warning", + &map_exit_warn, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "initial_empty_map", + &initial_empty_map, ini_yesno + }, + { + INI_TOK, VIDOOM_INI, "overwrite_warning", + &overwrite_warning, ini_yesno + }, + + /* Check LINEDEF + */ + { + INI_TOK, CLINEDEF_INI, "assume_yes", + &check_line_assume_yes, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_1side_lower", + &check_1side_lower, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_1side_middle", + &check_1side_middle, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_1side_upper", + &check_1side_upper, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_2side_lower", + &check_2side_lower, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_2side_middle", + &check_2side_middle, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, + "check_2side_same_sector", + &check_2side_same_sector, ini_yesno + }, + { + INI_TOK, CLINEDEF_INI, "check_2side_upper", + &check_2side_upper, ini_yesno + }, + + /* Node builder + */ + { + INI_TOK, BUILD_INI, "use", + &use_build, ini_yesno + }, + { + INI_STR, BUILD_INI, "command", + build_cmd, NULL + }, + { + INI_STR, BUILD_INI, "ignore", + build_ignore, NULL + }, + { + INI_STR, BUILD_INI, "infile", + build_in, NULL + }, + { + INI_STR, BUILD_INI, "outfile", + build_out, NULL + }, + { + INI_TOK, BUILD_INI, "in_before_out", + &build_in_before_out, ini_yesno + }, + { + INI_TOK, BUILD_INI, "always_view_output", + &build_always_view, ini_yesno + }, + }; + +static INI_Table doom_ini[]={INI_FOR_GAME(DOOM_INI)}; +static INI_Table ult_doom_ini[]={INI_FOR_GAME(ULT_DOOM_INI)}; +static INI_Table doom_2_ini[]={INI_FOR_GAME(DOOM2_INI)}; +static INI_Table tnt_ini[]={INI_FOR_GAME(FINAL_TNT_INI)}; +static INI_Table plut_ini[]={INI_FOR_GAME(FINAL_PLUT_INI)}; +static INI_Table zdoom_ini[]={INI_FOR_GAME(ZDOOM_INI)}; + + + +/* ------------------------------ TYPES +*/ +typedef struct + { + char *str; + int val; + } StrList; + + +/* ------------------------------ PRIVATE FUNCTIONS +*/ + +static void CheckVals(void) +{ + FILE *fp; + + grid_size=MAX(grid_size,2); + default_light_level=default_light_level%256; + linedef_select=MAX(linedef_select,1); + + /* Check config file exists + */ + if (!(fp=fopen(config_file,"r"))) + GFX_exit(EXIT_FAILURE,"Couldn't open config file %s\n",config_file); + + fclose(fp); +} + + +static int StrToInt(StrList s[],char *val,int def) +{ + int f; + int m; + + f=0; + m=def; + + while((s[f].str)&&(m==def)) + { + if (STREQ(s[f].str,val)) + m=s[f].val; + f++; + } + + return(m); +} + + +static char *GetLine(FILE *fp) +{ + static char s[MAXLEN+1]; + int l,f; + + fgets(s,MAXLEN,fp); + + if (feof(fp)) + return(FALSE); + + l=strlen(s)-1; + + if ((l>=0)&&(s[l]=='\n')) + s[l]=0; + + l=strlen(s)-1; + + if ((l>=0)&&(s[l]=='\r')) + s[l]=0; + + l=strlen(s); + for(f=0;f<l;f++) + if (!isspace(s[f])) + if (s[f]=='#') + return(GetLine(fp)); + else + return(s+f); + + return(GetLine(fp)); +} + + +static void DoLoadConfig(char *fn) +{ + static StrList mode_list[]={{"%THING_TYPES",M_THING_TYPES}, + {"%SECTOR_TYPES",M_SECTOR_TYPES}, + {"%LINEDEF_TYPES",M_LINEDEF_TYPES}, + {"%INCLUDE_FILES",M_INCLUDE}, + {"%THING_FLAGS",M_THING_FLAGS}, + {"%LINEDEF_FLAGS",M_LINEDEF_FLAGS}, + {"%LINEDEF_DEFAULTS",M_LINEDEF_DEFAULTS}, + {"%SECTOR_STYLES",M_SECTOR_STYLES}, + {"%LINEDEF_FLAGS_EXTRA",M_LINEDEF_FLAGS_EXTRA}, + {"%EMPTY_TEXTURE_NAME",M_EMPTY_TEXTURE_NAME}, + {"%THING_CLASSES",M_THING_CLASSES}, + {"%LINEDEF_CLASSES",M_LINEDEF_CLASSES}, + {"%SECTOR_CLASSES",M_SECTOR_CLASSES}, + {"%NORMAL_TYPES",M_NORMAL_TYPES}, + {"%LINEDEF_CHECK_DEFAULT", + M_LINEDEF_CHECK_DEFAULT}, + {NULL,0}}; + + FILE *fp; + char *line; + char orig[MAXLEN+1]; + int mode; + char *err; + + mode=M_NONE; + + if (!(fp=fopen(fn,"r"))) + GFX_exit(EXIT_FAILURE,"Couldn't open config file %s\n",fn); + + while((line=GetLine(fp))) + { + strcpy(orig,line); + err=NULL; + + if (*line=='%') + { + mode=StrToInt(mode_list,line,M_NONE); + + switch(mode) + { + case M_SECTOR_STYLES: + StartSectorStyles(); + break; + default: + break; + } + } + else + switch(mode) + { + case M_THING_CLASSES: + { + char *p[2]; + + p[0]=strtok(line,"|"); + + if (p[0]) + p[1]=strtok(NULL,"|"); + + if (p[1]) + ThingNewClass(p[0],ATOI(p[1])); + else + err="THING_CLASSES"; + + break; + } + + case M_LINEDEF_CLASSES: + LinedefNewClass(line); + break; + + case M_SECTOR_CLASSES: + SectorNewClass(line); + break; + + case M_THING_TYPES: + { + char *p[5]; + int f; + + p[0]=strtok(line,"|"); + + for(f=1;(f<5)&&(p[f-1]);f++) + p[f]=strtok(NULL,"|"); + + if (p[4]) + ThingAdd(p[0],p[1],ATOI(p[2]),ATOI(p[3]), + (load_sprites ? DecodeGraphicsLump(p[4]) : + NULL)); + else + err="THING_TYPES"; + + break; + } + + case M_SECTOR_TYPES: + { + char *p[4]; + int f; + + p[0]=strtok(line,"|"); + + for(f=1;(f<4)&&(p[f-1]);f++) + p[f]=strtok(NULL,"|"); + + if (p[3]) + SectorAdd(p[0],ATOI(p[1]),p[2],p[3]); + else + err="SECTOR_TYPES"; + + break; + } + + case M_LINEDEF_TYPES: + { + char *p[3]; + + p[0]=strtok(line,"|"); + + if (p[0]) + p[1]=strtok(NULL,"|"); + + if (p[1]) + p[2]=strtok(NULL,"|"); + + if (p[2]) + LinedefAdd(p[0],p[2],ATOI(p[1])); + else + err="LINEDEF_TYPES"; + + break; + } + + case M_LINEDEF_FLAGS: + { + char *p[3]; + int f; + + p[0]=strtok(line,"|"); + + if (p[0]) + p[1]=strtok(NULL,"|"); + + if (p[1]) + p[2]=strtok(NULL,"|"); + + f=ATOI(p[0]); + + if ((f>=0)&&(f<=15)&&(p[2])) + LinedefFlag(f,p[1],*p[2]); + else + err="LINEDEF_FLAGS"; + + break; + } + + case M_INCLUDE: + { + char s[PATH_MAX]; + + strcpy(s,line); + DoLoadConfig(s); + break; + } + + case M_THING_FLAGS: + { + char *p[3]; + int f; + + p[0]=strtok(line,"|"); + + if (p[0]) + p[1]=strtok(NULL,"|"); + + if (p[1]) + p[2]=strtok(NULL,"|"); + + f=ATOI(p[0]); + + if ((f>=0)&&(f<=15)&&(p[2])) + ThingFlag(f,p[1],p[2]); + else + err="THING_FLAGS"; + + break; + } + + case M_LINEDEF_DEFAULTS: + { + int flags; + char *p[2]; + + if (side2_bit==-1) + GFX_exit + (EXIT_FAILURE, + "LINEDEF_DEFAULTS appeared before " + "LINEDEF_FLAGS_EXTRA\n"); + + p[0]=strtok(line,"|"); + + if (p[0]) + p[1]=strtok(NULL,"|"); + + if (p[1]) + { + flags=ATOI(p[1]); + AddLinedefType(p[0],flags,flags&side2_mask); + } + else + err="LINEDEF_DEFAULTS"; + + break; + } + + case M_SECTOR_STYLES: + { + char *p[7]; + int f; + + p[0]=strtok(line,"|"); + + for(f=1;(f<7)&&(p[f-1]);f++) + p[f]=strtok(NULL,"|"); + + if (p[6]) + AddSectorStyle(p[1],ATOI(p[0]),p[2],p[3], + p[4],p[5],p[6]); + else + err="SECTOR_STYLES"; + + break; + } + + case M_LINEDEF_FLAGS_EXTRA: + { + char *p[4]; + int f; + + p[0]=strtok(line,"|"); + + for(f=1;(f<4)&&(p[f-1]);f++) + p[f]=strtok(NULL,"|"); + + if (p[3]) + { + side2_bit=ATOI(p[0]); + side2_mask=1<<side2_bit; + + block_bit=ATOI(p[1]); + block_mask=1<<block_bit; + + upper_peg_bit=ATOI(p[2]); + upper_peg_mask=1<<upper_peg_bit; + + lower_peg_bit=ATOI(p[3]); + lower_peg_mask=1<<lower_peg_bit; + } + else + err="LINEDEF_FLAGS_EXTRA"; + + break; + } + + case M_EMPTY_TEXTURE_NAME: + strncpy(empty_texture,line,sizeof(empty_texture)-1); + empty_texture[sizeof(empty_texture)-1]=0; + break; + + case M_NORMAL_TYPES: + { + char *p[2]; + + p[0]=strtok(line,"|"); + + if (p[0]) + p[1]=strtok(NULL,"|"); + + if (p[1]) + { + normal_sector=ATOI(p[0]); + normal_linedef=ATOI(p[1]); + } + else + err="NORMAL_TYPES"; + + break; + } + + case M_LINEDEF_CHECK_DEFAULT: + strncpy(linedef_check_default,line, + sizeof(linedef_check_default)-1); + linedef_check_default[sizeof(linedef_check_default)-1]=0; + break; + + case M_NONE: + break; + } + + if (err) + GFX_exit + (EXIT_FAILURE, + "%s: section %s\nError in line '%s'\n",fn,err,orig); + } + + fclose(fp); +} + + +/* ------------------------------ EXPORTED FUNCTIONS +*/ + +void LoadGlobalsPart1(void) +{ + INI_Load("vidoom.ini"); + INI_GetTable(part1_ini,INI_TAB_SIZE(part1_ini)); +} + + +void LoadGlobalsPart2(void) +{ + INI_GetTable(part2_ini,INI_TAB_SIZE(part2_ini)); + + switch(game) + { + case DOOM: + INI_GetTable(doom_ini,INI_TAB_SIZE(doom_ini)); + game_name="Doom - Knee Deep in The Dead"; + break; + case ULTIMATE_DOOM: + INI_GetTable(ult_doom_ini,INI_TAB_SIZE(ult_doom_ini)); + game_name="Utlimate Doom - Thy Flesh Consumed"; + break; + case DOOM_2: + INI_GetTable(doom_2_ini,INI_TAB_SIZE(doom_2_ini)); + game_name="Doom 2 - Hell On Earth"; + break; + case FINAL_TNT: + INI_GetTable(tnt_ini,INI_TAB_SIZE(tnt_ini)); + game_name="Final Doom - TNT:Evilution"; + break; + case FINAL_PLUTONIA: + INI_GetTable(plut_ini,INI_TAB_SIZE(plut_ini)); + game_name="Final Doom - The Plutonia Experiment"; + break; + case ZDOOM: + INI_GetTable(zdoom_ini,INI_TAB_SIZE(zdoom_ini)); + game_name="ZDoom/BOOM extensions to Doom"; + break; + } + + CheckVals(); +} + + +void SaveGlobals(void) +{ + INI_PutTable(part1_ini,INI_TAB_SIZE(part1_ini)); + INI_PutTable(part2_ini,INI_TAB_SIZE(part2_ini)); + + switch(game) + { + case DOOM: + INI_PutTable(doom_ini,INI_TAB_SIZE(doom_ini)); + break; + case ULTIMATE_DOOM: + INI_PutTable(ult_doom_ini,INI_TAB_SIZE(ult_doom_ini)); + break; + case DOOM_2: + INI_PutTable(doom_2_ini,INI_TAB_SIZE(doom_2_ini)); + break; + case FINAL_TNT: + INI_PutTable(tnt_ini,INI_TAB_SIZE(tnt_ini)); + break; + case FINAL_PLUTONIA: + INI_PutTable(plut_ini,INI_TAB_SIZE(plut_ini)); + break; + case ZDOOM: + INI_PutTable(zdoom_ini,INI_TAB_SIZE(zdoom_ini)); + break; + } + + INI_Save(); +} + + +void LoadConfig(void) +{ + DoLoadConfig(config_file); +} + + +/* END OF FILE */ + diff --git a/globals.h b/globals.h new file mode 100644 index 0000000..8109dd6 --- /dev/null +++ b/globals.h @@ -0,0 +1,211 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Global data - just about all from INI file + + $Id$ + +*/ + +#ifndef _GLOBALS_H + +#define _GLOBALS_H + + +#define MAX_PRELOAD_LEN 4096 + +/* ------------------------------ Game type +*/ + +typedef enum game_type { + DOOM, + ULTIMATE_DOOM, + DOOM_2, + FINAL_TNT, + FINAL_PLUTONIA, + ZDOOM + } GameType; + +typedef enum lev_style { + DOOM_LEVELS, + ULTIMATE_DOOM_LEVELS, + DOOM_2_LEVELS + } LevelStyle; + +/* These are set by LoadGlobalsGameSection() +*/ +extern GameType game; +extern int ask_for_game_type; +extern int disp_width; +extern int disp_height; + + +/* This and everthing from here on is set by LoadGlobalsOtherSections() +*/ +extern LevelStyle level_style; +extern char *game_name; + + +/* ------------------------------ Paths +*/ +extern char IWAD_path[]; +extern char PWAD_dir[]; +extern char PWAD_preload[]; + + +/* ------------------------------ Editor configuration +*/ +typedef enum hover { + HOVER_NONE, + HOVER_ADD, + HOVER_SINGLE + } Hover; + +typedef enum smovemode { + MOVE_ALL, + MOVE_RIGHT, + MOVE_LEFT + } SectorMoveMode; + +typedef enum newselect { + NEWSELECT_NEVER, + NEWSELECT_ASK, + NEWSELECT_SELECT + } NewSelect; + +typedef enum ldefmerge { + MERGE_ALWAYS, + MERGE_ASK, + MERGE_NEVER + } LinedefMerge; + +typedef enum defedit { + EDIT_SECTOR, + EDIT_VERTEX, + EDIT_LINEDEF, + EDIT_THING, + EDIT_MULTI + } DefaultEdit; + +extern int grid_onoff; +extern int grid_lock; +extern int grid_size; +extern double gfx_brighten; +extern int vertex_rad; +extern Hover hover_select; +extern int clear_on_move; +extern int clear_on_menu; +extern Hover insert_select; +extern SectorMoveMode sector_move; +extern int ask_middle_on_2sided; +extern int default_light_level; +extern int default_floor_height; +extern int default_ceiling_height; +extern NewSelect new_2sided_select; +extern LinedefMerge merge_linedef; +extern int auto_block_linedefs; +extern int default_scale; +extern DefaultEdit default_edit_mode; +extern int linedef_select; +extern int tag_highlight; +extern int show_full_linedef_info; + + +/* ------------------------------ viDOOM configuration +*/ +extern int sort_textures; +extern int sort_flats; +extern int show_titlepic; +extern int load_textures; +extern int load_flats; +extern int load_sprites; +extern int map_warn; +extern int map_exit_warn; +extern int initial_empty_map; +extern int overwrite_warning; + +/* ------------------------------ Required linedef flags bit and mask +*/ +extern int side2_bit; +extern int side2_mask; +extern int block_bit; +extern int block_mask; +extern int lower_peg_bit; +extern int lower_peg_mask; +extern int upper_peg_bit; +extern int upper_peg_mask; + + +/* ------------------------------ Normal values +*/ +extern int normal_linedef; +extern int normal_sector; + + +/* ------------------------------ LINEDEF checking +*/ +extern int check_line_assume_yes; +extern int check_1side_lower; +extern int check_1side_middle; +extern int check_1side_upper; +extern int check_2side_lower; +extern int check_2side_middle; +extern int check_2side_same_sector; +extern int check_2side_upper; + + +/* ------------------------------ Node Builder config +*/ +extern int use_build; +extern char build_cmd[]; +extern char build_ignore[]; +extern char build_in[]; +extern char build_out[]; +extern int build_in_before_out; +extern int build_always_view; + + +/* ------------------------------ Texture names +*/ +extern char empty_texture[]; +extern char linedef_check_default[]; + +/* ------------------------------ Interfaces +*/ + +/* Save and load global data to INI file +*/ +void LoadGlobalsPart1(void); +void LoadGlobalsPart2(void); + +void SaveGlobals(void); + +/* Read config file. This must be done once the default IWAD and any patch + PWADs have been read. +*/ +void LoadConfig(void); + + +#endif + + +/* END OF FILE */ @@ -0,0 +1,391 @@ +/* + + 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 GUI type routines + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> + +#include "gui.h" +#include "platgui.h" +#include "mem.h" +#include "ini.h" + +/* ---------------------------------------- VARS +*/ +#define GUI_INI "GUI" + +#define GUI_BORDER (fh/2) +#define GUI_BORDERFULL (GUI_BORDER*2) + +#define GUI_TITLEH (fh*2) +#define GUI_TITLEOFF (fh/2) +#define GUI_FOOTERH (fh*2) +#define GUI_FOOTEROFF (fh/2) + +#define GUI_BEVEL 2 + +#define MAXLINES 512 +#define MAXTEXT 4096 + +#define ANY_CLOSE "Press any key/mouse button to close" +#define ESC_CLOSE "Press ESC key to close" + +#define VIEW_LEN 70 + +int GUI_HI=GREY(210); +int GUI_MID=GREY(180); +int GUI_LO=GREY(140); +int GUI_TEXT=WHITE; +int GUI_TEXTSHADOW=BLACK; +int GUI_TEXTBOLD=BLACK; + +static INI_Table gui_ini[]= + { + {INI_INT,GUI_INI,"high",&GUI_HI,NULL}, + {INI_INT,GUI_INI,"mid",&GUI_MID,NULL}, + {INI_INT,GUI_INI,"low",&GUI_LO,NULL}, + {INI_INT,GUI_INI,"text",&GUI_TEXT,NULL}, + {INI_INT,GUI_INI,"shadow",&GUI_TEXTSHADOW,NULL}, + {INI_INT,GUI_INI,"bold",&GUI_TEXTBOLD,NULL} + }; + +static int SCRW; +static int SCRH; +static int fw; +static int fh; + +static char *doom_levels[]= + {"E1M1","E1M2","E1M3","E1M4","E1M5", + "E1M6","E1M7","E1M8","E1M9", + "E2M1","E2M2","E2M3","E2M4","E2M5", + "E2M6","E2M7","E2M8","E2M9", + "E3M1","E3M2","E3M3","E3M4","E3M5", + "E3M6","E3M7","E3M8","E3M9",NULL}; + +static char *ult_doom_levels[]= + {"E1M1","E1M2","E1M3","E1M4","E1M5", + "E1M6","E1M7","E1M8","E1M9", + "E2M1","E2M2","E2M3","E2M4","E2M5", + "E2M6","E2M7","E2M8","E2M9", + "E3M1","E3M2","E3M3","E3M4","E3M5", + "E3M6","E3M7","E3M8","E3M9", + "E4M1","E4M2","E4M3","E4M4","E4M5", + "E4M6","E4M7","E4M8","E4M9",NULL}; + +static char *doom2_levels[]= + {"MAP01","MAP02","MAP03","MAP04","MAP05", + "MAP06","MAP07","MAP08","MAP09","MAP10", + "MAP11","MAP12","MAP13","MAP14","MAP15", + "MAP16","MAP17","MAP18","MAP19","MAP20", + "MAP21","MAP22","MAP23","MAP24","MAP25", + "MAP26","MAP27","MAP28","MAP29","MAP30", + "MAP31","MAP32",NULL}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ + +static void CalcBounding(char *text,int *num,char *t[],int min_len, + int *x,int *y,int *w,int *h) +{ + int no; + int f; + char *p; + + no=0; + p=strtok(text,"|"); + + while(p) + { + t[no++]=p; + p=strtok(NULL,"|"); + } + + t[no]=NULL; + + *h=fh*no+GUI_BORDERFULL; + + for(f=0;f<no;f++) + if (strlen(t[f])>min_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<bevel;f++) + { + GFX_line(x+1+f,y+h-1-f,x+w-1-f,y+h-1-f,GUI_LO); + GFX_line(x+w-1-f,y+1+f,x+w-1-f,y+h-1-f,GUI_LO); + GFX_line(x+f,y+f,x+w-1-f,y+f,GUI_HI); + GFX_line(x+f,y+f,x+f,y+h-1-f,GUI_HI); + } +} + + +static void DrawTitle(int x,int y,int w,char *title) +{ + GFX_print((x+w/2)-(strlen(title)*fw)/2,y+GUI_TITLEOFF, + GUI_TEXTBOLD,"%s",title); + GFX_line(x+GUI_BEVEL,y+GUI_TITLEOFF+fh,x+w-GUI_BEVEL-1, + y+GUI_TITLEOFF+fh,GUI_HI); + GFX_line(x+GUI_BEVEL,y+GUI_TITLEOFF+fh+1,x+w-GUI_BEVEL-1, + y+GUI_TITLEOFF+fh+1,GUI_LO); +} + + +static void DrawText(int x,int y,char *p) +{ + /* + if ((STRNEQ("HTTP:",p))||(STRNEQ("FTP:",p))||(STRNEQ("MAILTO:",p))) + { + GFX_print(x+1,y+1,WHITE,"%s",p); + GFX_print(x,y,V_RGB(0x60,0x60,0xff),"%s",p); + } + else + */ + { + if (GUI_TEXTSHADOW!=GUI_TEXT) + GFX_print(x+1,y+1,GUI_TEXTSHADOW,"%s",p); + + GFX_print(x,y,GUI_TEXT,"%s",p); + } +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +void GuiSetScreen(int w,int h) +{ + INI_GetTable(gui_ini,INI_TAB_SIZE(gui_ini)); + + SCRW=w; + SCRH=h; + fw=GFX_fw(); + fh=GFX_fh()+2; +} + + +void GuiInfoBox(char *title,char *fmt,...) +{ + static char p[MAXTEXT]; + char *t[MAXLINES]; + int no,x,y,w,h; + int f; + GFXEvent ev; + va_list va; + + va_start(va,fmt); + vsprintf(p,fmt,va); + va_end(va); + + CalcBounding(p,&no,t,MAX(strlen(ANY_CLOSE),strlen(title)),&x,&y,&w,&h); + h+=GUI_TITLEH+GUI_FOOTERH; + + DrawBox(x,y,w,h,GUI_BEVEL); + + for(f=0;f<no;f++) + DrawText((SCRW-strlen(t[f])*fw)/2,y+GUI_BORDER+GUI_TITLEH+fh*f,t[f]); + + DrawTitle(x,y,w,title); + + GFX_print((SCRW-strlen(ANY_CLOSE)*fw)/2,y+h-GUI_FOOTERH+GUI_FOOTEROFF-1, + GUI_TEXTBOLD,"%s",ANY_CLOSE); + + GFX_redraw(); + GFX_bounce(); + GFX_await_input(&ev); + GFX_bounce(); +} + + +void GuiDrawInfoBox(char *title,int px,int py,int centre,char *fmt,...) +{ + static char p[MAXTEXT]; + char *t[MAXLINES]; + int no,x,y,w,h; + int f; + va_list va; + int cen; + + va_start(va,fmt); + vsprintf(p,fmt,va); + va_end(va); + + CalcBounding(p,&no,t,strlen(title),&x,&y,&w,&h); + h+=GUI_TITLEH; + + switch(px) + { + case GUI_CENTRE: + break; + case GUI_FLUSH_LEFT: + x=0; + break; + case GUI_FLUSH_RIGHT: + x=SCRW-w-1; + break; + default: + x=px; + break; + } + + switch(py) + { + case GUI_CENTRE: + break; + case GUI_FLUSH_TOP: + y=0; + break; + case GUI_FLUSH_LOWER: + y=SCRH-h-1; + break; + default: + y=py; + break; + } + + cen=(x+w/2); + + DrawBox(x,y,w,h,GUI_BEVEL); + + for(f=0;f<no;f++) + if (centre) + DrawText(cen-strlen(t[f])*(fw/2)+1, + y+GUI_BORDER+GUI_TITLEH+fh*f+1,t[f]); + else + DrawText(x+GUI_BEVEL+GUI_BORDER,y+GUI_BORDER+GUI_TITLEH+fh*f,t[f]); + + DrawTitle(x,y,w,title); +} + + +char *GuiPickLevel(char *prompt) +{ + int f; + static char s[256]; + + switch(level_style) + { + case DOOM_LEVELS: + f=GUI_picklist(prompt,doom_levels); + + if (f<0) + return(NULL); + + strcpy(s,doom_levels[f]); + break; + + case ULTIMATE_DOOM_LEVELS: + f=GUI_picklist(prompt,ult_doom_levels); + + if (f<0) + return(NULL); + + strcpy(s,ult_doom_levels[f]); + break; + + case DOOM_2_LEVELS: + f=GUI_picklist(prompt,doom2_levels); + + if (f<0) + return(NULL); + + strcpy(s,doom2_levels[f]); + break; + } + + return(s); +} + + +void ViewFile(char *title, char *file) +{ + FILE *fp; + int no; + char s[VIEW_LEN]; + char **line; + int f; + + if ((fp=fopen(file,"r"))) + { + no=0; + fgets(s,VIEW_LEN,fp); + + while(!feof(fp)) + { + no++; + fgets(s,VIEW_LEN,fp); + } + + no++; + + fclose(fp); + + line=Grab(sizeof(char *)*(no+1)); + + f=0; + fp=fopen(file,"r"); + + fgets(s,VIEW_LEN,fp); + + while(!feof(fp)) + { + line[f++]=Strdup(s); + fgets(s,VIEW_LEN,fp); + } + + line[f++]=Strdup("<END OF FILE>"); + line[f]=NULL; + + GUI_picklist(title,line); + + for(f=0;f<no;f++) + Release(line[f]); + + Release(line); + } + else + GuiInfoBox("ERROR","ViewFile couldn't open:%s",file); +} + + + +/* END OF FILE */ @@ -0,0 +1,88 @@ +/* + + 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 GUI routines + + $Id$ + +*/ + +#ifndef _GUI_H +#define _GUI_H + +#include "gfx.h" + + +/* If the platform specific GUI wants to provide a bas-relief GUI + in the same colours as the generic GUI it should use these colours. + + Note these values are not initialised until after GuiSetScreen() has been + called. +*/ +extern int GUI_HI; +extern int GUI_MID; +extern int GUI_LO; +extern int GUI_TEXT; +extern int GUI_TEXTSHADOW; +extern int GUI_TEXTBOLD; + + +/* These values can be passed to the InfoBox functions and the box will be + positioned accordingly. CENTRE can be used for both X and Y co-ords. +*/ +#define GUI_CENTRE -1000 +#define GUI_FLUSH_TOP -1002 +#define GUI_FLUSH_LEFT -1003 +#define GUI_FLUSH_RIGHT -1004 +#define GUI_FLUSH_LOWER -1005 + + +/* Inform GUI of screen size if required +*/ +void GuiSetScreen(int w,int h); + +/* Draw a box with filled with the supplied formatted text and wait for a + key/mouse button. Text is split into lines with a | char. +*/ +void GuiInfoBox(char *title, char *fmt,...); + +/* Draw a box identical to the Alert one, but don't wait for any input. Also + allows a position to be supplied for the top-left of the box. If any + position is -1 then the box is centred on that axis. If centre is set then + the text in the box is centred. +*/ +void GuiDrawInfoBox(char *title, int x, int y, int centre, char *fmt,...); + +/* Returns a string in the form MAPxx or ExMy, depending on the game type + defined in globals. Returns NULL if cancelled. + + Note the return is static and must be copied elsewhere if permanence is + required. +*/ +char *GuiPickLevel(char *prompt); + +/* View a text file +*/ +void ViewFile(char *title, char *file); + + +#endif @@ -0,0 +1,532 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Routines to read our version of an INI file + + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#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;f<l;f++) + if (!isspace(s[f])) + if (s[f]=='#') + return(GetLine(fp,len)); + else + return(s+f); + + return(GetLine(fp,len)); +} + + +static void AddToken(char *key, char *line) +{ + Token *tok; + Token *ins; + char *valkey,*val; + + valkey=strtok(line,"="); + val=strtok(NULL,"="); + + if (!val) + val=""; + + tok=Grab(sizeof(Token)); + + tok->key=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;f<no;f++) + if (FindToken(table[f].key,table[f].valkey)) + switch(table[f].type) + { + case INI_INT: + i=(int *)table[f].data; + *i=INI_ReadInt(table[f].key,table[f].valkey); + break; + + case INI_STR: + p=(char *)table[f].data; + strcpy(p,INI_ReadStr(table[f].key,table[f].valkey)); + break; + + case INI_TOK: + i=(int *)table[f].data; + *i=INI_ReadToken(table[f].key,table[f].valkey, + table[f].tokens); + break; + + case INI_DOUBLE: + d=(double *)table[f].data; + *d=INI_ReadDouble(table[f].key,table[f].valkey); + break; + } +} + +void INI_PutTable(INI_Table table[],int no) +{ + int f; + int i; + char *p; + double d; + + for(f=0;f<no;f++) + switch(table[f].type) + { + case INI_INT: + i=*((int *)table[f].data); + INI_SaveInt(table[f].key,table[f].valkey,i); + break; + + case INI_STR: + p=(char *)table[f].data; + INI_SaveStr(table[f].key,table[f].valkey,p); + break; + + case INI_TOK: + i=*((int *)table[f].data); + INI_SaveToken(table[f].key,table[f].valkey,i,table[f].tokens); + break; + + case INI_DOUBLE: + d=*((double *)table[f].data); + INI_SaveDouble(table[f].key,table[f].valkey,d); + break; + } +} + + +/* END OF FILE */ @@ -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 + + ------------------------------------------------------------------------- + + Routines and common keys used to read an INI file + Format of INI file: + + [key] + value_key=value + + $Id$ + +*/ + +#ifndef _INI_H + +#define _INI_H + + +/* Types for table filling queries +*/ +#define INI_INT 0 +#define INI_STR 1 +#define INI_TOK 2 +#define INI_DOUBLE 3 + + +/* Defines the possible values and the corresponding string token for the + value. +*/ +typedef struct + { + char *token; + int val; + } TokenTable; + +/* .data is treated as (int *) for INI_INT and INI_TOK. It is treated as + (char *) for INI_TOK and (double *) INI_DOUBLE. Tokens can be NULL for + non-INI_TOK types. +*/ +typedef struct + { + int type; + char *key; + char *valkey; + void *data; + TokenTable *tokens; + } INI_Table; + + +/* General yes/no token definitions +*/ +extern TokenTable ini_yesno[]; + +/* Macro for calculating table size +*/ +#define INI_TAB_SIZE(x) (sizeof(x)/sizeof(INI_Table)) + + +/* Note all returns are static +*/ +int INI_ReadInt(char *key,char *value_key); +char *INI_ReadStr(char *key,char *value_key); +int INI_ReadToken(char *key,char *value_key,TokenTable tokens[]); +double INI_ReadDouble(char *key,char *value_key); + +void INI_SaveInt(char *key,char *value_key,int val); +void INI_SaveStr(char *key,char *value_key,char *val); +void INI_SaveToken(char *key,char *value_key,int val,TokenTable tokens[]); +void INI_SaveDouble(char *key,char *value_key,double val); + +void INI_DeleteKey(char *key,char *value_key); + +void INI_Load(char *name); +void INI_Save(void); + +void INI_GetTable(INI_Table table[],int no); +void INI_PutTable(INI_Table table[],int no); + +/* This automatically takes iyase_dir from [config] and dir from [key]{iyase} + and adds on the passed filename. Note that return is static. +*/ +char *INI_FileName(char *key,char *fname); + +#endif + + +/* END OF FILE */ diff --git a/linedefs.c b/linedefs.c new file mode 100644 index 0000000..bfeb6bc --- /dev/null +++ b/linedefs.c @@ -0,0 +1,371 @@ +/* + + 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 + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "platgui.h" +#include "gfx.h" +#include "linedefs.h" +#include "mem.h" +#include "list.h" +#include "map.h" + + +/* ---------------------------------------- TYPES AND VARS +*/ +typedef struct + { + char *name; + } LineClass; + +typedef struct + { + int class; + int id; + char *name; + } LineInfo; + +typedef struct + { + char *name; + int id; + int two; + } LineDefault; + + +static int no_classes=0; + +static Map line_class=NULL; +static List line_list=NULL; +static Map line_def=NULL; + +static PLAT_PICKLIST **picklist=NULL; + +static PLAT_MENU *line_menu=NULL; + +static char *line_flags[17]= + {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + +static char line_flags_sh[16]= + {'?','?','?','?','?','?','?','?', + '?','?','?','?','?','?','?','?'}; + +static int line_flags_max=-1; + + +static char **line_def_plist=NULL; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static PLAT_PICKLIST *LinedefPicklist(int class) +{ + LineInfo *li; + Iterator i; + int no; + int f; + + if (picklist[class]) + return(picklist[class]); + else + { + no=0; + i=ListIterator(line_list); + + while(i) + { + li=IteratorData(i); + + if (li->class==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;f<MapSize(line_class);f++) + { + LineClass *c; + + c=MapElem(line_class,f); + + if (STREQ(c->name,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;f<no_classes;f++) + { + LineClass *c; + + c=MapElem(line_class,f); + line_menu[f].text=c->name; + line_menu[f].client_index=f; + } + + for(f=0;f<no_classes+1;f++) + picklist[f]=NULL; + + line_menu[no_classes].text=NULL; + } + + GFX_mouse(&x,&y); + + if (no_classes<2) + class=0; + else + class=GUI_menu("Pick class of LINEDEF",x,y,line_menu,LINEDEF_NULLID); + + if (class!=LINEDEF_NULLID) + class=GUI_client_picklist("LINEDEF",LinedefPicklist(class), + LINEDEF_NULLID); + + return(class); +} + + +char *LinedefName(int id) +{ + LineInfo *li; + Iterator i; + + i=ListIterator(line_list); + + while(i) + { + li=IteratorData(i); + + if (li->id==id) + { + IteratorClear(i); + return(li->name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +char *LinedefClass(int id) +{ + LineInfo *li; + LineClass *lc; + Iterator i; + + if (no_classes==0) + return("NO CLASSES!"); + + i=ListIterator(line_list); + + while(i) + { + li=IteratorData(i); + + if (li->id==id) + { + IteratorClear(i); + lc=MapElem(line_class,li->class); + return(lc->name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +void LinedefFlag(int bit,char *s,char sh) +{ + line_flags[bit]=Strdup(s); + line_flags_sh[bit]=sh; + + if (bit>line_flags_max) + line_flags_max=bit; +} + + +char **LinedefFlagArray(void) +{ + return(line_flags); +} + + +char *LinedefFlagText(int flags) +{ + static char s[32]; + int b; + char *p; + + s[0]=0; + p=s; + + for(b=line_flags_max;b>=0;b--) + { + if (flags&(1<<b)) + *p++=line_flags_sh[b]; + else + *p++='-'; + + *p=0; + } + + return(s); +} + + +void AddLinedefType(char *name,int flags,int two_sided) +{ + LineDefault l; + + if (!line_def) + line_def=MapNew(sizeof(LineDefault)); + + l.name=Grab(strlen(name)+20); + strcpy(l.name,name); + strcat(l.name," ["); + strcat(l.name,LinedefFlagText(flags)); + strcat(l.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;f<MapSize(line_def);f++) + { + l=MapElem(line_def,f); + line_def_plist[f]=l->name; + } + + line_def_plist[MapSize(line_def)]=NULL; + } + + f=GUI_picklist("LINEDEF TYPE",line_def_plist); + + if (f!=-1) + { + l=MapElem(line_def,f); + *flag=l->id; + *two=l->two; + return(TRUE); + } + else + return(FALSE); +} + + +/* END OF FILE */ diff --git a/linedefs.h b/linedefs.h new file mode 100644 index 0000000..9a0b044 --- /dev/null +++ b/linedefs.h @@ -0,0 +1,100 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Handles definition and storage of the supported LINEDEFs + + $Id$ + +*/ + +#ifndef _LINEDEFS_H + +#define _LINEDEFS_H + +#include "wad.h" +#include "gfx.h" +#include "platgui.h" + + +/* This is not going to be an ID, so is used to detect whether LinedefSelect() + was cancelled. +*/ +#define LINEDEF_NULLID -666 + + +/* Add a new class of linedef +*/ +void LinedefNewClass(char *class); + + +/* Add the named type to the supplied class with the ID +*/ +void LinedefAdd(char *class,char *name,int id); + + +/* Selects a type of linedef, returning the ID or LINEDEF_NULLID if cancelled +*/ +int SelectLinedef(void); + + +/* Returns the name of a linedef type +*/ +char *LinedefName(int id); + + +/* Returns the class of a linedef type +*/ +char *LinedefClass(int id); + + +/* Set the meaning of one of the bits in the options field for a linedef +*/ +void LinedefFlag(int bit,char *name,char shorthand); + + +/* Returns a GUI_multi_box() compatible text array for manipulating a LINEDEFs + flags. +*/ +char **LinedefFlagArray(void); + + +/* Return a static string representing the meaning of the passed in flags +*/ +char *LinedefFlagText(int flag); + + +/* Define a default linedef flags values +*/ +void AddLinedefType(char *name,int flags,int two_sided); + + +/* Return a default linedef flag value into flags after showing a picklist to + choose them from, and two is TRUE if the linedef is 2-sided. Returns TRUE + for accepted, FALSE cancelled. +*/ +int ChooseLinedefType(int *flags,int *two); + + +#endif + + +/* END OF FILE */ @@ -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 <string.h> +#include <stdio.h> + +#include "list.h" +#include "mem.h" + +struct _Elem + { + char *data; + struct _Elem *next; + struct _Elem *prev; + }; + +struct _List + { + int no; + int size; + struct _Elem *head; + struct _Elem *tail; + }; + +struct _Iterator + { + List l; + struct _Elem *e; + }; + +/* ---------------------------------------- +*/ +List ListNew(int type_size) +{ + List nl; + + nl=Grab(sizeof(struct _List)); + + nl->no=0; + nl->size=type_size; + nl->head=NULL; + nl->tail=NULL; + + return(nl); +} + +List ListClear(List l) +{ + struct _Elem *e,*d; + + if (l) + { + e=l->head; + + while(e) + { + d=e; + e=e->next; + Release(d->data); + Release(d); + } + + Release(l); + } + + return(NULL); +} + +List ListEmpty(List l) +{ + struct _Elem *e,*d; + + if (l) + { + e=l->head; + + while(e) + { + d=e; + e=e->next; + Release(d->data); + Release(d); + } + + l->no=0; + l->head=NULL; + l->tail=NULL; + } + + return(l); +} + +int ListSize(List l) +{ + if (l) + return(l->no); + else + return(0); +} + +Iterator ListIterator(List l) +{ + struct _Iterator *i; + + if (!l->head) + return(NULL); + + i=Grab(sizeof(struct _Iterator)); + i->l=l; + i->e=l->head; + + return(i); +} + +Iterator IteratorClear(Iterator i) +{ + if (i) + Release(i); + + return(NULL); +} + +void *IteratorData(Iterator i) +{ + if (i) + return(i->e->data); + else + return(NULL); +} + +Iterator IteratorNext(Iterator i) +{ + if (i) + if (!(i->e=i->e->next)) + { + Release(i); + i=NULL; + } + + return(i); +} + +Iterator IteratorPrev(Iterator i) +{ + if (i) + if (!(i->e=i->e->prev)) + { + Release(i); + i=NULL; + } + + return(i); +} + +Iterator IteratorUpdate(Iterator i,void *data) +{ + if (i) + { + Release(i->e->data); + i->e->data=Copy(data,i->l->size); + } + return(i); +} + +Iterator IteratorDelete(Iterator i) +{ + struct _Elem *e; + + e=i->e; + i->e=i->e->next; + + i->l->no--; + + if (e==i->l->head) + i->l->head=e->next; + + if (e==i->l->tail) + i->l->tail=e->prev; + + if (e->next) + e->next->prev=e->prev; + + if (e->prev) + e->prev->next=e->next; + + Release(e->data); + Release(e); + + if (!(i->e)) + { + Release(i); + i=NULL; + } + + return(i); +} + +void ListAppend(List l,void *data) +{ + struct _Elem *e; + + e=Grab(sizeof(struct _Elem)); + + e->next=NULL; + e->prev=l->tail; + e->data=Copy(data,l->size); + l->no++; + + if (l->head) + { + l->tail->next=e; + l->tail=e; + } + else + l->head=l->tail=e; +} + +void ListInsert(List l,void *data) +{ + struct _Elem *e; + + e=Grab(sizeof(struct _Elem)); + + e->prev=NULL; + e->next=l->head; + e->data=Copy(data,l->size); + l->no++; + + if (l->head) + { + l->head->prev=e; + l->head=e; + } + else + l->head=l->tail=e; +} + +Iterator ListFindElem(List l,int (*pred)(void *, void *),void *data) +{ + Iterator i; + struct _Elem *e; + + i=NULL; + + e=l->head; + + while((e)&&(!i)) + { + if ((*pred)(e->data,data)) + { + i=ListIterator(l); + i->e=e; + } + + e=e->next; + } + + return(i); +} + + +/* END OF FILE */ @@ -0,0 +1,104 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides a double-linked list + + $Id$ + +*/ + +#ifndef _LIST_H + +#define _LIST_H + +/* Opaque types for the list and iterator. NULL is the null list and iterator. +*/ +struct _List; +typedef struct _List *List; + +struct _Iterator; +typedef struct _Iterator *Iterator; + + +/* Create a list +*/ +List ListNew(int type_size); + +/* Free a list object +*/ +List ListClear(List l); + +/* Free all elements in a list +*/ +List ListEmpty(List l); + +/* Return number of elements in list +*/ +int ListSize(List l); + +/* Create an iterator over the list +*/ +Iterator ListIterator(List l); + +/* Destory an iterator +*/ +Iterator IteratorClear(Iterator i); + +/* Get data for pointed to by this iterator object +*/ +void *IteratorData(Iterator i); + +/* Move the iterator to the next element. NULL once done. +*/ +Iterator IteratorNext(Iterator i); + +/* Move the iterator to the previous element. NULL once done. +*/ +Iterator IteratorPrev(Iterator i); + +/* Replace the data currently stored in this this position with the new one +*/ +Iterator IteratorUpdate(Iterator i,void *data); + +/* Delete the data currently stored in this position and move the iterator to + the next element. +*/ +Iterator IteratorDelete(Iterator i); + +/* Append to the tail of the the list +*/ +void ListAppend(List l,void *data); + +/* Insert at the head of the the list +*/ +void ListInsert(List l,void *data); + +/* Return an iterator for the searched element. Note the fist void* passed + to the predicate will be of the type stored in the lists. The second + argument will be whatever was passed as data. +*/ +Iterator ListFindElem(List l,int (*pred)(void *, void *),void *data); + +#endif + + +/* END OF FILE */ diff --git a/make/djgpp.cfg b/make/djgpp.cfg new file mode 100644 index 0000000..e682b61 --- /dev/null +++ b/make/djgpp.cfg @@ -0,0 +1,41 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# +# Makefile config for DJGPP +# +# $Id: djgpp.cfg,v 1.6 2000/07/28 12:18:35 dosuser Exp dosuser $ +# +CC= gcc +LD= gcc +PLATFORM= djgpp +EXE_EXT= .exe +OBJ_EXT= .o +LIBS= -lalleg +EXTRACF= -g -O -Wall +EXTRALF= +DIRSEP= "/" +MATHLIB= -lm +TRACEFORM= "%s(%d):%s\n",__FILE__,__LINE__,__FUNCTION__ +EXEFLAG= -o +OBJFLAG= -c +DEFINEFLAG= -D +INCFLAG= -I +MAKEINSTALL= make INSTALLDIR='$(INSTALLDIR)' -f install + diff --git a/makefile b/makefile new file mode 100644 index 0000000..00961e2 --- /dev/null +++ b/makefile @@ -0,0 +1,259 @@ +# viDOOM - level editor for DOOM +# +# Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# ------------------------------------------------------------------------- +# + +# +# START OF CONFIGURATION PART +# +# 1. The platform to compile for. Currently supported ones are: +# djgpp +# +MAKEPLAT=djgpp + + +# 2. Set to the directory where you want to install viDOOM. Note this is not +# used in the default make - a 'make install' must be issued to activate +# this. +# +INSTALLDIR=C:/viDOOM + + +# 3. The directory seperator for this machine. This is unquoted (unlike the +# seperator in the config file) as this is for the makefiles own use. +# +MKDS=/ + + +# +# END OF CONFIGURATION PART +# + + + +# Shouldn't be any need to edit past here +# +include make$(MKDS)$(MAKEPLAT).cfg + + +# Uncomment to build debug version +# +# DEBUG=$(DEFINEFLAG)DEBUG + + +CFLAGS= $(EXTRACF) $(DEFINEFLAG)TRACEFORM='$(TRACEFORM)' $(DEBUG) \ + $(DEFINEFLAG)PLATFORM=$(PLATFORM) \ + $(DEFINEFLAG)DIRSEP='$(DIRSEP)' $(INCFLAG). + +VIDOOM= vidoom +WADDIR= waddir +GFXTEST= gfxtest + +COMMON_OBJ= $(PLATFORM)$(MKDS)main$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)file$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)gfx$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)mem$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)platgui$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)runcmd$(OBJ_EXT) \ + $(PLATFORM)$(MKDS)vstring$(OBJ_EXT) \ + ini$(OBJ_EXT) wad$(OBJ_EXT) 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) + +ALL_HEADERS= vidoom.h config.h file.h gfx.h mem.h map.h runcmd.h \ + ini.h wad.h list.h edit.h platgui.h gui.h debug.h globals.h \ + texture.h things.h linedefs.h editvar.h + +VIDOOM_OBJ= vidoom$(OBJ_EXT) $(COMMON_OBJ) +WADDIR_OBJ= waddir$(OBJ_EXT) $(COMMON_OBJ) +GFXTEST_OBJ= gfxtest$(OBJ_EXT) $(COMMON_OBJ) + + + +$(VIDOOM)$(EXE_EXT):$(VIDOOM_OBJ) + $(LD) $(EXTRALF) $(EXEFLAG) $(VIDOOM)$(EXE_EXT) \ + $(VIDOOM_OBJ) $(LIBS) $(MATHLIB) + +$(WADDIR)$(EXE_EXT):$(WADDIR_OBJ) + $(LD) $(EXTRALF) $(EXEFLAG) $(WADDIR)$(EXE_EXT) \ + $(WADDIR_OBJ) $(LIBS) $(MATHLIB) + +$(GFXTEST)$(EXE_EXT):$(GFXTEST_OBJ) + $(LD) $(EXTRALF) $(EXEFLAG) $(GFXTEST)$(EXE_EXT) $(GFXTEST_OBJ) \ + $(LIBS) $(MATHLIB) + +all: $(VIDOOM)$(EXE_EXT) $(WADDIR)$(EXE_EXT) $(GFXTEST)$(EXE_EXT) + + +$(PLATFORM)$(MKDS)main$(OBJ_EXT): $(PLATFORM)$(MKDS)main.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. main.c ; cd .. + +$(PLATFORM)$(MKDS)file$(OBJ_EXT): $(PLATFORM)$(MKDS)file.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. file.c ; cd .. + +$(PLATFORM)$(MKDS)gfx$(OBJ_EXT): $(PLATFORM)$(MKDS)gfx.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. gfx.c ; cd .. + +$(PLATFORM)$(MKDS)mem$(OBJ_EXT): $(PLATFORM)$(MKDS)mem.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. mem.c ; cd .. + +$(PLATFORM)$(MKDS)platgui$(OBJ_EXT): $(PLATFORM)$(MKDS)platgui.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. platgui.c ; cd .. + +$(PLATFORM)$(MKDS)runcmd$(OBJ_EXT): $(PLATFORM)$(MKDS)runcmd.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. runcmd.c ; cd .. + +$(PLATFORM)$(MKDS)vstring$(OBJ_EXT): $(PLATFORM)$(MKDS)vstring.c $(ALL_HEADERS) + cd $(PLATFORM); $(CC) $(CFLAGS) $(OBJFLAG) $(INCFLAG).. vstring.c ; cd .. + + +debug$(OBJ_EXT): debug.c config.h debug.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +edit$(OBJ_EXT): edit.c config.h globals.h edit.h wad.h map.h list.h editvar.h \ + things.h gfx.h platgui.h linedefs.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editcord$(OBJ_EXT): editcord.c config.h globals.h texture.h gfx.h platgui.h \ + editvar.h things.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editdraw$(OBJ_EXT): editdraw.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editevnt$(OBJ_EXT): editevnt.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editgui$(OBJ_EXT): editgui.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h texture.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editline$(OBJ_EXT): editline.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editsect$(OBJ_EXT): editsect.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editsel$(OBJ_EXT): editsel.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editsrot$(OBJ_EXT): editsrot.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editcrse$(OBJ_EXT): editcrse.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editthng$(OBJ_EXT): editthng.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editvar$(OBJ_EXT): editvar.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editvert$(OBJ_EXT): editvert.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editmrg$(OBJ_EXT): editmrg.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editmult$(OBJ_EXT): editmult.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +editilst$(OBJ_EXT): editilst.c config.h globals.h editvar.h things.h gfx.h \ + platgui.h linedefs.h wad.h map.h list.h gui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +gfxtest$(OBJ_EXT): gfxtest.c config.h globals.h gfx.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +globals$(OBJ_EXT): globals.c config.h globals.h ini.h gfx.h texture.h \ + platgui.h things.h linedefs.h sectors.h wad.h map.h list.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +gui$(OBJ_EXT): gui.c config.h globals.h gui.h gfx.h platgui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +ini$(OBJ_EXT): ini.c config.h ini.h mem.h file.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +linedefs$(OBJ_EXT): linedefs.c config.h globals.h linedefs.h wad.h map.h \ + list.h gfx.h platgui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +sectors$(OBJ_EXT): sectors.c config.h globals.h sectors.h wad.h map.h list.h \ + gfx.h platgui.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +list$(OBJ_EXT): list.c config.h list.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +map$(OBJ_EXT): map.c config.h map.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +texture$(OBJ_EXT): texture.c config.h globals.h texture.h gfx.h platgui.h \ + wad.h map.h list.h mem.h gui.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +things$(OBJ_EXT): things.c config.h globals.h things.h gfx.h platgui.h mem.h \ + list.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +wad$(OBJ_EXT): wad.c config.h globals.h wad.h map.h list.h gfx.h mem.h + $(CC) $(CFLAGS) $(OBJFLAG) $< + +util$(OBJ_EXT): util.c config.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 + + +# Rule for installation +# +install: $(VIDOOM)$(EXE_EXT) FORCE + cd $(PLATFORM) ; $(MAKEINSTALL) + +FORCE: + + +# +# $Id: makefile,v 1.30 2000/08/13 17:22:44 dosuser Exp dosuser $ +# +# END OF FILE @@ -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 <string.h> + +#include "map.h" +#include "mem.h" + +#define MAPCHUNK 100 + +struct _Map + { + int top; + int alloc; + int size; + char *data; + }; + +/* ---------------------------------------- +*/ +Map MapNew(int type_size) +{ + Map nm; + + nm=Grab(sizeof(struct _Map)); + + nm->top=-1; + nm->size=type_size; + nm->alloc=0; + nm->data=NULL; + + return(nm); +} + +Map MapCopy(Map m) +{ + Map nm; + + nm=NULL; + + if (m) + { + nm=Copy(m,sizeof(struct _Map)); + nm->data=Copy(m->data,m->alloc*m->size); + } + + return(nm); +} + +Map MapClear(Map m) +{ + if (m) + { + if (m->data) + Release(m->data); + Release(m); + } + + return(NULL); +} + +Map MapEmpty(Map m) +{ + if (m) + { + if (m->data) + Release(m->data); + + m->top=-1; + m->alloc=0; + m->data=NULL; + } + + return(m); +} + +int MapSize(Map m) +{ + if (m) + return(m->top+1); + else + return(0); +} + +void *MapElem(Map m,int no) +{ + if ((no<0)||(no>m->top)) + return(NULL); + else + return(m->data+(no*m->size)); +} + +void MapAdd(Map m,int no,void *data) +{ + if (no==-1) + no=m->top+1; + + if (m->alloc<no+1) + { + m->alloc=(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->top<no) + m->top=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 */ @@ -0,0 +1,86 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides a dynamic sort-of-array type + + $Id$ + +*/ + +#ifndef _MAP_H + +#define _MAP_H + +/* Opaque types for the map. NULL is the null map. +*/ +struct _Map; +typedef struct _Map *Map; + +/* Create a new Map that handles objects of type_size +*/ +Map MapNew(int type_size); + + +/* Copy a Map +*/ +Map MapCopy(Map m); + + +/* Destroy a Map object +*/ +Map MapClear(Map m); + + +/* Destroy all elements in a Map +*/ +Map MapEmpty(Map m); + + +/* Return number of elements in the Map +*/ +int MapSize(Map m); + + +/* Get the element from index no +*/ +void *MapElem(Map m,int no); + + +/* Add an element at position no. no==-1 positions the element at the end +*/ +void MapAdd(Map m,int no,void *data); + + +/* Find and element, searching using the passed predicate function. Function + should return TRUE for found, FALSE for not found. + + Note the fist void* passed to the predicate will be of the type stored in + the Map. The second argument will be whatever was passed as data. + + Returns NULL if the entry cannot be found. +*/ +void *MapFindElem(Map m,int (*pred)(void *, void *),void *data); + +#endif + + +/* END OF FILE */ @@ -0,0 +1,79 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Memory allocation + + $Id$ + +*/ + +#ifndef _MEM_H + +#define _MEM_H + +/* Notes: All these functions take debug information. The versions actually + used in the code are the #define's following the prototypes +*/ + + +/* Grab len bytes of memory. len==0 is valid. Memory is zereod on allocation. +*/ +void *FGrab(char *file, int line, int len); + + +/* Given a pointer returned by Grab() and a new size reallocates it to a + larger or smaller block. The orignal contents are copied to the new + block. Passing an NULL for ptr makes this call the same as FGrab(len). +*/ +void *FReGrab(char *file, int line, void *ptr, int len); + + +/* Reserve len bytes and copy len bytes from p to the new memory. len==0 is + valid +*/ +void *FCopy(char *file, int line, void *p,int len); + + +/* Reserve space for the nul terminated string and copy the source there. + Return is NULL if source is NULL +*/ +char *FStrdup(char *file, int line, char *s); + + +/* Release allocated memory +*/ +void FRelease(char *file, int line, void *p); + + + +/* Actually use these +*/ +#define Grab(n) FGrab(__FILE__,__LINE__,(n)) +#define ReGrab(p,n) FReGrab(__FILE__,__LINE__,(p),(n)) +#define Copy(p,n) FCopy(__FILE__,__LINE__,(p),(n)) +#define Strdup(p) FStrdup(__FILE__,__LINE__,(p)) +#define Release(p) FRelease(__FILE__,__LINE__,(p)) + +#endif + + +/* END OF FILE */ diff --git a/platgui.h b/platgui.h new file mode 100644 index 0000000..0719ef0 --- /dev/null +++ b/platgui.h @@ -0,0 +1,199 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Platform specific GUI routines + + This is the platform specific routines for pop-up menus, dialogs and + file selectors. More DOOM graphics orientied GUI is handled by the + generic GUI (gui.h) that is built on top of gfx. + + As with the platform specific GFX all calls can be differentiated from + the generic gui by starting with GUI_, rather than Gui. + + Note that all these routines are expected to preserve screen contents. + + $Id$ + +*/ + +#ifndef _PLATGUI_H +#define _PLATGUI_H + +#include "gfx.h" + +/* Type for a picklist, where each entry has an associated grahpic. If the + image is NULL then no picture should be shown for that entry. +*/ +typedef struct + { + char *text; + GFX_IMAGE img; + int client_index; /* Returned by GUI_image_picklist() */ + } PLAT_IMG_PICKLIST; + + +/* Type for a picklist +*/ +typedef struct + { + char *text; + int client_index; /* Returned by GUI_client_picklist() */ + } PLAT_PICKLIST; + + +/* Types to define a menu +*/ +typedef struct + { + char *text; /* Text to display */ + int client_index; /* Value returned by GUI_menu() */ + } PLAT_MENU; + + +/* Types to define a radio box +*/ +typedef struct + { + char *text; /* Label for this button. NULL==end */ + int client_index; /* Value returned by GUI_radio() */ + } PLAT_RADIO; + +/* Types to define a simple dialog +*/ +#define PLAT_DIAL_MAXSTRLEN 128 + +#define PLAT_DIAL_STRING 0 +#define PLAT_DIAL_INTEGER 1 +#define PLAT_DIAL_DOUBLE 2 + +typedef struct + { + char *text; /* Label for item. NULL==no label */ + int type; /* Data type (PLAT_DIAL_xxx) */ + union /* Data */ + { + int i; + char s[PLAT_DIAL_MAXSTRLEN+1]; + double d; + } data; + } PLAT_DIALOG; + + +/* Inform GUI of screen size if required +*/ +void GUI_setscreen(int w,int h); + +/* Display a Yes/No option box. Returns TRUE/FALSE accordingly. +*/ +int GUI_yesno(char *question); + + +/* Pop-up/display a menu. Return the client_index of the selected item from the + menus, or defval for no selection. The co-ords can obviously be ignored or + honoured, though honouring is preferable. + + MENU array is terminated by one with a NULL text entry. +*/ +int GUI_menu(char *title, int x, int y, PLAT_MENU menu[], int defval); + + +/* Allow selection of a filename. Returns NULL if cancelled, otherwise the + selected path with must be Releas()'ed later. + + If supported then files ending with filter should only be displayed. Filter + should be NULL to show all files. +*/ +char *GUI_fsel(char *title, char *default_path, char *filter); + + +/* Display a picklist. The items are described by the array of pointers + passed in, which terminates with a NULL pointer. The index to the selected + item is returned, or -1 if the pickbox was cancelled. +*/ +int GUI_picklist(char *title,char *opts[]); + + +/* Does a picklist as above, but works on structures cntaining client return + values, rather than simple array indexes. +*/ +int GUI_client_picklist(char *title,PLAT_PICKLIST opts[],int defval); + + +/* Display a picklist with associated images. The items are described by the + array of structs passed in, which terminates with a NULL pointer in the + text field. The client index data in the selected item is returned, or + defval if the pickbox was cancelled. + + If this cannot be supported on the platform then the minimum this should + do is a sideways call to GUI_client_picklist() +*/ +int GUI_image_picklist(char *title,PLAT_IMG_PICKLIST opts[],int defval); + + +/* Display a radio box. The items are described by the array of structs + passed in, which terminates with a NULL pointer in the text field. + The client index data in the selected item is returned, or defval if the + radio box was cancelled. + + If one of the entries client index values is the same as current then that + option will be the one selected when the radio box is displayed. Otherwise + the first item will be the selected one. +*/ +int GUI_radio_box(char *title,PLAT_RADIO opts[],int current,int defval); + +/* Display a mutli-selection radio box. The items are described by the array + of char pointers passed in, which terminates with a NULL pointer. + + The passed in integer pointer points to a value which is used to enable/ + disable the options dependent on the integers bit setting. The integer + pointed to is updated on exit of the multi-selection box is not cancelled. + + Note that the bit patterns are matched bit number to opt index. ie. + val & 0x0001 corresponds to opts[0] + val & 0x0002 corresponds to opts[1] + .... + val & 0x0010 corresponds to opts[4] + .... + val & 0x0100 corresponds to opts[8] + .... + val & 0x8000 corresponds to opts[15] + + A maximum of 16 bits should be all that needs supporting currently. + + Returns TRUE if dialog accepted, otherwise FALSE. +*/ +int GUI_multi_box(char *title,char *opts[],int *val); + + +/* Displays a very simple dialog made up of 'no' fields as defined in pd[]. + Returns TRUE if the dialog is accepted, FALSE otherwise. + + Note that as the values in the PLAT_DIALOG array are not pointing to + actual client data they need not be preserved on a cancel of the dialog. +*/ +int GUI_dialog(char *title, int no, PLAT_DIALOG pd[]); + + +#endif + + +/* END OF FILE */ diff --git a/runcmd.h b/runcmd.h new file mode 100644 index 0000000..e1ba406 --- /dev/null +++ b/runcmd.h @@ -0,0 +1,57 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Command execution interface + + $Id$ + + +*/ + +#ifndef _RUNCMD_H + +#define _RUNCMD_H + +/* Run a command. Te output from the command (if any) should NOT disturb the + screen contents. The call should return TRUE if the call succeeds, FALSE + otherwise. + + The argv list is an array of pointers to various sections of the command + and it's arguemnts, terminated with a NULL pointer. + + Note that arguments may contain more than one argument in each line, ie. + the actual command is described simply by concatanating all the + pointers together, eg. + argv[0]="bsp.exe" + argv[1]="x.wad" + argv[2]="-o x.wad" + argv[3]=NULL + + The path argument is a place to copy a file where the output from the + comand has been stored. If this is not supported then the empty string + should be assigned to it. viDOOM will remove() the file after it has + read it. +*/ +int RunCommand(char *argv[],char *path); + + +#endif diff --git a/sectors.c b/sectors.c new file mode 100644 index 0000000..0c6ce40 --- /dev/null +++ b/sectors.c @@ -0,0 +1,318 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Handles definition and storage of the supported SECTORS + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "sectors.h" +#include "mem.h" +#include "list.h" +#include "map.h" + + +/* ---------------------------------------- TYPES AND VARS +*/ +typedef struct + { + char *name; + } + SectorClass; + +typedef struct + { + int class; + int id; + char *long_name; + char *short_name; + } SectorInfo; + +typedef struct + { + int flags; + char *name; + DirName upper; + DirName middle; + DirName lower; + DirName floor; + DirName ceiling; + } SectorStyle; + +static int no_classes=0; + +static Map sect_class=NULL; +static List sect_list=NULL; +static Map sect_style=NULL; + +static PLAT_MENU *menu=NULL; +static PLAT_PICKLIST **picklist=NULL; + +static char **sect_style_plist=NULL; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static PLAT_PICKLIST *SectorPicklist(int class) +{ + SectorInfo *si; + Iterator i; + int no; + int f; + + if (picklist[class]) + return(picklist[class]); + + no=0; + i=ListIterator(sect_list); + + while(i) + { + si=IteratorData(i); + + if (si->class==class) + no++; + + i=IteratorNext(i); + } + + picklist[class]=Grab(sizeof(PLAT_PICKLIST)*(no+1)); + + i=ListIterator(sect_list); + + f=0; + while(i) + { + si=IteratorData(i); + + if (si->class==class) + { + picklist[class][f].text=si->long_name; + picklist[class][f].client_index=si->id; + f++; + } + + i=IteratorNext(i); + } + + picklist[class][f].text=NULL; + + return(picklist[class]); +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void SectorNewClass(char *class) +{ + SectorClass c; + + if (!sect_class) + sect_class=MapNew(sizeof(SectorClass)); + + c.name=Strdup(class); + + MapAdd(sect_class,no_classes++,&c); +} + + +void SectorAdd(char *class,int id,char *long_name,char *short_name) +{ + SectorInfo *s; + int i_class; + int f; + + if (!sect_list) + sect_list=ListNew(sizeof(SectorInfo)); + + s=Grab(sizeof(SectorInfo)); + + i_class=-1; + + for(f=0;f<MapSize(sect_class);f++) + { + SectorClass *c; + + c=MapElem(sect_class,f); + + if (STREQ(c->name,class)) + i_class=f; + } + + if (i_class==-1) + i_class=0; + + s->class=i_class; + s->id=id; + s->long_name=Strdup(long_name); + s->short_name=Strdup(short_name); + ListAppend(sect_list,s); +} + + +int SelectSector(void) +{ + int class; + int f; + int x,y; + + if (!menu) + { + menu=Grab(sizeof(PLAT_MENU)*(no_classes+1)); + picklist=Grab(sizeof(PLAT_IMG_PICKLIST *)*(no_classes+1)); + + for(f=0;f<no_classes;f++) + { + SectorClass *c; + + c=MapElem(sect_class,f); + menu[f].text=c->name; + menu[f].client_index=f; + } + + for(f=0;f<no_classes+1;f++) + picklist[f]=NULL; + + menu[no_classes].text=NULL; + } + + GFX_mouse(&x,&y); + + if (no_classes<2) + class=0; + else + class=GUI_menu("Pick class of SECTOR",x,y,menu,SECTOR_NULLID); + + if (class!=SECTOR_NULLID) + class=GUI_client_picklist("SECTOR",SectorPicklist(class),SECTOR_NULLID); + + return(class); +} + + +char *SectorName(int id) +{ + SectorInfo *si; + Iterator i; + + i=ListIterator(sect_list); + + while(i) + { + si=IteratorData(i); + + if (si->id==id) + { + IteratorClear(i); + return(si->short_name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +void StartSectorStyles(void) +{ + SectorStyle *s; + int f; + + if (!sect_style) + { + for(f=0;f<MapSize(sect_style);f++) + { + s=MapElem(sect_style,f); + Release(s->name); + } + + sect_style=MapNew(sizeof(SectorStyle)); + } + else + MapEmpty(sect_style); +} + + +void AddSectorStyle(char *name, int flags, DirName upper, DirName middle, + DirName lower, DirName floor, DirName ceiling) +{ + SectorStyle s; + + s.flags=flags; + s.name=Strdup(name); + strcpy(s.upper,upper); + strcpy(s.middle,middle); + strcpy(s.lower,lower); + strcpy(s.floor,floor); + strcpy(s.ceiling,ceiling); + + MapAdd(sect_style,-1,&s); +} + + +int ChooseSectorStyle(int *flags, DirName upper,DirName middle,DirName lower, + DirName floor,DirName ceiling) +{ + SectorStyle *s; + int f; + + if (!sect_style_plist) + { + sect_style_plist=Grab(sizeof(char *)*(MapSize(sect_style)+1)); + + for(f=0;f<MapSize(sect_style);f++) + { + s=MapElem(sect_style,f); + sect_style_plist[f]=s->name; + } + + sect_style_plist[MapSize(sect_style)]=NULL; + } + + f=GUI_picklist("SECTOR STYLE",sect_style_plist); + + if (f!=-1) + { + s=MapElem(sect_style,f); + *flags=s->flags; + strcpy(lower,s->lower); + strcpy(middle,s->middle); + strcpy(upper,s->upper); + strcpy(floor,s->floor); + strcpy(ceiling,s->ceiling); + return(TRUE); + } + else + return(FALSE); +} + +int NoSectorStyles(void) +{ + return(MapSize(sect_style)); +} + + +/* END OF FILE */ diff --git a/sectors.h b/sectors.h new file mode 100644 index 0000000..b59ec63 --- /dev/null +++ b/sectors.h @@ -0,0 +1,96 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Handles definition and storage of the supported SECTORs + + $Id$ + +*/ + +#ifndef _SECTORS_H + +#define _SECTORS_H + +#include "wad.h" +#include "gfx.h" +#include "platgui.h" + +/* This is not going to be an ID, so is returned from SelectSector() if it is + cancelled. +*/ +#define SECTOR_NULLID -666 + + +/* Meanings for the flags in the sector styles +*/ +#define SSTYLE_FACING_IN 0x01 +#define SSTYLE_FACING_OUT 0x02 +#define SSTYLE_LEAVE_PEG 0x04 +#define SSTYLE_UPPER_PEG 0x08 +#define SSTYLE_LOWER_PEG 0x10 + + +/* Add a new class of sector +*/ +void SectorNewClass(char *class); + + +/* Add the named type to the supplied class with the ID +*/ +void SectorAdd(char *class,int id,char *long_name, char *short_name); + + +/* Select the ID type for a sector. Returns SECTOR_NULLID if cancelled +*/ +int SelectSector(void); + + +/* Returns the short name of a sector type +*/ +char *SectorName(int id); + + +/* Start defining sector styles. +*/ +void StartSectorStyles(void); + +/* Define a linedef style +*/ +void AddSectorStyle(char *name, int flags, + DirName upper,DirName middle,DirName lower, + DirName floor,DirName ceiling); + +/* Return the number of defined sector styles +*/ +int NoSectorStyles(void); + +/* Choose a sector style. TRUE is accepted, FALSE cancelled. +*/ +int ChooseSectorStyle(int *flags, + DirName upper,DirName middle,DirName lower, + DirName floor,DirName ceiling); + + +#endif + + +/* END OF FILE */ diff --git a/texture.c b/texture.c new file mode 100644 index 0000000..eb29d01 --- /dev/null +++ b/texture.c @@ -0,0 +1,594 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Stores lists of the graphical information from the WADs + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <string.h> + +#include "texture.h" +#include "wad.h" +#include "mem.h" +#include "gfx.h" +#include "platgui.h" +#include "gui.h" +#include "vstring.h" + + +PLAT_IMG_PICKLIST *flat_picklist=NULL; +PLAT_IMG_PICKLIST *texture_picklist=NULL; + +/* The height and width of a texture are actually stored along with the + texture name +*/ +#define TXTNUMWID 8 +#define TXTHEIGHT 10 +#define TXTWIDTH 20 +#define TXTMALLOC 31 + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static int CmpText(const void *a,const void *b) +{ + const PLAT_IMG_PICKLIST *p1,*p2; + + p1=a; + p2=b; + + return(StrCaseCmp(p1->text,p2->text)); +} + + +static Byte *GetShort(Byte *p,Short *s) +{ + *s=(Short)(*p++); + *s|=((Short)(*p++))<<8; + return(p); +} + + +static Byte *GetLong(Byte *p,Long *l) +{ + *l=(Long)(*p++); + *l|=((Long)(*p++))<<8; + *l|=((Long)(*p++))<<16; + *l|=((Long)(*p++))<<24; + return(p); +} + +static Byte *GetName(Byte *p,char *s) +{ + int f; + + for(f=0;f<8;f++) + *s++=*p++; + + *s=0; + return(p); +} + + +static void BMPlot(int x,int y,int c,GFX_BITMAP *bm) +{ + if ((x>=0)&&(x<bm->w)&&(y>=0)&&(y<bm->h)) + *(bm->data+(x)+(y*bm->w))=c; +} + + +static void DecodeLump(Byte *lump, int ox, int oy, GFX_BITMAP *bm) +{ + Short lw,lh,lox,loy; + Byte *base; + Byte *col; + Long off; + int x,y,f; + Byte cno; + + base=lump; + lump=GetShort(lump,&lw); + lump=GetShort(lump,&lh); + lump=GetShort(lump,&lox); + lump=GetShort(lump,&loy); + + lox=MAX(lox,0); + loy=MAX(loy,0); + + for(x=0;x<lw;x++) + { + lump=GetLong(lump,&off); + col=base+off; + + while(*col!=0xff) + { + y=*col++; + cno=*col++; + col++; + + for(f=0;f<cno;f++) + { + BMPlot(ox+x,oy+y,(int)*col,bm); + col++; + y++; + } + + col++; + } + } +} + + +static GFX_IMAGE GetTexture(Byte *t_ent, Byte *pn, GFX_BITMAP *bm) +{ + char name[9]; + Short no,w,h,xo,yo,pno; + int f; + Byte *patch; + + /* Skip over name and 2 always zero fields + */ + t_ent+=8+2+2; + + /* Get height and width of texture (limited to max size of bitmap) + */ + t_ent=GetShort(t_ent,&w); + bm->w=MIN(w,MAX_GFXBM_W); + + t_ent=GetShort(t_ent,&h); + bm->h=MIN(h,MAX_GFXBM_H); + + /* Once we have the width and height, return if the actual image is not to + be loaded + */ + if (!load_textures) + return(NULL); + + /* Skip over always zero fields + */ + t_ent+=4; + + /* The bitmap is filled with the transparent colour + */ + memset(bm->data,243,w*h); + + /* Get no of patches that make up this texture + */ + t_ent=GetShort(t_ent,&no); + + /* Read each patch and add to the texture + */ + for(f=0;f<no;f++) + { + /* Patch offsets and number then skip remaining + */ + t_ent=GetShort(t_ent,&xo); + t_ent=GetShort(t_ent,&yo); + t_ent=GetShort(t_ent,&pno); + t_ent+=4; + + /* Get the name from the Pname entry and load the lump + */ + GetName(pn+4+8*pno,name); + + if (!(patch=GetLump(name,NULL))) + GFX_exit(EXIT_FAILURE,"Failed to find patch %s\n",name); + + /* Decode the graphics lump and load it into the bitmap + */ + DecodeLump(patch,xo,yo,bm); + + Release(patch); + } + + return(GFX_create_image(bm)); +} + + +static void ReadTextures(char *name,Byte *texture, + Byte *pn,int *i,GFX_BITMAP *bm) +{ + Long no; + Long off; + Byte *base; + int f; + + base=texture; + + /* Get the no of the textures + */ + texture=GetLong(texture,&no); + + /* Loop through all the textures and create the picklist entry + */ + for(f=0;f<no;f++) + { + texture=GetLong(texture,&off); + + texture_picklist[*i].text=Grab(TXTMALLOC); + + GetName(base+off,texture_picklist[*i].text); + + GuiDrawInfoBox((load_textures ? + "Please wait. Reading wall texture graphics": + "Please wait. Reading wall texture names"), + GUI_CENTRE,GUI_CENTRE,TRUE, + "Lump %s|Texture %s|%d%% complete", + name,texture_picklist[*i].text, + f*100/no); + GFX_redraw(); + + texture_picklist[*i].img=GetTexture(base+off,pn,bm); + sprintf(texture_picklist[*i].text+TXTWIDTH, + "%*.*d",TXTNUMWID,TXTNUMWID,bm->w); + 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;f<no;f++) + flat_picklist[f].client_index=f; +} + + +void ReadWADTextures(void) +{ + Long t1_size,t2_size; + int no; + Byte *t1=NULL; + Byte *t2=NULL; + Byte *pn=NULL; + Byte *pal=NULL; + GFX_BITMAP bm; + int ip; + int f; + + if (!(pal=GetLump("PLAYPAL",NULL))) + GFX_exit(EXIT_FAILURE,"There MUST be a PLAYPAL lump in the WADs!!\n"); + + if (!(t1=GetLump("TEXTURE1",NULL))) + GFX_exit(EXIT_FAILURE,"There MUST be a TEXTURE1 lump in the WADs!!\n"); + + if ((game==DOOM)||(game==ULTIMATE_DOOM)) + if (!(t2=GetLump("TEXTURE2",NULL))) + GFX_exit(EXIT_FAILURE, + "There MUST be a TEXTURE2 lump in the WADs!!\n"); + + if (!(pn=GetLump("PNAMES",NULL))) + GFX_exit(EXIT_FAILURE,"There MUST be a PNAMES lump in the WADs!!\n"); + + if (texture_picklist) + { + ip=0; + while(texture_picklist[ip].text) + { + Release(texture_picklist[ip].text); + if (texture_picklist[ip].img) + GFX_destroy_image(texture_picklist[ip].img); + } + + Release(texture_picklist); + } + + /* Calculate the size of the resulting picklist + extra two - + one for the empty '-' texture and the other for the end of list marker. + */ + GetLong(t1,&t1_size); + + if (t2) + GetLong(t2,&t2_size); + else + t2_size=0; + + no=t1_size+t2_size+2; + + texture_picklist=Grab(sizeof(PLAT_IMG_PICKLIST)*no); + + /* Storage and palette for bitmap + */ + bm.data=Grab(MAX_GFXBM_W*MAX_GFXBM_H); + + 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); + } + + /* Create '-' texture + */ + ip=0; + + texture_picklist[ip].text=Grab(TXTMALLOC); + strcpy(texture_picklist[ip].text,empty_texture); + sprintf(texture_picklist[ip].text+TXTHEIGHT, + "%*.*d",TXTNUMWID,TXTNUMWID,0); + sprintf(texture_picklist[ip].text+TXTWIDTH, + "%*.*d",TXTNUMWID,TXTNUMWID,0); + + texture_picklist[ip].img=NULL; + ip++; + + /* Read the patches from TEXTURE1 and possible TEXTURE2 + */ + ReadTextures("TEXTURE1",t1,pn,&ip,&bm); + + if (t2) + ReadTextures("TEXTURE2",t2,pn,&ip,&bm); + + /* Create end of picklist marker + */ + texture_picklist[ip].text=NULL; + + Release(bm.data); + Release(t1); + Release(t2); + Release(pn); + Release(pal); + + /* Sort the list if requested + */ + if (sort_textures) + qsort(&texture_picklist[1],no-2,sizeof(PLAT_IMG_PICKLIST),CmpText); + + /* Set the client indexes + */ + for(f=0;f<no;f++) + texture_picklist[f].client_index=f; +} + + +void TextureSize(char *name, int *width, int *height) +{ + int f; + + f=0; + while(texture_picklist[f].text) + { + if (STREQ(texture_picklist[f].text,name)) + { + if (width) + *width=atoi(texture_picklist[f].text+TXTWIDTH); + + if (height) + *height=atoi(texture_picklist[f].text+TXTHEIGHT); + + return; + } + + f++; + } + + if (width) + *width=0; + + if (height) + *height=0; +} + + +GFX_IMAGE DecodeGraphicsLump(char *lump) +{ + Byte *obj; + Byte *base; + Byte *pal; + GFX_BITMAP bm; + GFX_IMAGE img; + int f; + Short w,h; + + if (!(obj=GetLump(lump,NULL))) + return(NULL); + + if (!(pal=GetLump("PLAYPAL",NULL))) + GFX_exit(EXIT_FAILURE,"There MUST be a PLAYPAL lump in the WADs!!\n"); + + base=obj; + obj=GetShort(obj,&w); + obj=GetShort(obj,&h); + + bm.w=w; + bm.h=h; + bm.data=Grab(w*h); + + 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); + } + + DecodeLump(base,0,0,&bm); + + img=GFX_create_image(&bm); + + Release(bm.data); + Release(base); + Release(pal); + + return(img); +} + + +/* END OF FILE */ + diff --git a/texture.h b/texture.h new file mode 100644 index 0000000..45959e3 --- /dev/null +++ b/texture.h @@ -0,0 +1,69 @@ +/* + + 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 + + $Id$ + +*/ + +#ifndef _TEXTURE_H + +#define _TEXTURE_H + +#include "gfx.h" +#include "platgui.h" + +/* Picklists to allow selection of textures and flats. The client data returns + from these picklists will be the index into the picklist. +*/ +extern PLAT_IMG_PICKLIST *flat_picklist; +extern PLAT_IMG_PICKLIST *texture_picklist; + +#define TXT_PICKDEFVAL -1 /* Use as cancel/defval in picklist */ + + +/* Create the picklists. Note these expect the graphics routines to be + initialised so that progress meters can be drawn. +*/ +void ReadWADFlats(void); +void ReadWADTextures(void); + +/* Given a texture name give the size of the texture. Note that 0 is returned + for the "-" empty texture and unknown names. +*/ +void TextureSize(char *name,int *width,int *height); + + +/* Utility to return a GFX_IMAGE for the supplied graphics lump. Note the + lump must be in the Doom graphics format used for textures and sprites - + flats cannot be read with this. Returns NULL if the lump cannot be found. + + Note that error checking on the type of lump given is not *AT ALL* done. +*/ +GFX_IMAGE DecodeGraphicsLump(char *lump); + + +#endif + + +/* END OF FILE */ diff --git a/things.c b/things.c new file mode 100644 index 0000000..dc39546 --- /dev/null +++ b/things.c @@ -0,0 +1,331 @@ +/* + + 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 + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include "platgui.h" +#include "gfx.h" +#include "things.h" +#include "mem.h" +#include "list.h" +#include "map.h" + + +/* ---------------------------------------- TYPES AND VARS +*/ +#define DEFAULT_RAD 20 +#define DEFAULT_COL V_RGB(0xff,0x80,0x80) + +typedef struct + { + char *name; + int col; + } ThingClass; + +typedef struct + { + int class; + int id; + char *name; + GFX_IMAGE img; + } ThingInfo; + +typedef struct + { + int id; + int rad; + int col; + } ThingRad; + +static int no_classes=0; + +static Map thing_class=NULL; +static List thing_list=NULL; +static List rad_list=NULL; + +static PLAT_IMG_PICKLIST **picklist=NULL; +static PLAT_MENU *thing_menu=NULL; + +static char *thing_flags[17]= + {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + +static char *thing_flags_sh[17]= + {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static PLAT_IMG_PICKLIST *ThingPicklist(int class) +{ + ThingInfo *ti; + Iterator i; + int no; + int f; + + if (picklist[class]) + return(picklist[class]); + else + { + no=0; + i=ListIterator(thing_list); + + while(i) + { + ti=IteratorData(i); + + if (ti->class==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;f<MapSize(thing_class);f++) + { + ThingClass *c; + + c=MapElem(thing_class,f); + + if (STREQ(c->name,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;f<no_classes;f++) + { + ThingClass *c; + + c=MapElem(thing_class,f); + thing_menu[f].text=c->name; + thing_menu[f].client_index=f; + } + + for(f=0;f<no_classes+1;f++) + picklist[f]=NULL; + + thing_menu[no_classes].text=NULL; + } + + GFX_mouse(&x,&y); + + if (no_classes<2) + class=0; + else + class=GUI_menu("Pick class of THING",x,y,thing_menu,THING_NULLID); + + if (class!=THING_NULLID) + class=GUI_image_picklist("THING",ThingPicklist(class),THING_NULLID); + + return(class); +} + + +int ThingRadius(int id, int *col) +{ + Iterator i; + ThingRad *r; + + i=ListIterator(rad_list); + + while(i) + { + r=IteratorData(i); + + if (r->id==id) + { + IteratorClear(i); + + if (col) + *col=r->col; + + return(r->rad); + } + + i=IteratorNext(i); + } + + if (col) + *col=DEFAULT_COL; + + return(DEFAULT_RAD); +} + + +char *ThingName(int id) +{ + ThingInfo *ti; + Iterator i; + + i=ListIterator(thing_list); + + while(i) + { + ti=IteratorData(i); + + if (ti->id==id) + { + IteratorClear(i); + return(ti->name); + } + + i=IteratorNext(i); + } + + return("UNKNOWN"); +} + + +void ThingFlag(int bit,char *s,char *sh) +{ + thing_flags[bit]=Strdup(s); + thing_flags_sh[bit]=Strdup(sh); +} + + +char **ThingFlagArray(void) +{ + return(thing_flags); +} + + +char *ThingFlagText(int flags) +{ + static char s[512]; + int b; + + s[0]=0; + + for(b=0;b<16;b++) + if (flags&(1<<b)) + if (thing_flags_sh[b]) + if (!s[0]) + strcpy(s,thing_flags_sh[b]); + else + { + strcat(s,","); + strcat(s,thing_flags_sh[b]); + } + return(s); +} + + + +/* END OF FILE */ diff --git a/things.h b/things.h new file mode 100644 index 0000000..512de19 --- /dev/null +++ b/things.h @@ -0,0 +1,88 @@ +/* + + 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 _THINGS_H + +#define _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); + + +/* Set the meaning of one of the bits in the options field for a thing +*/ +void ThingFlag(int bit,char *name,char *shorthand); + + +/* Returns a GUI_multi_box() compatible text array for manipulating a THINGs + flags. +*/ +char **ThingFlagArray(void); + + +/* Return a static string representing the meaning of the passed in flags +*/ +char *ThingFlagText(int flag); + + +#endif + + +/* END OF FILE */ @@ -0,0 +1,61 @@ +/* + + 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 <string.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]); +} + + +/* END OF FILE */ @@ -0,0 +1,45 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Various utility functions + + $Id$ + + +*/ + +#ifndef _UTIL_H + +#define _UTIL_H + +/* 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); + +#endif diff --git a/vidoom.c b/vidoom.c new file mode 100644 index 0000000..d6ee820 --- /dev/null +++ b/vidoom.c @@ -0,0 +1,726 @@ +/* + + 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 <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "wad.h" +#include "platgui.h" +#include "gui.h" +#include "gfx.h" +#include "file.h" +#include "mem.h" +#include "edit.h" +#include "texture.h" +#include "things.h" +#include "runcmd.h" + +/* ---------------------------------------- VARS +*/ +static WadMap *wad=NULL; +static char mapname[32]="NONE"; +static GFX_IMAGE doom_image; + +/* Menu for asking game type +*/ +static PLAT_MENU game_type_menu[]= + { + {"Doom", DOOM}, + {"Ultimate Doom", ULTIMATE_DOOM}, + {"Doom II", DOOM_2}, + {"TNT:Evilution", FINAL_TNT}, + {"The Plutonia Experiment", FINAL_PLUTONIA}, + {"ZDoom", ZDOOM}, + {NULL,0} + }; + + +/* ---------------------------------------- PROTOS +*/ +static void MainMenu(void); +static void GPL_clear(void); + + +/* ---------------------------------------- MAIN +*/ +int viDOOM(int argc,char *argv[]) +{ + char *load,*p; + int f; + + if (getenv("VIDOOM_DIR")) + Cd(getenv("VIDOOM_DIR")); + + GFX_init(); + GFX_clear_XOR_mode(); + + if (GFX_mouse_buttons()<2) + GFX_exit(EXIT_FAILURE,"viDOOM expects at least a 2-button mouse\n"); + + LoadGlobalsPart1(); + + if ((disp_width<640)||(disp_height<480)) + GFX_exit(EXIT_FAILURE,"viDOOM expects at least a display of 640x480\n"); + + GFX_open(disp_width,disp_height); + EditSetScreen(disp_width,disp_height); + GuiSetScreen(disp_width,disp_height); + GUI_setscreen(disp_width,disp_height); + + GPL_clear(); + + /* Ask for game type? + */ + if (ask_for_game_type) + { + int new; + + GFX_redraw(); + + new=GUI_menu("Select type of game to edit", + disp_width/2,disp_height/2,game_type_menu,-666); + + if (new!=-666) + game=(GameType)new; + } + + LoadGlobalsPart2(); + + if (AddIWAD(IWAD_path)!=WAD_OK) + { + GuiInfoBox("ERROR","AddIWAD(%s): %s",IWAD_path,WadErrorString()); + GFX_close(); + return(EXIT_FAILURE); + } + + /* Read in resource WADS from preloaded config + */ + if (PWAD_preload[0]) + { + load=Strdup(PWAD_preload); + + p=strtok(load,";"); + + while(p) + { + if (AddPWAD(p)!=WAD_OK) + GuiInfoBox("ERROR","AddPWAD(%s): %s",p,WadErrorString()); + + p=strtok(NULL,";"); + } + + Release(load); + } + + /* Read in WADS from command line + */ + for(f=1;f<argc;f++) + if (AddPWAD(argv[f])!=WAD_OK) + GuiInfoBox("ERROR","AddPWAD(%s): %s",argv[f],WadErrorString()); + + /* Read in editor configuration + */ + GPL_clear(); + GuiDrawInfoBox("Please wait",GUI_CENTRE,GUI_CENTRE,TRUE, + "Reading editor|config file"); + GFX_redraw(); + LoadConfig(); + + /* Read in TEXTURES and FLATS + */ + GPL_clear(); + ReadWADTextures(); + + GPL_clear(); + ReadWADFlats(); + + if (show_titlepic) + doom_image=DecodeGraphicsLump("TITLEPIC"); + else + doom_image=NULL; + + + /* Create initial empty map + */ + if (initial_empty_map) + { + switch(level_style) + { + case DOOM_LEVELS: + case ULTIMATE_DOOM_LEVELS: + strcpy(mapname,"E1M1"); + break; + + case DOOM_2_LEVELS: + strcpy(mapname,"MAP01"); + break; + + } + + wad=NewMap(); + EditLoad(wad); + } + + MainMenu(); + + GFX_close(); + + return(EXIT_SUCCESS); +} + +/* Clear screen and show simple GPL warning during startup +*/ +static void GPL_clear(void) +{ + GFX_clear(BLACK); + + GuiDrawInfoBox("viDOOM " VIDOOMVER " " VIDOOMRELEASE, + GUI_CENTRE,GUI_FLUSH_TOP,TRUE, + "Copyright (c) 2000 Ian Cowburn| |" + "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."); +} + + +/* Format an argument for the node builder command +*/ +static char *FormatArg(char *path, char *arg) +{ + char *ret; + char *p; + + ret=Grab(PATH_MAX); + p=ret; + + while(*arg) + if (*arg=='%') + { + *p=0; + strcat(ret,path); + p+=strlen(path); + arg++; + } + else + *p++=*arg++; + + return(ret); +} + + +/* Upper case a string +*/ +static void ToUpper(char *p) +{ + while(*p) + { + *p=toupper(*p); + p++; + } +} + + +/* Check whether file should be ignored for node building +*/ +static int IsIgnored(char *path) +{ + char i[PATH_MAX]; + char w[PATH_MAX]; + + if (!build_ignore[0]) + return(FALSE); + + strcpy(w,Basename(path)); + strcpy(i,build_ignore); + + ToUpper(w); + ToUpper(i); + + return((int)strstr(w,i)); +} + + +/* ---------------------------------------- TOP LEVEL MENU +*/ +static void MainMenu(void) +{ +# define MENU_NEW 1 +# define MENU_LOAD 2 +# define MENU_EDIT 3 +# define MENU_SAVE 4 +# define MENU_OPEN 5 +# define MENU_CLOSE 6 +# define MENU_PREVIEW 7 +# define MENU_ABOUT 8 +# define MENU_QUIT 9 +# define MENU_RENAME 10 +# define MENU_LISTDIR 11 +# define MENU_DEBUG 666 + + static PLAT_MENU main_menu[]= + { + {"Edit current level", MENU_EDIT}, + {"Load level from open WADs", MENU_LOAD}, + {"Save current level", MENU_SAVE}, + {"Create new empty level", MENU_NEW}, + {"Change current level name", MENU_RENAME}, + {"Open PWAD file", MENU_OPEN}, + {"Close PWAD file", MENU_CLOSE}, + {"Preview level", MENU_PREVIEW}, + {"List entries in WAD directory", MENU_LISTDIR}, + {"About viDOOM " VIDOOMVER, MENU_ABOUT}, +#ifdef DEBUG + {"DEBUG", MENU_DEBUG}, +#endif + {"Quit", MENU_QUIT}, + {NULL,0} + }; + + int quit; + int editted; + + quit=FALSE; + editted=FALSE; + + while(!quit) + { + char *open; + + GFX_clear(BLACK); + + if (doom_image) + GFX_fill_screen(doom_image); + + GuiDrawInfoBox(game_name,GUI_FLUSH_RIGHT,GUI_FLUSH_TOP,FALSE, + "Current map : %s| |Open WAD files :|%s", + mapname,open=OpenWads()); + + Release(open); + + GFX_redraw(); + + switch(GUI_menu("MAIN MENU",10,10,main_menu,-1)) + { + case MENU_NEW: + { + char *name; + int new=TRUE; + + if ((name=GuiPickLevel("Pick map to create"))) + { + if (wad) + if ((!map_warn)|| + (new=GUI_yesno("Map already open. Continue?"))) + { + strcpy(mapname,"NONE"); + wad=ClearMap(wad); + editted=FALSE; + } + + if (new) + { + strcpy(mapname,name); + wad=NewMap(); + EditLoad(wad); + editted=FALSE; + } + } + + break; + } + + case MENU_LOAD: + { + char *name; + int load=TRUE; + + if ((name=GuiPickLevel("Pick map to load for editting"))) + { + if (wad) + if ((!map_warn)|| + (load=GUI_yesno("Map already open. Continue?"))) + { + strcpy(mapname,"NONE"); + wad=ClearMap(wad); + editted=FALSE; + } + + if (load) + { + GuiDrawInfoBox("Loading...",GUI_CENTRE,GUI_CENTRE,TRUE, + "Loading level %s",name); + GFX_redraw(); + + if (!(wad=LoadMap(name))) + GuiInfoBox("ERROR","LoadMap(%s): %s", + name,WadErrorString()); + else + { + strcpy(mapname,name); + EditLoad(wad); + editted=FALSE; + } + } + } + + break; + } + + case MENU_EDIT: + if (!wad) + GuiInfoBox("ERROR","No map currently being editted"); + else + { + EditLoop(); + editted=TRUE; + } + break; + + case MENU_SAVE: + { + char *wadf; + + if (!wad) + GuiInfoBox("ERROR","No map currently being editted"); + else + if ((wadf=GUI_fsel + ("Select WAD to save map as",PWAD_dir,".WAD"))) + { + int ok; + + if ((overwrite_warning)&&(FileExists(wadf))) + ok=GUI_yesno("Overwrite file?"); + else + ok=TRUE; + + if (ok) + { + GuiDrawInfoBox + ("Saving...",GUI_CENTRE,GUI_CENTRE,TRUE, + "Saving level %s to %s",mapname,wadf); + GFX_redraw(); + + EditCompact(); + EditSave(wad); + + if (SaveMap(wad,mapname,wadf)!=WAD_OK) + GuiInfoBox("ERROR","SaveMap(%s)|%s", + wadf,WadErrorString()); + else + { + int do_build; + char *open; + char *p; + + editted=FALSE; + + if (use_build) + do_build=!IsIgnored(wadf); + else + do_build=FALSE; + + if (do_build) + { + char path[PATH_MAX]; + char *arg[4]; + + arg[0]=build_cmd; + + if (build_in_before_out) + { + arg[1]=FormatArg(wadf,build_in); + arg[2]=FormatArg(wadf,build_out); + } + else + { + arg[2]=FormatArg(wadf,build_in); + arg[1]=FormatArg(wadf,build_out); + } + + arg[3]=NULL; + + if (RunCommand(arg,path)) + { + if ((build_always_view)&&(path[0])) + ViewFile("Node Builder",path); + } + else + if (path[0]) + ViewFile("Node Builder FAILED", + path); + else + GuiInfoBox("ERROR", + "Node builder|%s|failed|" + "(no results available)", + build_cmd); + + if (path[0]) + remove(path); + + Release(arg[1]); + Release(arg[2]); + } + + /* Check to see if we've saved on of the + currently loaded PWADS + */ + if ((open=OpenWads())) + { + p=open; + + p=strtok(p,"|"); + + while(p) + { + if (FilenamesEqual(p,wadf)) + { + if (CloseWad(wadf)!=WAD_OK) + GuiInfoBox + ("ERROR","CloseWad(%s)|%s", + wadf,WadErrorString()); + + if (AddPWAD(wadf)!=WAD_OK) + GuiInfoBox + ("ERROR","AddPWAD(%s)|%s", + wadf,WadErrorString()); + + p=NULL; + } + else + p=strtok(NULL,"|"); + } + + Release(open); + } + } + } + + Release(wadf); + } + break; + } + + case MENU_RENAME: + { + char *name; + + if (!wad) + GuiInfoBox("ERROR","No map currently being editted"); + else + if ((name=GuiPickLevel("Pick new name for level"))) + strcpy(mapname,name); + + break; + } + + case MENU_OPEN: + { + char *wadf; + + if ((wadf=GUI_fsel("Select WAD to open",PWAD_dir,".WAD"))) + { + GuiDrawInfoBox("Loading...",GUI_CENTRE,GUI_CENTRE,TRUE, + "Loading PWAD %s",wadf); + GFX_redraw(); + + if (AddPWAD(wadf)!=WAD_OK) + GuiInfoBox("ERROR","AddPWAD(%s)|%s", + wadf,WadErrorString()); + + Release(wadf); + } + } + break; + + case MENU_CLOSE: + { + char *open; + char *wadf[512]; + char *p; + int f; + + if ((open=OpenWads())) + { + p=strtok(open,"|"); + f=0; + + while(p) + { + wadf[f++]=p; + p=strtok(NULL,"|"); + } + + wadf[f]=NULL; + + f=GUI_picklist("Select WAD file to close",wadf); + + if (f!=-1) + if (strcmp(wadf[f],IWAD_path)==0) + GuiInfoBox("ERROR","Cannot unload base IWAD|%s", + wadf[f]); + else + { + GuiDrawInfoBox("Closing...", + GUI_CENTRE,GUI_CENTRE,TRUE, + "Closing PWAD %s",wadf[f]); + + if (CloseWad(wadf[f])!=WAD_OK) + GuiInfoBox("ERROR","CloseWad(%s)|%s", + wadf[f],WadErrorString()); + } + + Release(open); + } + + break; + } + + case MENU_LISTDIR: + { + char s[1024]; + WadDir *wd; + Iterator i; + char **list; + int f; + + list=Grab(sizeof(char *)*(GetWadDirSize()+1)); + i=GetWadDir(); + + f=0; + while(i) + { + wd=IteratorData(i); + i=IteratorNext(i); + + sprintf(s,"%-9s 0x%.8lx 0x%.8lx %s", + wd->name,wd->off,wd->size,Basename(wd->wad)); + list[f++]=Strdup(s); + } + + list[f]=NULL; + + GUI_picklist("WAD DIR (Name, Offset, Size, WAD file)",list); + + f=0; + while(list[f]) + Release(list[f++]); + + Release(list); + + break; + } + + case MENU_PREVIEW: + { + char *name; + WadMap *preview; + + if ((name=GuiPickLevel("Pick map to preview"))) + if (!(preview=LoadMap(name))) + GuiInfoBox("ERROR","LoadMap(%s): %s", + name,WadErrorString()); + else + { + EditPreviewWadMap(name,preview); + preview=ClearMap(preview); + } + + break; + } + + case MENU_ABOUT: + GuiInfoBox ("viDOOM " VIDOOMVER " " VIDOOMRELEASE, + "Copyright (c) 2000 Ian Cowburn|" + "http://www.noddybox.demon.co.uk/vidoom/| |" + + "viDOOM comes with ABSOLUTELY NO WARRANTY.|" + "For details see LICENSE.| |" + + "This is free software, and you are welcome|" + "to redistribute it under certain conditions.|" + "See LICENSE for details.| |" + + "DOOM, Ultimate DOOM, DOOM 2 and Final DOOM|" + "(c) id Software.|" + "http://www.idsoftware.com/| |" + "Levels in DOOM, DOOM 2 and Ultimate DOOM|" + "designed by id Software.| |" + "Levels in The Plutonia Experiment designed by|" + "Milo & Dario Casali whilst in Team TNT.| |" + "Levels in TNT:Evilution designed by|" + "various members of Team TNT. Get details at|" + "http://www.teamtnt.com/| |" + "Thanks to all concerned for some of my favourite|" + "Lovecraftian Dark Evil Places.| |" + "viDOOM will only work if you have the registered|" + "version of any of the follow id Sofwtare games:|" + "DOOM, Ultimate DOOM, DOOM 2 or Final DOOM"); + break; + + case MENU_QUIT: + if ((map_exit_warn)&&(editted)) + quit=GUI_yesno("Map may have been changed " + "- really quit?"); + else + quit=TRUE; + break; + +#ifdef DEBUG + case MENU_DEBUG: + GuiInfoBox("DEBUG", + "block_bit=%d|" + "block_mask=%d|" + "side2_bit=%d|" + "side2_mask=%d|" + "upper_bit=%d|" + "upper_mask=%d|" + "lower_bit=%d|" + "lower_mask=%d|" + "empty_texture='%s'|" + "", + block_bit,block_mask, + side2_bit,side2_mask, + upper_peg_bit,upper_peg_mask, + lower_peg_bit,lower_peg_mask, + empty_texture); + break; +#endif + + default: + break; + } + } +} + + +/* END OF FILE */ diff --git a/vidoom.h b/vidoom.h new file mode 100644 index 0000000..2ba884b --- /dev/null +++ b/vidoom.h @@ -0,0 +1,44 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + viDOOM main entry point + + Provided to allow systems that don't start via main() to be used. The + platform dependent object main.o should do any necessary initialisation + for this port and then call the entry point here. + + $Id$ + +*/ + +#ifndef _VIDOOM_H + +#define _VIDOOM_H + +/* Main viDOOM entry point +*/ +int viDOOM(int argc, char *argv[]); + +#endif + +/* END OF FILE */ + diff --git a/vstring.h b/vstring.h new file mode 100644 index 0000000..f2f7b04 --- /dev/null +++ b/vstring.h @@ -0,0 +1,44 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides portable versions of necessary string routines + + $Id$ + + +*/ + +#ifndef _VSTRING_H + +#define _VSTRING_H + +/* Does exactly the same as strcmp(), but ignores case. + The passed in strings should not be altered. +*/ +int StrCaseCmp(char *a, char *b); + +/* Does exactly the same as strncmp(), but ignores case. + The passed in strings should not be altered. +*/ +int StrNCaseCmp(char *a, char *b, int n); + +#endif @@ -0,0 +1,806 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + WAD file definitions and readers + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <stdio.h> +#include <string.h> + +#include "wad.h" +#include "gfx.h" +#include "mem.h" +#include "file.h" + +/* ---------------------------------------- TYPES +*/ + +typedef struct WadEnt + { + DirName name; + Long off; + Long size; + } WadEnt; + +typedef struct WadDirTable + { + int no; + WadEnt *ent; + } WadDirTable; + +typedef struct WadFile + { + FILE *fp; + char path[PATH_MAX+1]; + } WadFile; + + +/* ---------------------------------------- VARS +*/ + +#define IGNORE_LUMP 0 +#define THING_LUMP 1 +#define VERTEX_LUMP 2 +#define LINEDEF_LUMP 3 +#define SIDEDEF_LUMP 4 +#define SECTOR_LUMP 5 + +#define ERR(e,r) do {wad_err=e;return(r);} while(0) +static const char *wad_errstr[WAD_NOERROR]= + { + "no error", + "File not found", + "File not an IWAD or PWAD", + "File not an IWAD", + "File not a PWAD", + "Map not found", + "Lump not found", + "Could not create file", + __FILE__ " - ??? BROKEN ???", + }; + +static int wad_err=WAD_OK; + +static List waddir=NULL; +static List wadlist=NULL; + + +/* ---------------------------------------- MACROS +*/ +#define ERR(e,r) do {wad_err=e;return(r);} while(0) + + +/* ---------------------------------------- PREDICATE FUNCTIONS +*/ +static int FindDirEnt(void *a,void *b) +{ + WadDir *aa; + + aa=(WadDir *)a; + + return(STREQ(aa->name,b)); +} + + +static int FindWAD(void *a,void *b) +{ + WadFile *aa; + + aa=a; + + return(FilenamesEqual(aa->path,b)); +} + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static Word GetShort(FILE *fp) +{ + return ((Short)fgetc(fp)|((Short)fgetc(fp))<<8); +} + + +static Long GetLong(FILE *fp) +{ + return ((Long)fgetc(fp)| + ((Long)fgetc(fp))<<8| + ((Long)fgetc(fp))<<16| + ((Long)fgetc(fp))<<24); +} + + +static char *GetName(FILE *fp) +{ + static DirName d; + + fread(d,1,8,fp); + d[sizeof(d)-1]=0; + return(d); +} + + +static void PutShort(FILE *fp,Short s) +{ + fputc(s&0xff,fp); + fputc((s>>8)&0xff,fp); +} + + +static void PutLong(FILE *fp,Long l) +{ + fputc(l&0xff,fp); + fputc((l>>8)&0xff,fp); + fputc((l>>16)&0xff,fp); + fputc((l>>24)&0xff,fp); +} + + +static void PutName(FILE *fp,char *p) +{ + int f; + + f=0; + while(f<8) + { + fputc(*p,fp); + + if (*p) + p++; + + f++; + } +} + + +static void PutDirEnt(FILE *fp,Long off,Long size,char *p) +{ + PutLong(fp,off); + PutLong(fp,size); + PutName(fp,p); +} + + +static int IsMapLump(char *n) +{ + return(STREQ("THINGS",n)|| + STREQ("LINEDEFS",n)|| + STREQ("SIDEDEFS",n)|| + STREQ("VERTEXES",n)|| + STREQ("SEGS",n)|| + STREQ("SSECTORS",n)|| + STREQ("NODES",n)|| + STREQ("SECTORS",n)|| + STREQ("REJECT",n)|| + STREQ("BLOCKMAP",n)); +} + +static int HandledMapLump(char *n) +{ + static struct + { + char *name; + int lump; + } lump[]= { + {"THINGS",THING_LUMP}, + {"VERTEXES",VERTEX_LUMP}, + {"SIDEDEFS",SIDEDEF_LUMP}, + {"LINEDEFS",LINEDEF_LUMP}, + {"SECTORS",SECTOR_LUMP}, + {NULL,IGNORE_LUMP}, + }; + + int f; + + f=0; + while(lump[f].name) + { + if (STREQ(lump[f].name,n)) + return(lump[f].lump); + + f++; + } + + return(IGNORE_LUMP); +} + + +static WadDir *GetDir(char *name) +{ + Iterator i; + WadDir *w; + + if (!(i=ListFindElem(waddir,FindDirEnt,name))) + return(NULL); + + w=IteratorData(i); + IteratorClear(i); + + return(w); +} + + +static WadFile *GetWADFile(char *name) +{ + Iterator i; + WadFile *w; + + if (!(i=ListFindElem(wadlist,FindWAD,name))) + return(NULL); + + w=IteratorData(i); + IteratorClear(i); + + return(w); +} + + +static void *LoadDirEnt(WadDir *d,Long *size) +{ + void *ret; + WadFile *wf; + + if (!(wf=GetWADFile(d->wad))) + return(NULL); + + ret=Grab(d->size); + fseek(wf->fp,(long)d->off,SEEK_SET); + fread(ret,1,d->size,wf->fp); + + if (size) + *size=d->size; + + return(ret); +} + + +static WadDirTable *ReadDir(char *wad, char *expect) +{ + char type[4]; + WadDirTable *d; + int f; + FILE *fp; + + if (!(fp=fopen(wad,"rb"))) + ERR(WAD_FILE_NOT_FOUND,NULL); + + fread(type,1,4,fp); + + if (STRNEQ("IWAD",expect)&&(!STRNEQ("IWAD",type))) + ERR(WAD_NOT_IWAD,NULL); + else if (STRNEQ("PWAD",expect)&&(!STRNEQ("PWAD",type))) + ERR(WAD_NOT_PWAD,NULL); + + d=Grab(sizeof(WadDirTable)); + d->no=GetLong(fp); + + d->ent=Grab(sizeof(WadEnt)*d->no); + + fseek(fp,(long)GetLong(fp),SEEK_SET); + + for(f=0;f<d->no;f++) + { + d->ent[f].off=GetLong(fp); + d->ent[f].size=GetLong(fp); + strcpy(d->ent[f].name,GetName(fp)); + } + + return(d); +} + + +static int AddWAD(char *wad,char *type) +{ + Iterator i; + WadDirTable *d; + WadDir w; + int f; + char *wadname; + WadFile *wf; + int check; + int e2m1; + int map01; + + /* Read in the directory from the WAD + */ + if (!waddir) + { + waddir=ListNew(sizeof(WadDir)); + wadlist=ListNew(sizeof(WadFile)); + } + + if (!(d=ReadDir(wad,type))) + return(wad_err); + + /* Find the WAD name in the WAD list + */ + if ((i=ListFindElem(wadlist,FindWAD,wad))) + { + wadname=((WadFile *)IteratorData(i))->path; + IteratorClear(i); + } + else + { + wf=Grab(sizeof(WadFile)); + + if (!(wf->fp=fopen(wad,"rb"))) + GFX_exit(EXIT_FAILURE,"BIZARRE: WAD opening failed after " + "first open succeeded on\nt%s\n",wad); + + strcpy(wf->path,wad); + wadname=wf->path; + ListInsert(wadlist,wf); + } + + /* Add the directory entries to the global dir + */ + e2m1=FALSE; + map01=FALSE; + check=STRNEQ("IWAD",type); + + for(f=d->no-1;f>=0;f--) + { + w.wad=wadname; + w.off=d->ent[f].off; + w.size=d->ent[f].size; + strcpy(w.name,d->ent[f].name); + + if (check) + { + if (STREQ("E2M1",d->ent[f].name)) + e2m1=TRUE; + + if (STREQ("MAP01",d->ent[f].name)) + map01=TRUE; + } + + ListInsert(waddir,&w); + } + + /* Shareware checks fo IWAD files + */ + if (check) + switch(level_style) + { + case DOOM_LEVELS: + case ULTIMATE_DOOM_LEVELS: + if (e2m1) + break; + case DOOM_2_LEVELS: + if (map01) + break; + default: + GFX_exit(EXIT_FAILURE, + "You MUST have an IWAD from the registered " + "version of\nDOOM, ULTIMATE DOOM, DOOM II " + "or FINAL DOOM\n"); + break; + } + + Release(d->ent); + Release(d); + + ERR(WAD_OK,WAD_OK); +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ + +int AddIWAD(char *wad) +{ + return (AddWAD(wad,"IWAD")); +} + + +int AddPWAD(char *wad) +{ + return (AddWAD(wad,"PWAD")); +} + + +int CloseWad(char *wad) +{ + WadDir *w; + Iterator i; + + if (!(i=ListFindElem(wadlist,FindWAD,wad))) + ERR(WAD_FILE_NOT_FOUND,WAD_FILE_NOT_FOUND); + + i=IteratorDelete(i); + IteratorClear(i); + + i=ListIterator(waddir); + + while(i) + { + w=IteratorData(i); + + if (strcmp(w->wad,wad)==0) + i=IteratorDelete(i); + else + i=IteratorNext(i); + } + + IteratorClear(i); + + ERR(WAD_OK,WAD_OK); +} + + +char *OpenWads(void) +{ + Iterator i; + WadFile *w; + char *ret; + + if (!(i=ListIterator(wadlist))) + ret=Strdup(""); + else + { + w=IteratorData(i); + ret=Grab(PATH_MAX+1); + strcpy(ret,w->path); + i=IteratorNext(i); + + while(i) + { + strcat(ret,"|"); + w=IteratorData(i); + ret=ReGrab(ret,strlen(ret)+PATH_MAX+1); + strcat(ret,w->path); + i=IteratorNext(i); + } + } + + return(ret); +} + + +Iterator GetWadDir(void) +{ + return(ListIterator(waddir)); +} + + +int GetWadDirSize(void) +{ + return(ListSize(waddir)); +} + + +void *GetLump(char *name, Long *size) +{ + WadDir *d; + void *ret; + + if (size) + *size=0; + + if (!(d=GetDir(name))) + ERR(WAD_LUMP_NOT_FOUND,NULL); + + if ((ret=LoadDirEnt(d,size))) + ERR(WAD_OK,ret); + else + ERR(WAD_FILE_NOT_FOUND,NULL); +} + + +WadMap *LoadMap(char *name) +{ + Iterator i; + WadMap *map; + WadDir *dir; + WadFile *wf; + Thing thing; + Vertex vertex; + Sidedef sidedef; + Linedef linedef; + Sector sector; + int f; + + if (!(i=ListFindElem(waddir,FindDirEnt,name))) + ERR(WAD_MAP_NOT_FOUND,NULL); + + dir=IteratorData(i); + if (!(wf=GetWADFile(dir->wad))) + ERR(WAD_FILE_NOT_FOUND,NULL); + + map=Grab(sizeof(WadMap)); + map->thing=MapNew(sizeof(Thing)); + map->vertex=MapNew(sizeof(Vertex)); + map->sidedef=MapNew(sizeof(Sidedef)); + map->linedef=MapNew(sizeof(Linedef)); + map->sector=MapNew(sizeof(Sector)); + + /* Step through the items following the map in the dir to load the + lumps for the level in. + */ + while(TRUE) + { + i=IteratorNext(i); + dir=IteratorData(i); + + if (!IsMapLump(dir->name)) + ERR(WAD_OK,map); + + switch (HandledMapLump(dir->name)) + { + case THING_LUMP: + fseek(wf->fp,(long)dir->off,SEEK_SET); + + for(f=0;f<dir->size/THING_SIZE;f++) + { + thing.x=GetShort(wf->fp); + thing.y=GetShort(wf->fp); + thing.ang=GetShort(wf->fp); + thing.type=GetShort(wf->fp); + thing.opt=GetShort(wf->fp); + + MapAdd(map->thing,f,&thing); + } + break; + + case VERTEX_LUMP: + fseek(wf->fp,(long)dir->off,SEEK_SET); + + for(f=0;f<dir->size/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;f<dir->size/SIDEDEF_SIZE;f++) + { + sidedef.x=GetShort(wf->fp); + sidedef.y=GetShort(wf->fp); + strcpy(sidedef.upper,GetName(wf->fp)); + strcpy(sidedef.lower,GetName(wf->fp)); + strcpy(sidedef.middle,GetName(wf->fp)); + sidedef.sector=GetShort(wf->fp); + MapAdd(map->sidedef,f,&sidedef); + } + break; + + case LINEDEF_LUMP: + fseek(wf->fp,(long)dir->off,SEEK_SET); + + for(f=0;f<dir->size/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;f<dir->size/SECTOR_SIZE;f++) + { + sector.floor=GetShort(wf->fp); + sector.ceiling=GetShort(wf->fp); + strcpy(sector.floor_t,GetName(wf->fp)); + strcpy(sector.ceiling_t,GetName(wf->fp)); + sector.light=GetShort(wf->fp); + sector.special=GetShort(wf->fp); + sector.tag=GetShort(wf->fp); + MapAdd(map->sector,f,§or); + } + break; + + default: + break; + } + } + + ERR(WAD_OK,map); +} + + +WadMap *NewMap(void) +{ + WadMap *map; + + map=Grab(sizeof(WadMap)); + map->thing=MapNew(sizeof(Thing)); + map->vertex=MapNew(sizeof(Vertex)); + map->sidedef=MapNew(sizeof(Sidedef)); + map->linedef=MapNew(sizeof(Linedef)); + map->sector=MapNew(sizeof(Sector)); + + return(map); +} + + +WadMap *ClearMap(WadMap *map) +{ + MapClear(map->thing); + MapClear(map->vertex); + MapClear(map->sidedef); + MapClear(map->linedef); + MapClear(map->sector); + Release(map); + return(NULL); +} + + +int SaveMap(WadMap *map, char *name, char *wad) +{ + FILE *fp; + Long off; + int f; + + if (!(fp=fopen(wad,"wb"))) + ERR(WAD_COULD_NOT_CREATE,WAD_COULD_NOT_CREATE); + + off=MapSize(map->vertex)*VERTEX_SIZE+ + MapSize(map->sidedef)*SIDEDEF_SIZE+ + MapSize(map->linedef)*LINEDEF_SIZE+ + MapSize(map->sector)*SECTOR_SIZE+ + MapSize(map->thing)*THING_SIZE+12; + + /* Put PWAD header + */ + fputs("PWAD",fp); + PutLong(fp,10); + PutLong(fp,off); + + /* Put THINGS + */ + for(f=0;f<MapSize(map->thing);f++) + { + Thing *t; + + t=MapElem(map->thing,f); + PutShort(fp,t->x); + PutShort(fp,t->y); + PutShort(fp,t->ang); + PutShort(fp,t->type); + PutShort(fp,t->opt); + } + + /* Put LINEDEFS + */ + for(f=0;f<MapSize(map->linedef);f++) + { + Linedef *l; + + l=MapElem(map->linedef,f); + PutShort(fp,l->from); + PutShort(fp,l->to); + PutShort(fp,l->flags); + PutShort(fp,l->type); + PutShort(fp,l->tag); + PutShort(fp,l->right); + PutShort(fp,l->left); + } + + /* Put SIDEDEFS + */ + for(f=0;f<MapSize(map->sidedef);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;f<MapSize(map->vertex);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;f<MapSize(map->sector);f++) + { + Sector *s; + + s=MapElem(map->sector,f); + PutShort(fp,s->floor); + PutShort(fp,s->ceiling); + PutName(fp,s->floor_t); + PutName(fp,s->ceiling_t); + PutShort(fp,s->light); + PutShort(fp,s->special); + PutShort(fp,s->tag); + } + + /* Skip REJECT, BLOCKMAP + */ + + /* Create directory + */ + off=12; + + PutDirEnt(fp,off,0,name); + + PutDirEnt(fp,off,MapSize(map->thing)*THING_SIZE,"THINGS"); + off+=MapSize(map->thing)*THING_SIZE; + + PutDirEnt(fp,off,MapSize(map->linedef)*LINEDEF_SIZE,"LINEDEFS"); + off+=MapSize(map->linedef)*LINEDEF_SIZE; + + PutDirEnt(fp,off,MapSize(map->sidedef)*SIDEDEF_SIZE,"SIDEDEFS"); + off+=MapSize(map->sidedef)*SIDEDEF_SIZE; + + PutDirEnt(fp,off,MapSize(map->vertex)*VERTEX_SIZE,"VERTEXES"); + off+=MapSize(map->vertex)*VERTEX_SIZE; + + PutDirEnt(fp,off,0,"SEGS"); + PutDirEnt(fp,off,0,"SSECTORS"); + PutDirEnt(fp,off,0,"NODES"); + + PutDirEnt(fp,off,MapSize(map->sector)*SECTOR_SIZE,"SECTORS"); + off+=MapSize(map->sector)*SECTOR_SIZE; + + PutDirEnt(fp,off,0,"REJECT"); + PutDirEnt(fp,off,0,"BLOCKMAP"); + + fclose(fp); + + ERR(WAD_OK,WAD_OK); +} + + +int WadError(void) +{ + return(wad_err); +} + + +const char *WadErrorString(void) +{ + return(wad_errstr[wad_err]); +} + +/* END OF FILE */ @@ -0,0 +1,242 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + WAD file definitions and readers + + These things should be noted about the handling of mutiple entries + from different wad files: + + - Entries in later WADs overwrite earlier loaded WADs. + + - New entries for MAPxy and ExMy automatically overwrite the + following entries from the previous map: + THINGS + LINEDEFS + SIDEDEFS + VERTEXES + SEGS + SSECTORS + NODES + SECTORS + REJECT + BLOCKMAP + + If these entries don't appear in the new map they are + replaced by dummy entries of zero length. + + $Id$ + +*/ + +#ifndef _WAD_H + +#define _WAD_H + +#include "map.h" +#include "list.h" + +/* Basic WAD types +*/ +#define DIRNAME_LEN 8 +typedef char DirName[DIRNAME_LEN+1]; + +/* Directory types +*/ +typedef struct WadDir + { + char *wad; /* WAD the entry is from */ + DirName name; /* Lump name */ + Long off; /* Lump offset */ + Long size; /* Lump size */ + } WadDir; + + +/* Base level types and their sizes in the WAD +*/ +#define THING_SIZE (sizeof(Short)*5) + +typedef struct Thing + { + Short x; + Short y; + Short ang; + Short type; + Short opt; + } Thing; + +#define VERTEX_SIZE (sizeof(Short)*2) + +typedef struct Vertex + { + Short x; + Short y; + } Vertex; + +#define SIDEDEF_SIZE (sizeof(Short)*3+DIRNAME_LEN*3) + +typedef struct Sidedef + { + Short x; + Short y; + DirName upper; + DirName lower; + DirName middle; + Short sector; + } Sidedef; + +#define LINEDEF_SIZE (sizeof(Short)*7) + +typedef struct + { + Short from; + Short to; + Short flags; + Short type; + Short tag; + Short right; + Short left; + } Linedef; + +#define SECTOR_SIZE (sizeof(Short)*5+DIRNAME_LEN*2) + +typedef struct Sector + { + Short floor; + Short ceiling; + DirName floor_t; + DirName ceiling_t; + Short light; + Short special; + Short tag; + } Sector; + +typedef struct WadMap + { + Map thing; + Map vertex; + Map linedef; + Map sidedef; + Map sector; + } WadMap; + + +/* Error codes +*/ +#define WAD_OK 0 +#define WAD_FILE_NOT_FOUND 1 +#define WAD_NOT_WAD 2 +#define WAD_NOT_IWAD 3 +#define WAD_NOT_PWAD 4 +#define WAD_MAP_NOT_FOUND 5 +#define WAD_LUMP_NOT_FOUND 6 +#define WAD_COULD_NOT_CREATE 7 +#define WAD_BROKEN 8 /* Must be last error code */ + +#define WAD_NOERROR (WAD_BROKEN+1) + + +/* Add the named IWAD to the list of open WADs. Returns non-zero on error. +*/ +int AddIWAD(char *wad); + + +/* Add the named PWAD to the list of open WADs. Returns non-zero on error. + AddPWAD() and AddIWAD() are by and large identical - they just include + different checking so that the initial loading of IWAD will not allow it + be a PWAD, and also do shareware checking. +*/ +int AddPWAD(char *wad); + + +/* Close a wad from the open list. Removes entries for this wad fom the + global directory, replacing entries from prevous WADs (if any). + + Returns non-zero on error. +*/ +int CloseWad(char *wad); + + +/* Returns a list of open WADS as a string like "<wad>|<wad>|..". The return + must be Release()ed after use. +*/ +char *OpenWads(void); + + +/* If you wish access to the directory of all the open wads, this allows + them to retrieved as a List of WadDir. Returns NULL if none. + + Note the directory is organised with the last loaded WAD files first. + This is the quickest (though hungriest) method for ensuring that later + WAD resources override earlier ones. +*/ +Iterator GetWadDir(void); + +/* No of entries in WadDir list +*/ +int GetWadDirSize(void); + + +/* Retrieves the named lump from the WADs. Return is a pointer to size + bytes. If size is NULL it is not set. + + The pointer must be Release()'ed by the user afterwards. + + NULL indicates the lump could not be found. +*/ +void *GetLump(char *name, Long *size); + + +/* Load a MAPxx or ExMy map from the open wads. Returns NULL on error. +*/ +WadMap *LoadMap(char *name); + + +/* Create a new empty map +*/ +WadMap *NewMap(void); + + +/* Release the memory for a WadMap +*/ +WadMap *ClearMap(WadMap *map); + + +/* Save the passed WadMap as a MAPxx or ExMy PWAD. Note that this PWAD is + overwritten and the map is the sole object written to the PWAD. Returns + non-zero on error. +*/ +int SaveMap(WadMap *map, char *name, char *wad); + + +/* Return the current error code +*/ +int WadError(void); + + +/* Return a string for the error code +*/ +const char *WadErrorString(void); + + +#endif + +/* END OF FILE */ diff --git a/waddir.c b/waddir.c new file mode 100644 index 0000000..d7bf4ae --- /dev/null +++ b/waddir.c @@ -0,0 +1,75 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Tester for routines in wad.c + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <stdio.h> + +#include "wad.h" +#include "gfx.h" +#include "mem.h" +#include "file.h" + +#define SCRW 640 +#define SCRH 480 + + +/* ---------------------------------------- MAIN +*/ +int viDOOM(int argc,char *argv[]) +{ + Iterator i; + + if (argc<2) + GFX_exit(1,"usage:%s wad\n",argv[0]); + + LoadGlobals(); + + if (AddIWAD(argv[1])!=WAD_OK) + if (AddPWAD(argv[1])!=WAD_OK) + GFX_exit(1,"wadderr=%s\n",WadErrorString()); + + i=GetWadDir(); + + while(i) + { + WadDir *w; + + w=IteratorData(i); + + printf("%-10s 0x%.8x 0x%.8x %s\n", + w->name,w->off,w->size,Basename(w->wad)); + + i=IteratorNext(i); + } + + return(0); +} + + +/* END OF FILE */ |