2825 lines
72 KiB
Diff
2825 lines
72 KiB
Diff
diff -u -r -N yadex-1.7.0/atclib/al_adigits.c yadex-1.7.0-all/atclib/al_adigits.c
|
||
--- yadex-1.7.0/atclib/al_adigits.c 1999-08-02 00:52:00.000000000 +1000
|
||
+++ yadex-1.7.0-all/atclib/al_adigits.c 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -29,5 +29,11 @@
|
||
#include "atclib.h"
|
||
|
||
|
||
-const char al_adigits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||
+const char al_adigits[36] =
|
||
+{
|
||
+'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||
+'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||
+'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||
+'U', 'V', 'W', 'X', 'Y', 'Z'
|
||
+};
|
||
|
||
diff -u -r -N yadex-1.7.0/docsrc/index.html yadex-1.7.0-all/docsrc/index.html
|
||
--- yadex-1.7.0/docsrc/index.html 2002-05-09 23:36:06.000000000 +1000
|
||
+++ yadex-1.7.0-all/docsrc/index.html 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -34,6 +34,7 @@
|
||
|
||
<ul>
|
||
<li><a href="palette.html">Palette viewer</a>
|
||
+<li><a href="preview.html">3D Level Preview</a>
|
||
<li><a href="advanced.html">Advanced user's guide</a>
|
||
<li><a href="../TODO"><code>TODO</code></a>
|
||
<li><a href="yadex.6">The man page for Yadex</a>
|
||
diff -u -r -N yadex-1.7.0/docsrc/preview.html yadex-1.7.0-all/docsrc/preview.html
|
||
--- yadex-1.7.0/docsrc/preview.html 1970-01-01 10:00:00.000000000 +1000
|
||
+++ yadex-1.7.0-all/docsrc/preview.html 2005-01-10 14:34:20.000000000 +1100
|
||
@@ -0,0 +1,108 @@
|
||
+<html>
|
||
+<head>
|
||
+<title>Yadex 3D level preview</title>
|
||
+</head>
|
||
+<body>
|
||
+
|
||
+<div align="center">
|
||
+<img src="logo_small.png" alt="Fancy logo">
|
||
+<br>Yadex $VERSION ($SOURCE_DATE)
|
||
+<h1>3D Level Preview</h1>
|
||
+</div>
|
||
+<br>
|
||
+<br>
|
||
+<br>
|
||
+
|
||
+ <h2>What's it for</h2>
|
||
+
|
||
+<p>The 3D level preview function lets you get a rough idea of what
|
||
+your level looks like, quickly, without all the hassle of saving,
|
||
+building nodes and starting DOOM. It is activated by pressing the
|
||
+`R' key while editing a level, and draws the player's view that
|
||
+you would see within DOOM (with some limitations). While the
|
||
+rendering window is up, you can move around the level using the
|
||
+cursor keys and toggle things like texturing and sprites on/off.
|
||
+
|
||
+ <h2>Key bindings</h2>
|
||
+
|
||
+<dl>
|
||
+<dt>[<kbd>Left</kbd>]
|
||
+<br>[<kbd>Right</kbd>]
|
||
+<dd>Turn the view left or right. Use the SHIFT key to
|
||
+turn a greater amount.
|
||
+
|
||
+<dt>[<kbd>Up</kbd>]
|
||
+<br>[<kbd>Down</kbd>]
|
||
+<dd>Move the view forward or back. Use the SHIFT key to
|
||
+move a greater distance.
|
||
+
|
||
+<dt>[<kbd>n</kbd>]
|
||
+<br>[<kbd>m</kbd>]
|
||
+<dd>Move the view sideways left or right (strafing). Uppercase `N'
|
||
+and `M' (i.e. with the SHIFT key) will move a greater distance.
|
||
+
|
||
+<dt>[<kbd>c</kbd>]
|
||
+<br>[<kbd>d</kbd>]
|
||
+<dd>Move the view upwards or downwards (flying). Uppercase `C' and
|
||
+`D' (i.e. with the SHIFT key) will move a greater distance. Note
|
||
+that you cannot move up or down when "walking" mode is enabled.
|
||
+
|
||
+<dt>[<kbd>t</kbd>]
|
||
+<dd>Toggle texture mapping. When disabled (the default), all walls,
|
||
+ceilings and floors are drawn with solid (somewhat random) colours.
|
||
+
|
||
+<dt>[<kbd>s</kbd>]
|
||
+<dd>Toggle sprites.
|
||
+
|
||
+<dt>[<kbd>w</kbd>]
|
||
+<dd>Toggle walking mode. When enabled, the view height is always
|
||
+above the current floor. For example, if you move forward over a
|
||
+cliff, the view will drop down. When disabled (the default), you can
|
||
+fly about the level at any height.
|
||
+
|
||
+<dt>[<kbd>Esc</kbd>]
|
||
+<br>[<kbd>q</kbd>]
|
||
+<dd>Exit the 3D level preview. The current viewing state (position,
|
||
+direction, etc) are remembered, and will be used next time the 3D
|
||
+preview is activated (unless the player object has been moved, or a
|
||
+different level was loaded).
|
||
+
|
||
+</dl>
|
||
+
|
||
+ <h2>Features</h2>
|
||
+
|
||
+<ul>
|
||
+<li>No BSP (nodes) required !
|
||
+<li>Textures and flats are drawn exactly like DOOM, including X/Y
|
||
+offsets and upper/lower unpegging flags.
|
||
+<li>Sky is handled just like in DOOM (but drawn in solid blue).
|
||
+</ul>
|
||
+
|
||
+ <h2>Limitations</h2>
|
||
+
|
||
+<ul>
|
||
+<li>No lighting, the level appears full-bright all the time.
|
||
+<li>No mid-masked textures (rails, gratings) are drawn.
|
||
+<li>Thing sprites (especially monsters) are always drawn facing
|
||
+you, even when their direction is away from you.
|
||
+<li>Sprite positioning may be inaccurate, because their X and
|
||
+Y offsets are not honoured.
|
||
+<li>Things that are supposed to hang from the ceiling
|
||
+(hanging body parts, chandeliers, etc) will appear on the floor.
|
||
+<li>There are some glitches in the current renderer, which look like
|
||
+"slimetrails" (vertical lines).
|
||
+</ul>
|
||
+
|
||
+ <h2>Caveats</h2>
|
||
+
|
||
+One last thing. The 3D preview function can use a huge amount of
|
||
+memory when texturing and sprites are both enabled (and a large amount
|
||
+even when texturing and sprites are both disabled). If your computer
|
||
+has a very low amount of memory (e.g. less than 16 MB), then Yadex may
|
||
+crash with an out of memory error. I think you are unlikely to hit
|
||
+this problem, but if in doubt, save your work first.
|
||
+
|
||
+
|
||
+<p><hr>AJA $SELF_DATE
|
||
+</body>
|
||
+</html>
|
||
diff -u -r -N yadex-1.7.0/GNUmakefile yadex-1.7.0-all/GNUmakefile
|
||
--- yadex-1.7.0/GNUmakefile 2003-12-29 04:23:56.000000000 +1100
|
||
+++ yadex-1.7.0-all/GNUmakefile 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -160,6 +160,7 @@
|
||
s_swapf s_vertices sanity scrnshot \
|
||
selbox selectn selpath selrect \
|
||
serialnum spritdir sticker swapmem \
|
||
+ r_render r_images \
|
||
t_centre t_flags t_prop t_spin \
|
||
textures things trace v_centre \
|
||
v_merge v_polyg vectext verbmsg \
|
||
@@ -237,6 +238,7 @@
|
||
docsrc/legal.html \
|
||
docsrc/packagers_guide.html \
|
||
docsrc/palette.html \
|
||
+ docsrc/preview.html \
|
||
docsrc/reporting.html \
|
||
docsrc/tips.html \
|
||
docsrc/trivia.html \
|
||
@@ -609,8 +611,9 @@
|
||
#
|
||
########################################################################
|
||
|
||
-# If Makefile.config doesn't exist, give a hint...
|
||
+# If Makefile.config or config.h don't exist, give a hint...
|
||
$(OBJDIR)/Makefile.config:
|
||
+$(OBJDIR)/config.h:
|
||
@echo "Sorry guv'nor, but... did you run ./configure ?" >&2
|
||
@false
|
||
|
||
@@ -637,7 +640,7 @@
|
||
# Note: the modules of Atclib are not scanned as they all
|
||
# depend on $(HEADERS_ATCLIB) and nothing else.
|
||
|
||
-yadex.dep: $(SRC_NON_GEN)
|
||
+yadex.dep: $(SRC_NON_GEN) src/config.h
|
||
@echo "Generating $@"
|
||
@makedepend -f- -Y -Iatclib $(SRC_NON_GEN) 2>/dev/null \
|
||
| awk 'sub (/^src/, "") == 1 { \
|
||
diff -u -r -N yadex-1.7.0/src/editloop.cc yadex-1.7.0-all/src/editloop.cc
|
||
--- yadex-1.7.0/src/editloop.cc 2003-07-05 21:12:32.000000000 +1000
|
||
+++ yadex-1.7.0-all/src/editloop.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -70,6 +70,7 @@
|
||
#include "x_exchng.h"
|
||
#include "x_hover.h"
|
||
#include "xref.h"
|
||
+#include "r_render.h"
|
||
|
||
#ifdef Y_X11
|
||
#include <X11/Xlib.h>
|
||
@@ -304,8 +305,8 @@
|
||
|
||
e.mb_menu[MBM_EDIT] = new Menu (NULL,
|
||
"~Copy object(s)", 'o', 0,
|
||
- "~Add object", YK_INS, 0,
|
||
- "~Delete object(s)", YK_DEL, 0,
|
||
+ "~Add object", 'I', 0,
|
||
+ "~Delete object(s)", '\b', 0,
|
||
"~Exchange object numbers", 24, 0,
|
||
"~Preferences...", YK_F5, 0,
|
||
"~Snap to grid", 'y', MIF_VTICK, &e.grid_snap, 0,
|
||
@@ -342,6 +343,7 @@
|
||
"~Next object", 'n', 0,
|
||
"~Prev object", 'p', 0,
|
||
"~Jump to object...", 'j', 0,
|
||
+ "~Find by type", 'f', 0,
|
||
NULL);
|
||
|
||
e.mb_menu[MBM_MISC_L] = new Menu ("Misc. operations",
|
||
@@ -1344,8 +1346,8 @@
|
||
}
|
||
}
|
||
|
||
- // [F8]: pop up the "Misc. operations" menu
|
||
- else if (is.key == YK_F8
|
||
+ // [M]: pop up the "Misc. operations" menu
|
||
+ else if (is.key == 'M'
|
||
&& e.menubar->highlighted () < 0)
|
||
{
|
||
e.modpopup->set (e.menubar->get_menu (MBI_MISC), 1);
|
||
@@ -1706,7 +1708,15 @@
|
||
select_linedefs_path (&e.Selected, e.highlighted.num, YS_TOGGLE);
|
||
RedrawMap = 1;
|
||
}
|
||
-
|
||
+ // [E]: add linedef and split sector -- [AJA]
|
||
+ else if (is.key == 'E' && e.obj_type == OBJ_VERTICES)
|
||
+ {
|
||
+ if (e.Selected)
|
||
+ {
|
||
+ MiscOperations (e.obj_type, &e.Selected, 5);
|
||
+ RedrawMap = 1;
|
||
+ }
|
||
+ }
|
||
// [E]: Select/unselect all 1s linedefs in path
|
||
else if (is.key == 'E' && e.highlighted._is_linedef ())
|
||
{
|
||
@@ -1834,6 +1844,56 @@
|
||
RedrawMap = 1;
|
||
}
|
||
|
||
+ // [f]: find object by type
|
||
+ else if (is.key == 'f' && (! e.global || e.highlighted ()))
|
||
+ {
|
||
+ Objid find_obj;
|
||
+ int otype;
|
||
+ obj_no_t omax,onum;
|
||
+ find_obj.type = e.highlighted () ? e.highlighted.type : e.obj_type;
|
||
+ onum = find_obj.num = e.highlighted () ? e.highlighted.num : 0;
|
||
+ omax = GetMaxObjectNum(find_obj.type);
|
||
+ switch (find_obj.type)
|
||
+ {
|
||
+ case OBJ_SECTORS:
|
||
+ if ( ! InputSectorType( 84, 21, &otype))
|
||
+ {
|
||
+ for (onum = e.highlighted () ? onum + 1 : onum; onum <= omax; onum++)
|
||
+ if (Sectors[onum].special == (wad_stype_t) otype)
|
||
+ {
|
||
+ find_obj.num = onum;
|
||
+ GoToObject(find_obj);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ break;
|
||
+ case OBJ_THINGS:
|
||
+ if ( ! InputThingType( 42, 21, &otype))
|
||
+ {
|
||
+ for (onum = e.highlighted () ? onum + 1 : onum; onum <= omax; onum++)
|
||
+ if (Things[onum].type == (wad_ttype_t) otype)
|
||
+ {
|
||
+ find_obj.num = onum;
|
||
+ GoToObject(find_obj);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ break;
|
||
+ case OBJ_LINEDEFS:
|
||
+ if ( ! InputLinedefType( 0, 21, &otype))
|
||
+ {
|
||
+ for (onum = e.highlighted () ? onum + 1 : onum; onum <= omax; onum++)
|
||
+ if (LineDefs[onum].type == (wad_ldtype_t) otype)
|
||
+ {
|
||
+ find_obj.num = onum;
|
||
+ GoToObject(find_obj);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+ RedrawMap = 1;
|
||
+ }
|
||
#if 0
|
||
// [c]: clear selection and redraw the map
|
||
else if (is.key == 'c')
|
||
@@ -1921,6 +1981,17 @@
|
||
StretchSelBox = false;
|
||
}
|
||
|
||
+ // [w]: split sector between vertices
|
||
+ else if (is.key == 'w' && e.obj_type == OBJ_VERTICES
|
||
+ && e.Selected && e.Selected->next && ! e.Selected->next->next)
|
||
+ {
|
||
+ SplitSector (e.Selected->next->objnum, e.Selected->objnum);
|
||
+ ForgetSelection (&e.Selected);
|
||
+ RedrawMap = 1;
|
||
+ DragObject = false;
|
||
+ StretchSelBox = false;
|
||
+ }
|
||
+
|
||
// [x]: spin things 1/8 turn clockwise
|
||
else if (is.key == 'x' && e.obj_type == OBJ_THINGS
|
||
&& (e.Selected || e.highlighted ()))
|
||
@@ -1987,7 +2058,7 @@
|
||
}
|
||
|
||
// [Del]: delete the current object
|
||
- else if (is.key == YK_DEL
|
||
+ else if (is.key == '\b'
|
||
&& (e.Selected || e.highlighted ())) /* 'Del' */
|
||
{
|
||
if (e.obj_type == OBJ_THINGS
|
||
@@ -2015,7 +2086,7 @@
|
||
}
|
||
|
||
// [Ins]: insert a new object
|
||
- else if (is.key == YK_INS || is.key == YK_INS + YK_SHIFT) /* 'Ins' */
|
||
+ else if (is.key == 'I' || is.key == YK_INS + YK_SHIFT) /* 'Ins' */
|
||
{
|
||
SelPtr cur;
|
||
int prev_obj_type = e.obj_type;
|
||
@@ -2201,12 +2272,34 @@
|
||
RedrawMap = 1;
|
||
}
|
||
|
||
+ // [Z] Set sector on surrounding linedefs (AJA)
|
||
+ else if (is.key == 'Z' && e.pointer_in_window)
|
||
+ {
|
||
+ if (e.obj_type == OBJ_SECTORS && e.Selected)
|
||
+ {
|
||
+ SuperSectorSelector (e.pointer_x, e.pointer_y,
|
||
+ e.Selected->objnum);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ SuperSectorSelector (e.pointer_x, e.pointer_y, OBJ_NO_NONE);
|
||
+ }
|
||
+ RedrawMap = 1;
|
||
+ }
|
||
+
|
||
// [!] Debug info (not documented)
|
||
else if (is.key == '!')
|
||
{
|
||
DumpSelection (e.Selected);
|
||
}
|
||
|
||
+ // [R] Render 3D view (AJA)
|
||
+ else if (is.key == 'R')
|
||
+ {
|
||
+ Render3D ();
|
||
+ RedrawMap = 1;
|
||
+ }
|
||
+
|
||
// [@] Show font (not documented)
|
||
else if (is.key == '@')
|
||
{
|
||
@@ -2214,6 +2307,30 @@
|
||
RedrawMap = 1;
|
||
}
|
||
|
||
+ // [T] Transfer properties to selected objects (AJA)
|
||
+ else if (is.key == 'T' && e.Selected
|
||
+ && e.highlighted.num >= 0)
|
||
+ {
|
||
+ switch (e.obj_type)
|
||
+ {
|
||
+ case OBJ_SECTORS:
|
||
+ TransferSectorProperties (e.highlighted.num, e.Selected);
|
||
+ RedrawMap = 1;
|
||
+ break;
|
||
+ case OBJ_THINGS:
|
||
+ TransferThingProperties (e.highlighted.num, e.Selected);
|
||
+ RedrawMap = 1;
|
||
+ break;
|
||
+ case OBJ_LINEDEFS:
|
||
+ TransferLinedefProperties (e.highlighted.num, e.Selected);
|
||
+ RedrawMap = 1;
|
||
+ break;
|
||
+ default:
|
||
+ Beep ();
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
// [|] Show colours (not documented)
|
||
else if (is.key == '|')
|
||
{
|
||
diff -u -r -N yadex-1.7.0/src/editloop.h yadex-1.7.0-all/src/editloop.h
|
||
--- yadex-1.7.0/src/editloop.h 2000-01-11 00:40:12.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/editloop.h 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -6,6 +6,9 @@
|
||
|
||
void EditorLoop (const char *); /* SWAP! */
|
||
const char *SelectLevel (int levelno);
|
||
+extern int InputSectorType(int x0, int y0, int *number);
|
||
+extern int InputLinedefType(int x0, int y0, int *number);
|
||
+extern int InputThingType(int x0, int y0, int *number);
|
||
|
||
|
||
|
||
diff -u -r -N yadex-1.7.0/src/gcolour1.cc yadex-1.7.0-all/src/gcolour1.cc
|
||
--- yadex-1.7.0/src/gcolour1.cc 2003-03-28 23:37:32.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/gcolour1.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -127,6 +127,21 @@
|
||
}
|
||
verbmsg ("colours: colour %d remapped to %d (delta %d)\n",
|
||
IMG_TRANSP, colour0, smallest_delta);
|
||
+
|
||
+ rgb_c med_blue (0, 0, 128);
|
||
+ sky_colour = 0;
|
||
+ smallest_delta = INT_MAX;
|
||
+
|
||
+ for (size_t n = 0; n < DOOM_COLOURS; n++)
|
||
+ {
|
||
+ int delta = med_blue - rgb_values[n];
|
||
+ if (delta < smallest_delta)
|
||
+ {
|
||
+ sky_colour = n;
|
||
+ smallest_delta = delta;
|
||
+ }
|
||
+ }
|
||
+ verbmsg ("Sky Colour remapped to %d (delta %d)\n", sky_colour, smallest_delta);
|
||
}
|
||
|
||
#endif
|
||
diff -u -r -N yadex-1.7.0/src/gcolour2.cc yadex-1.7.0-all/src/gcolour2.cc
|
||
--- yadex-1.7.0/src/gcolour2.cc 2003-03-28 23:37:32.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/gcolour2.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -35,4 +35,5 @@
|
||
|
||
pcolour_t *game_colour = 0; // Pixel values for the DOOM_COLOURS game clrs.
|
||
int colour0; // Game colour to which g. colour 0 is remapped
|
||
+int sky_colour; // Game colour for a medium sky blue
|
||
|
||
diff -u -r -N yadex-1.7.0/src/gcolour2.h yadex-1.7.0-all/src/gcolour2.h
|
||
--- yadex-1.7.0/src/gcolour2.h 2000-08-11 07:18:16.000000000 +1000
|
||
+++ yadex-1.7.0-all/src/gcolour2.h 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -10,4 +10,5 @@
|
||
|
||
extern pcolour_t *game_colour; // Pixel values for the DOOM_COLOURS game clrs.
|
||
extern int colour0; // Game colour to which g. colour 0 is remapped
|
||
+extern int sky_colour; // Game colour for a medium blue sky
|
||
|
||
diff -u -r -N yadex-1.7.0/src/l_prop.cc yadex-1.7.0-all/src/l_prop.cc
|
||
--- yadex-1.7.0/src/l_prop.cc 2003-03-28 23:37:32.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/l_prop.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -105,7 +105,7 @@
|
||
* Prototypes of private functions
|
||
*/
|
||
static char *GetTaggedLineDefFlag (int linedefnum, int flagndx);
|
||
-static int InputLinedefType (int x0, int y0, int *number);
|
||
+int InputLinedefType (int x0, int y0, int *number);
|
||
static const char *PrintLdtgroup (void *ptr);
|
||
|
||
|
||
@@ -475,7 +475,7 @@
|
||
* Let the user select a linedef type number and return it.
|
||
* Returns 0 if OK, <>0 if cancelled
|
||
*/
|
||
-static int InputLinedefType (int x0, int y0, int *number)
|
||
+int InputLinedefType (int x0, int y0, int *number)
|
||
{
|
||
int r;
|
||
int ldtgno = 0;
|
||
@@ -547,3 +547,37 @@
|
||
return ((ldtgroup_t *)ptr)->desc;
|
||
}
|
||
|
||
+/*
|
||
+ * TransferLinedefProperties
|
||
+ *
|
||
+ * Note: right now nothing is done about sidedefs. Being able to
|
||
+ * (intelligently) transfer sidedef properties from source line to
|
||
+ * destination linedefs could be a useful feature -- though it is
|
||
+ * unclear the best way to do it. OTOH not touching sidedefs might
|
||
+ * be useful too.
|
||
+ *
|
||
+ * -AJA- 2001-05-27
|
||
+ */
|
||
+#define LINEDEF_FLAG_KEEP (1 + 4)
|
||
+
|
||
+void TransferLinedefProperties (int src_linedef, SelPtr linedefs)
|
||
+{
|
||
+ SelPtr cur;
|
||
+ wad_ldflags_t src_flags = LineDefs[src_linedef].flags & ~LINEDEF_FLAG_KEEP;
|
||
+
|
||
+ for (cur=linedefs; cur; cur=cur->next)
|
||
+ {
|
||
+ if (! is_obj(cur->objnum))
|
||
+ continue;
|
||
+
|
||
+ // don't transfer certain flags
|
||
+ LineDefs[cur->objnum].flags &= LINEDEF_FLAG_KEEP;
|
||
+ LineDefs[cur->objnum].flags |= src_flags;
|
||
+
|
||
+ LineDefs[cur->objnum].type = LineDefs[src_linedef].type;
|
||
+ LineDefs[cur->objnum].tag = LineDefs[src_linedef].tag;
|
||
+
|
||
+ MadeChanges = 1;
|
||
+ }
|
||
+}
|
||
+
|
||
diff -u -r -N yadex-1.7.0/src/r_images.cc yadex-1.7.0-all/src/r_images.cc
|
||
--- yadex-1.7.0/src/r_images.cc 1970-01-01 10:00:00.000000000 +1000
|
||
+++ yadex-1.7.0-all/src/r_images.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -0,0 +1,400 @@
|
||
+/*
|
||
+ * r_images.cc
|
||
+ * AJA 2002-04-23 (based on textures.cc and flats.cc)
|
||
+ */
|
||
+
|
||
+
|
||
+/*
|
||
+This file is part of Yadex.
|
||
+
|
||
+Yadex incorporates code from DEU 5.21 that was put in the public domain in
|
||
+1994 by Rapha<68>l Quinet and Brendon Wyber.
|
||
+
|
||
+The rest of Yadex is Copyright <20> 1997-2000 Andr<64> Majorel.
|
||
+
|
||
+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.
|
||
+*/
|
||
+
|
||
+
|
||
+#include "yadex.h"
|
||
+#ifdef Y_X11
|
||
+#include <X11/Xlib.h>
|
||
+#endif
|
||
+#include "dialog.h"
|
||
+#include "game.h" /* yg_picture_format */
|
||
+#include "gfx.h"
|
||
+#include "levels.h"
|
||
+#include "lists.h"
|
||
+#include "patchdir.h"
|
||
+#include "pic2img.h"
|
||
+#include "sticker.h"
|
||
+#include "flats.h"
|
||
+#include "textures.h"
|
||
+#include "wadfile.h"
|
||
+#include "wads.h"
|
||
+#include "wadres.h"
|
||
+#include "wstructs.h"
|
||
+
|
||
+#include "r_images.h"
|
||
+
|
||
+
|
||
+/*
|
||
+ * flat_list_entry_match
|
||
+ * Function used by bsearch() to locate a particular
|
||
+ * flat in the FTexture.
|
||
+ */
|
||
+static int flat_list_entry_match (const void *key, const void *flat_list_entry)
|
||
+{
|
||
+return y_strnicmp ((const char *) key,
|
||
+ ((const flat_list_entry_t *) flat_list_entry)->name,
|
||
+ WAD_FLAT_NAME);
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ * load a flat into a new image. NULL if not found.
|
||
+ */
|
||
+
|
||
+Img * Flat2Img (const wad_flat_name_t& fname)
|
||
+{
|
||
+char name[WAD_FLAT_NAME + 1];
|
||
+strncpy (name, fname, WAD_FLAT_NAME);
|
||
+name[WAD_FLAT_NAME] = 0;
|
||
+
|
||
+flat_list_entry_t *flat = (flat_list_entry_t *)
|
||
+ bsearch (name, flat_list, NumFTexture, sizeof *flat_list,
|
||
+ flat_list_entry_match);
|
||
+
|
||
+if (! flat) // Not found in list
|
||
+ return 0;
|
||
+
|
||
+int width = DOOM_FLAT_WIDTH; // Big deal !
|
||
+int height = DOOM_FLAT_HEIGHT;
|
||
+
|
||
+const Wad_file *wadfile = flat->wadfile;
|
||
+wadfile->seek (flat->offset);
|
||
+
|
||
+Img *img = new Img (width, height, false);
|
||
+
|
||
+wadfile->read_bytes (img->wbuf (), (long) width * height);
|
||
+
|
||
+return img;
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ * load a wall texture ("TEXTURE1" or "TEXTURE2" object) into an image.
|
||
+ * Returns NULL if not found or error.
|
||
+ */
|
||
+
|
||
+Img * Tex2Img (const wad_tex_name_t& texname)
|
||
+{
|
||
+MDirPtr dir = 0; /* main directory pointer to the TEXTURE* entries */
|
||
+i32 *offsets; /* array of offsets to texture names */
|
||
+int n; /* general counter */
|
||
+i16 width, height; /* size of the texture */
|
||
+i16 npatches; /* number of wall patches used to build this texture */
|
||
+i32 numtex; /* number of texture names in TEXTURE* list */
|
||
+i32 texofs; /* offset in the wad file to the texture data */
|
||
+char tname[WAD_TEX_NAME + 1]; /* texture name */
|
||
+char picname[WAD_PIC_NAME + 1]; /* wall patch name */
|
||
+bool have_dummy_bytes;
|
||
+int header_size;
|
||
+int item_size;
|
||
+
|
||
+char name[WAD_TEX_NAME + 1];
|
||
+strncpy (name, texname, WAD_TEX_NAME);
|
||
+name[WAD_TEX_NAME] = 0;
|
||
+
|
||
+// Iwad-dependant details
|
||
+if (yg_texture_format == YGTF_NAMELESS)
|
||
+ {
|
||
+ have_dummy_bytes = true;
|
||
+ header_size = 14;
|
||
+ item_size = 10;
|
||
+ }
|
||
+else if (yg_texture_format == YGTF_NORMAL)
|
||
+ {
|
||
+ have_dummy_bytes = true;
|
||
+ header_size = 14;
|
||
+ item_size = 10;
|
||
+ }
|
||
+else if (yg_texture_format == YGTF_STRIFE11)
|
||
+ {
|
||
+ have_dummy_bytes = false;
|
||
+ header_size = 10;
|
||
+ item_size = 6;
|
||
+ }
|
||
+else
|
||
+ {
|
||
+ nf_bug ("Bad texture format %d.", (int) yg_texture_format);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+/* offset for texture we want. */
|
||
+texofs = 0;
|
||
+// Doom alpha 0.4 : "TEXTURES", no names
|
||
+if (yg_texture_lumps == YGTL_TEXTURES && yg_texture_format == YGTF_NAMELESS)
|
||
+ {
|
||
+ dir = FindMasterDir (MasterDir, "TEXTURES");
|
||
+ if (dir != NULL)
|
||
+ {
|
||
+ dir->wadfile->seek (dir->dir.start);
|
||
+ dir->wadfile->read_i32 (&numtex);
|
||
+ if (WAD_TEX_NAME < 7) nf_bug ("WAD_TEX_NAME too small"); // Sanity
|
||
+ if (! y_strnicmp (name, "TEX", 3)
|
||
+ && isdigit (name[3])
|
||
+ && isdigit (name[4])
|
||
+ && isdigit (name[5])
|
||
+ && isdigit (name[6])
|
||
+ && name[7] == '\0')
|
||
+ {
|
||
+ long num;
|
||
+ if (sscanf (name + 3, "%4ld", &num) == 1
|
||
+ && num >= 0 && num < numtex)
|
||
+ {
|
||
+ dir->wadfile->seek (dir->dir.start + 4 + 4 * num);
|
||
+ dir->wadfile->read_i32 (&texofs);
|
||
+ texofs += dir->dir.start;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+// Doom alpha 0.5 : only "TEXTURES"
|
||
+else if (yg_texture_lumps == YGTL_TEXTURES
|
||
+ && (yg_texture_format == YGTF_NORMAL || yg_texture_format == YGTF_STRIFE11))
|
||
+ {
|
||
+ // Is it in TEXTURES ?
|
||
+ dir = FindMasterDir (MasterDir, "TEXTURES");
|
||
+ if (dir != NULL) // (Theoretically, it should always exist)
|
||
+ {
|
||
+ dir->wadfile->seek (dir->dir.start);
|
||
+ dir->wadfile->read_i32 (&numtex);
|
||
+ /* read in the offsets for texture1 names and info. */
|
||
+ offsets = (i32 *) GetMemory ((long) numtex * 4);
|
||
+ dir->wadfile->read_i32 (offsets, numtex);
|
||
+ for (n = 0; n < numtex && !texofs; n++)
|
||
+ {
|
||
+ dir->wadfile->seek (dir->dir.start + offsets[n]);
|
||
+ dir->wadfile->read_bytes (&tname, WAD_TEX_NAME);
|
||
+ if (!y_strnicmp (tname, name, WAD_TEX_NAME))
|
||
+ texofs = dir->dir.start + offsets[n];
|
||
+ }
|
||
+ FreeMemory (offsets);
|
||
+ }
|
||
+ }
|
||
+// Other iwads : "TEXTURE1" and "TEXTURE2"
|
||
+else if (yg_texture_lumps == YGTL_NORMAL
|
||
+ && (yg_texture_format == YGTF_NORMAL || yg_texture_format == YGTF_STRIFE11))
|
||
+ {
|
||
+ // Is it in TEXTURE1 ?
|
||
+ dir = FindMasterDir (MasterDir, "TEXTURE1");
|
||
+ if (dir != NULL) // (Theoretically, it should always exist)
|
||
+ {
|
||
+ dir->wadfile->seek (dir->dir.start);
|
||
+ dir->wadfile->read_i32 (&numtex);
|
||
+ /* read in the offsets for texture1 names and info. */
|
||
+ offsets = (i32 *) GetMemory ((long) numtex * 4);
|
||
+ dir->wadfile->read_i32 (offsets, numtex);
|
||
+ for (n = 0; n < numtex && !texofs; n++)
|
||
+ {
|
||
+ dir->wadfile->seek (dir->dir.start + offsets[n]);
|
||
+ dir->wadfile->read_bytes (&tname, WAD_TEX_NAME);
|
||
+ if (!y_strnicmp (tname, name, WAD_TEX_NAME))
|
||
+ texofs = dir->dir.start + offsets[n];
|
||
+ }
|
||
+ FreeMemory (offsets);
|
||
+ }
|
||
+ // Well, then is it in TEXTURE2 ?
|
||
+ if (texofs == 0)
|
||
+ {
|
||
+ dir = FindMasterDir (MasterDir, "TEXTURE2");
|
||
+ if (dir != NULL) // Doom II has no TEXTURE2
|
||
+ {
|
||
+ dir->wadfile->seek (dir->dir.start);
|
||
+ dir->wadfile->read_i32 (&numtex);
|
||
+ /* read in the offsets for texture2 names */
|
||
+ offsets = (i32 *) GetMemory ((long) numtex * 4);
|
||
+ dir->wadfile->read_i32 (offsets, numtex);
|
||
+ for (n = 0; n < numtex && !texofs; n++)
|
||
+ {
|
||
+ dir->wadfile->seek (dir->dir.start + offsets[n]);
|
||
+ dir->wadfile->read_bytes (&tname, WAD_TEX_NAME);
|
||
+ if (!y_strnicmp (tname, name, WAD_TEX_NAME))
|
||
+ texofs = dir->dir.start + offsets[n];
|
||
+ }
|
||
+ FreeMemory (offsets);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+else
|
||
+ nf_bug ("Invalid texture_format/texture_lumps combination.");
|
||
+
|
||
+/* texture name not found */
|
||
+if (texofs == 0)
|
||
+ return 0;
|
||
+
|
||
+/* read the info for this texture */
|
||
+i32 header_ofs;
|
||
+if (yg_texture_format == YGTF_NAMELESS)
|
||
+ header_ofs = texofs;
|
||
+else
|
||
+ header_ofs = texofs + WAD_TEX_NAME;
|
||
+dir->wadfile->seek (header_ofs + 4);
|
||
+dir->wadfile->read_i16 (&width);
|
||
+dir->wadfile->read_i16 (&height);
|
||
+if (have_dummy_bytes)
|
||
+ {
|
||
+ i16 dummy;
|
||
+ dir->wadfile->read_i16 (&dummy);
|
||
+ dir->wadfile->read_i16 (&dummy);
|
||
+ }
|
||
+dir->wadfile->read_i16 (&npatches);
|
||
+
|
||
+/* Compose the texture */
|
||
+Img *texbuf = new Img (width, height, false);
|
||
+
|
||
+/* Paste onto the buffer all the patches that the texture is
|
||
+ made of. */
|
||
+for (n = 0; n < npatches; n++)
|
||
+ {
|
||
+ i16 xofs, yofs; // offset in texture space for the patch
|
||
+ i16 pnameind; // index of patch in PNAMES
|
||
+
|
||
+ dir->wadfile->seek (header_ofs + header_size + (long) n * item_size);
|
||
+ dir->wadfile->read_i16 (&xofs);
|
||
+ dir->wadfile->read_i16 (&yofs);
|
||
+ dir->wadfile->read_i16 (&pnameind);
|
||
+
|
||
+ if (have_dummy_bytes)
|
||
+ {
|
||
+ i16 stepdir;
|
||
+ i16 colormap;
|
||
+ dir->wadfile->read_i16 (&stepdir); // Always 1, unused.
|
||
+ dir->wadfile->read_i16 (&colormap); // Always 0, unused.
|
||
+ }
|
||
+
|
||
+ /* AYM 1998-08-08: Yes, that's weird but that's what Doom
|
||
+ does. Without these two lines, the few textures that have
|
||
+ patches with negative y-offsets (BIGDOOR7, SKY1, TEKWALL1,
|
||
+ TEKWALL5 and a few others) would not look in the texture
|
||
+ viewer quite like in Doom. This should be mentioned in
|
||
+ the UDS, by the way. */
|
||
+ if (yofs < 0)
|
||
+ yofs = 0;
|
||
+
|
||
+ Lump_loc loc;
|
||
+ {
|
||
+ wad_pic_name_t *wname = patch_dir.name_for_num (pnameind);
|
||
+ if (wname == 0)
|
||
+ {
|
||
+ warn ("texture \"%.*s\": patch %2d has bad index %d.\n",
|
||
+ WAD_TEX_NAME, tname, (int) n, (int) pnameind);
|
||
+ continue;
|
||
+ }
|
||
+ patch_dir.loc_by_name ((const char *) *wname, loc);
|
||
+ *picname = '\0';
|
||
+ strncat (picname, (const char *) *wname, sizeof picname - 1);
|
||
+ }
|
||
+
|
||
+ if (LoadPicture (*texbuf, picname, loc, xofs, yofs, 0, 0))
|
||
+ warn ("texture \"%.*s\": patch \"%.*s\" not found.\n",
|
||
+ WAD_TEX_NAME, tname, WAD_PIC_NAME, picname);
|
||
+ }
|
||
+
|
||
+return texbuf;
|
||
+}
|
||
+
|
||
+
|
||
+/* --- ImageCache methods --- */
|
||
+
|
||
+
|
||
+Img *ImageCache::GetFlat (const wad_flat_name_t& fname)
|
||
+{
|
||
+std::string f_str = WadToString(fname);
|
||
+
|
||
+flat_map_t::iterator P = flats.find (f_str);
|
||
+
|
||
+if (P != flats.end ())
|
||
+ return P->second;
|
||
+
|
||
+// flat not in the list yet. Add it.
|
||
+
|
||
+Img *result = Flat2Img (fname);
|
||
+flats[f_str] = result;
|
||
+
|
||
+// note that a NULL return from Flat2Img is OK, it means that no
|
||
+// such flat exists. Our renderer will revert to using a solid
|
||
+// colour.
|
||
+
|
||
+return result;
|
||
+}
|
||
+
|
||
+
|
||
+Img *ImageCache::GetTex (const wad_tex_name_t& tname)
|
||
+{
|
||
+if (tname[0] == 0 || tname[0] == '-')
|
||
+ return 0;
|
||
+
|
||
+std::string t_str = WadToString(tname);
|
||
+
|
||
+tex_map_t::iterator P = textures.find (t_str);
|
||
+
|
||
+if (P != textures.end ())
|
||
+ return P->second;
|
||
+
|
||
+// texture not in the list yet. Add it.
|
||
+
|
||
+Img *result = Tex2Img (tname);
|
||
+textures[t_str] = result;
|
||
+
|
||
+// note that a NULL return from Tex2Img is OK, it means that no
|
||
+// such texture exists. Our renderer will revert to using a solid
|
||
+// colour.
|
||
+
|
||
+return result;
|
||
+}
|
||
+
|
||
+
|
||
+Img *ImageCache::GetSprite (const wad_ttype_t& type)
|
||
+{
|
||
+sprite_map_t::iterator P = sprites.find (type);
|
||
+
|
||
+if (P != sprites.end ())
|
||
+ return P->second;
|
||
+
|
||
+// sprite not in the list yet. Add it.
|
||
+
|
||
+Img *result = 0;
|
||
+
|
||
+const char *sprite_root = get_thing_sprite (type);
|
||
+if (sprite_root)
|
||
+ {
|
||
+ Lump_loc loc;
|
||
+ wad_res.sprites.loc_by_root (sprite_root, loc);
|
||
+ result = new Img ();
|
||
+
|
||
+ if (LoadPicture (*result, sprite_root, loc, 0, 0) != 0)
|
||
+ {
|
||
+ delete result;
|
||
+ result = 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+// note that a NULL image is OK. Our renderer will just ignore the
|
||
+// missing sprite.
|
||
+
|
||
+sprites[type] = result;
|
||
+return result;
|
||
+}
|
||
diff -u -r -N yadex-1.7.0/src/r_images.h yadex-1.7.0-all/src/r_images.h
|
||
--- yadex-1.7.0/src/r_images.h 1970-01-01 10:00:00.000000000 +1000
|
||
+++ yadex-1.7.0-all/src/r_images.h 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -0,0 +1,69 @@
|
||
+/*
|
||
+ * r_images.h
|
||
+ * AJA 2002-04-27
|
||
+ */
|
||
+
|
||
+
|
||
+#ifndef YH_R_IMAGES /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
|
||
+#define YH_R_IMAGES
|
||
+
|
||
+
|
||
+#include <map>
|
||
+#include <algorithm>
|
||
+#include <string>
|
||
+
|
||
+
|
||
+struct ImageCache
|
||
+{
|
||
+public:
|
||
+ typedef std::map<std::string, Img *> flat_map_t;
|
||
+ typedef std::map<std::string, Img *> tex_map_t;
|
||
+ typedef std::map<wad_ttype_t, Img *> sprite_map_t;
|
||
+
|
||
+ flat_map_t flats;
|
||
+ tex_map_t textures;
|
||
+ sprite_map_t sprites;
|
||
+
|
||
+ static std::string WadToString(const wad_flat_name_t& fname)
|
||
+ {
|
||
+ int len;
|
||
+
|
||
+ for (len = 0; len < WAD_NAME && fname[len]; len++)
|
||
+ { }
|
||
+
|
||
+ return std::string(fname, len);
|
||
+ }
|
||
+
|
||
+ static void DeleteFlat(const flat_map_t::value_type& P)
|
||
+ {
|
||
+ delete P.second;
|
||
+ }
|
||
+
|
||
+ static void DeleteTex(const tex_map_t::value_type& P)
|
||
+ {
|
||
+ delete P.second;
|
||
+ }
|
||
+
|
||
+ static void DeleteSprite(const sprite_map_t::value_type& P)
|
||
+ {
|
||
+ delete P.second;
|
||
+ }
|
||
+
|
||
+ ~ImageCache ()
|
||
+ {
|
||
+ std::for_each (flats.begin (), flats.end (), DeleteFlat);
|
||
+ std::for_each (textures.begin (), textures.end (), DeleteTex);
|
||
+ std::for_each (sprites.begin (), sprites.end (), DeleteSprite);
|
||
+
|
||
+ flats.clear ();
|
||
+ textures.clear ();
|
||
+ sprites.clear ();
|
||
+ }
|
||
+
|
||
+ Img *GetFlat (const wad_flat_name_t& fname);
|
||
+ Img *GetTex (const wad_tex_name_t& tname);
|
||
+ Img *GetSprite (const wad_ttype_t& type);
|
||
+};
|
||
+
|
||
+
|
||
+#endif /* DO NOT ADD ANYTHING AFTER THIS LINE */
|
||
diff -u -r -N yadex-1.7.0/src/r_render.cc yadex-1.7.0-all/src/r_render.cc
|
||
--- yadex-1.7.0/src/r_render.cc 1970-01-01 10:00:00.000000000 +1000
|
||
+++ yadex-1.7.0-all/src/r_render.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -0,0 +1,1275 @@
|
||
+/*
|
||
+ * r_render.cc
|
||
+ * 3D Rendering
|
||
+ * AJA 2002-04-21
|
||
+ */
|
||
+
|
||
+
|
||
+/*
|
||
+This file is part of Yadex.
|
||
+
|
||
+Yadex incorporates code from DEU 5.21 that was put in the public domain in
|
||
+1994 by Rapha<68>l Quinet and Brendon Wyber.
|
||
+
|
||
+The rest of Yadex is Copyright <20> 1997-2000 Andr<64> Majorel.
|
||
+
|
||
+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.
|
||
+*/
|
||
+
|
||
+
|
||
+#include "yadex.h"
|
||
+
|
||
+#include <math.h>
|
||
+#include <vector>
|
||
+#include <map>
|
||
+#include <algorithm>
|
||
+
|
||
+#ifdef Y_X11
|
||
+#include <X11/Xlib.h>
|
||
+#include <X11/Xutil.h>
|
||
+#endif
|
||
+#include "levels.h"
|
||
+#include "wstructs.h"
|
||
+#include "gfx.h"
|
||
+#include "img.h"
|
||
+#include "sticker.h"
|
||
+#include "gamesky.h"
|
||
+#include "things.h"
|
||
+#include "wadres.h"
|
||
+#include "objid.h"
|
||
+#include "objects.h"
|
||
+#include "pic2img.h"
|
||
+#include "rgb.h"
|
||
+#include "gcolour2.h"
|
||
+
|
||
+#include "r_render.h"
|
||
+#include "r_images.h"
|
||
+
|
||
+
|
||
+#define ML_UPPER_UNPEGGED 0x08
|
||
+#define ML_LOWER_UNPEGGED 0x10
|
||
+
|
||
+
|
||
+struct Y_View
|
||
+{
|
||
+public:
|
||
+ int p_type, px, py;
|
||
+ // player type and position.
|
||
+
|
||
+ float x, y;
|
||
+ int z;
|
||
+ // view position.
|
||
+
|
||
+ static const int EYE_HEIGHT = 41;
|
||
+ // standard height above the floor.
|
||
+
|
||
+ float angle;
|
||
+ float Sin, Cos;
|
||
+ // view direction.
|
||
+
|
||
+ int sw, sh;
|
||
+ Img *screen;
|
||
+ // screen image.
|
||
+
|
||
+ bool texturing;
|
||
+ bool sprites;
|
||
+ bool walking;
|
||
+
|
||
+ ImageCache *im_ch;
|
||
+
|
||
+ int *thing_floors;
|
||
+
|
||
+ Y_View () { memset (this, 0, sizeof *this); }
|
||
+
|
||
+ void SetAngle (float new_ang)
|
||
+ {
|
||
+ angle = new_ang;
|
||
+
|
||
+ if (angle >= TWOPI)
|
||
+ angle -= TWOPI;
|
||
+ else if (angle < 0)
|
||
+ angle += TWOPI;
|
||
+
|
||
+ Sin = sin (angle);
|
||
+ Cos = cos (angle);
|
||
+ }
|
||
+
|
||
+ void CalcViewZ ()
|
||
+ {
|
||
+ Objid o;
|
||
+ GetCurObject (o, OBJ_SECTORS, int (x), int (y));
|
||
+ int secnum = o.num;
|
||
+ if (secnum >= 0)
|
||
+ z = Sectors[secnum].floorh + EYE_HEIGHT;
|
||
+ }
|
||
+
|
||
+ void ClearScreen ()
|
||
+ {
|
||
+ memset (screen->wbuf (), colour0, sw * sh);
|
||
+ }
|
||
+
|
||
+ void PutScreen (int x, int y)
|
||
+ {
|
||
+ DrawScreenBox3D (x, y, x + BOX_BORDER*2 + sw, y + BOX_BORDER*2 + sh);
|
||
+
|
||
+ Sticker sticker (*screen, true);
|
||
+
|
||
+ sticker.draw (drw, 't', x + BOX_BORDER, y + BOX_BORDER);
|
||
+ }
|
||
+
|
||
+ void FindThingFloors ()
|
||
+ {
|
||
+ thing_floors = new int[NumThings];
|
||
+
|
||
+ for (int i = 0; i < NumThings; i++)
|
||
+ {
|
||
+ Objid o;
|
||
+ GetCurObject (o, OBJ_SECTORS, Things[i].xpos,
|
||
+ Things[i].ypos);
|
||
+ int secnum = o.num;
|
||
+
|
||
+ if (secnum < 0)
|
||
+ thing_floors[i] = 0;
|
||
+ else
|
||
+ thing_floors[i] = Sectors[secnum].floorh;
|
||
+ }
|
||
+ }
|
||
+};
|
||
+
|
||
+
|
||
+static Y_View view;
|
||
+
|
||
+
|
||
+struct DrawSurf
|
||
+{
|
||
+public:
|
||
+ enum
|
||
+ {
|
||
+ K_INVIS = 0,
|
||
+ K_FLAT,
|
||
+ K_TEXTURE
|
||
+ };
|
||
+ int kind;
|
||
+
|
||
+ int h1, h2, tex_h;
|
||
+ // heights for the surface (h1 is above h2).
|
||
+
|
||
+ Img *img;
|
||
+ img_pixel_t col; /* used if img is zero */
|
||
+
|
||
+ enum
|
||
+ {
|
||
+ SOLID_ABOVE = 1,
|
||
+ SOLID_BELOW = 2
|
||
+ };
|
||
+ int y_clip;
|
||
+
|
||
+ /* CTor */
|
||
+
|
||
+ DrawSurf () { kind = K_INVIS; img = 0; }
|
||
+
|
||
+ void FindFlat (const wad_flat_name_t& fname, Sector *sec)
|
||
+ {
|
||
+ if (view.texturing)
|
||
+ {
|
||
+ img = view.im_ch->GetFlat (fname);
|
||
+
|
||
+ if (img != 0)
|
||
+ return;
|
||
+ }
|
||
+ col = 0x70 + ((sec - Sectors) % 48);
|
||
+ }
|
||
+
|
||
+ void FindTex (const wad_tex_name_t& tname, LineDef *ld)
|
||
+ {
|
||
+ if (view.texturing)
|
||
+ {
|
||
+ img = view.im_ch->GetTex (tname);
|
||
+
|
||
+ if (img != 0)
|
||
+ return;
|
||
+ }
|
||
+ col = 0x30 + ((ld - LineDefs) % 64);
|
||
+
|
||
+ if (col >= 0x60)
|
||
+ col += 0x70;
|
||
+ }
|
||
+};
|
||
+
|
||
+
|
||
+struct DrawWall
|
||
+{
|
||
+public:
|
||
+ typedef std::vector<struct DrawWall *> vec_t;
|
||
+
|
||
+ Thing *th;
|
||
+ // when `th' is non-zero, this is actually a sprite, and `ld' and
|
||
+ // `sd' will be zero. Sprites use the info in the `ceil' surface.
|
||
+
|
||
+ LineDef *ld;
|
||
+ SideDef *sd;
|
||
+ Sector *sec;
|
||
+
|
||
+ int side;
|
||
+ // which side this wall faces (0 right, 1 left)
|
||
+
|
||
+ float ang1, dang, cur_ang;
|
||
+ float base_ang;
|
||
+ // clipped angles
|
||
+
|
||
+ float dist, t_dist;
|
||
+ float normal;
|
||
+ // line constants
|
||
+
|
||
+ double iz1, diz, cur_iz;
|
||
+ double mid_iz;
|
||
+ // distance values (inverted, so they can be lerped)
|
||
+
|
||
+ float spr_tx1;
|
||
+ // translate coord, for sprite
|
||
+
|
||
+ int sx1, sx2;
|
||
+ // screen X coordinates
|
||
+
|
||
+ int oy1, oy2;
|
||
+ // for sprites, the remembered open space to clip to
|
||
+
|
||
+ /* surfaces */
|
||
+
|
||
+ DrawSurf ceil;
|
||
+ DrawSurf upper;
|
||
+ DrawSurf lower;
|
||
+ DrawSurf floor;
|
||
+
|
||
+ static const double IZ_EPSILON = 0.000001;
|
||
+
|
||
+ /* PREDICATES */
|
||
+
|
||
+ struct MidDistCmp
|
||
+ {
|
||
+ inline bool operator() (const DrawWall * A, const DrawWall * B) const
|
||
+ {
|
||
+ return A->mid_iz > B->mid_iz;
|
||
+ }
|
||
+ };
|
||
+
|
||
+ struct DistCmp
|
||
+ {
|
||
+ inline bool operator() (const DrawWall * A, const DrawWall * B) const
|
||
+ {
|
||
+ if (fabs (A->cur_iz - B->cur_iz) < IZ_EPSILON)
|
||
+ return A->diz > B->diz;
|
||
+
|
||
+ return A->cur_iz > B->cur_iz;
|
||
+ }
|
||
+ };
|
||
+
|
||
+ struct SX1Cmp
|
||
+ {
|
||
+ inline bool operator() (const DrawWall * A, const DrawWall * B) const
|
||
+ {
|
||
+ return A->sx1 < B->sx1;
|
||
+ }
|
||
+
|
||
+ inline bool operator() (const DrawWall * A, int x) const
|
||
+ {
|
||
+ return A->sx1 < x;
|
||
+ }
|
||
+
|
||
+ inline bool operator() (int x, const DrawWall * A) const
|
||
+ {
|
||
+ return x < A->sx1;
|
||
+ }
|
||
+ };
|
||
+
|
||
+ struct SX2Less
|
||
+ {
|
||
+ int x;
|
||
+
|
||
+ SX2Less (int _x) : x (_x) { }
|
||
+
|
||
+ inline bool operator() (const DrawWall * A) const
|
||
+ {
|
||
+ return A->sx2 < x;
|
||
+ }
|
||
+ };
|
||
+
|
||
+ /* methods */
|
||
+
|
||
+ void ComputeWallSurface ()
|
||
+ {
|
||
+ Sector *front = sec;
|
||
+ Sector *back = 0;
|
||
+
|
||
+ if (is_obj (side ? ld->sidedef1 : ld->sidedef2))
|
||
+ {
|
||
+ SideDef *bsd = SideDefs + (side ? ld->sidedef1 : ld->sidedef2);
|
||
+
|
||
+ if (is_obj (bsd->sector))
|
||
+ back = Sectors + bsd->sector;
|
||
+ }
|
||
+
|
||
+ bool sky_upper = back && is_sky (front->ceilt) && is_sky (back->ceilt);
|
||
+
|
||
+ if ((front->ceilh > view.z || is_sky (front->ceilt)) && ! sky_upper)
|
||
+ {
|
||
+ ceil.kind = DrawSurf::K_FLAT;
|
||
+ ceil.h1 = +99999;
|
||
+ ceil.h2 = front->ceilh;
|
||
+ ceil.tex_h = ceil.h2;
|
||
+ ceil.y_clip = DrawSurf::SOLID_ABOVE;
|
||
+
|
||
+ if (is_sky (front->ceilt))
|
||
+ ceil.col = sky_colour;
|
||
+ else
|
||
+ ceil.FindFlat (front->ceilt, front);
|
||
+ }
|
||
+
|
||
+ if (front->floorh < view.z)
|
||
+ {
|
||
+ floor.kind = DrawSurf::K_FLAT;
|
||
+ floor.h1 = front->floorh;
|
||
+ floor.h2 = -99999;
|
||
+ floor.tex_h = floor.h1;
|
||
+ floor.y_clip = DrawSurf::SOLID_BELOW;
|
||
+
|
||
+ if (is_sky (front->floort))
|
||
+ floor.col = sky_colour;
|
||
+ else
|
||
+ floor.FindFlat (front->floort, front);
|
||
+ }
|
||
+
|
||
+ if (! back)
|
||
+ {
|
||
+ /* ONE-sided line */
|
||
+
|
||
+ lower.kind = DrawSurf::K_TEXTURE;
|
||
+ lower.h1 = front->ceilh;
|
||
+ lower.h2 = front->floorh;
|
||
+ lower.y_clip = DrawSurf::SOLID_ABOVE | DrawSurf::SOLID_BELOW;
|
||
+
|
||
+ lower.FindTex (sd->tex3, ld);
|
||
+
|
||
+ if (lower.img && (ld->flags & ML_LOWER_UNPEGGED))
|
||
+ lower.tex_h = lower.h2 + lower.img->height ();
|
||
+ else
|
||
+ lower.tex_h = lower.h1;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* TWO-sided line */
|
||
+
|
||
+ if (back->ceilh < front->ceilh && ! sky_upper)
|
||
+ {
|
||
+ upper.kind = DrawSurf::K_TEXTURE;
|
||
+ upper.h1 = front->ceilh;
|
||
+ upper.h2 = back->ceilh;
|
||
+ upper.tex_h = upper.h1;
|
||
+ upper.y_clip = DrawSurf::SOLID_ABOVE;
|
||
+
|
||
+ upper.FindTex (sd->tex1, ld);
|
||
+
|
||
+ if (upper.img && ! (ld->flags & ML_UPPER_UNPEGGED))
|
||
+ upper.tex_h = upper.h2 + upper.img->height ();
|
||
+ else
|
||
+ upper.tex_h = upper.h1;
|
||
+ }
|
||
+
|
||
+ if (back->floorh > front->floorh)
|
||
+ {
|
||
+ lower.kind = DrawSurf::K_TEXTURE;
|
||
+ lower.h1 = back->floorh;
|
||
+ lower.h2 = front->floorh;
|
||
+ lower.y_clip = DrawSurf::SOLID_BELOW;
|
||
+
|
||
+ lower.FindTex (sd->tex2, ld);
|
||
+
|
||
+ if (ld->flags & ML_LOWER_UNPEGGED)
|
||
+ lower.tex_h = front->ceilh;
|
||
+ else
|
||
+ lower.tex_h = lower.h1;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+};
|
||
+
|
||
+
|
||
+struct RendInfo
|
||
+{
|
||
+public:
|
||
+ DrawWall::vec_t walls;
|
||
+ // complete set of walls/sprites to draw.
|
||
+
|
||
+ DrawWall::vec_t active;
|
||
+ // the active list. Pointers here are always duplicates of ones in
|
||
+ // the walls list (no need to `delete' any of them).
|
||
+
|
||
+ std::vector<double> depth_x;
|
||
+ // inverse distances over X range, 0 when empty.
|
||
+
|
||
+ int open_y1;
|
||
+ int open_y2;
|
||
+
|
||
+ static const double Y_SLOPE = 1.70;
|
||
+
|
||
+ static void DeleteWall (DrawWall *P)
|
||
+ {
|
||
+ delete P;
|
||
+ }
|
||
+
|
||
+ ~RendInfo ()
|
||
+ {
|
||
+ std::for_each (walls.begin (), walls.end (), DeleteWall);
|
||
+
|
||
+ walls.clear ();
|
||
+ active.clear ();
|
||
+ }
|
||
+
|
||
+ void InitDepthBuf (int width)
|
||
+ {
|
||
+ depth_x.resize (width);
|
||
+
|
||
+ std::fill_n (depth_x.begin (), width, 0);
|
||
+ }
|
||
+
|
||
+ static inline float PointToAngle (float x, float y)
|
||
+ {
|
||
+ if (-0.01 < x && x < 0.01)
|
||
+ return (y > 0) ? HALFPI : (3 * HALFPI);
|
||
+
|
||
+ float angle = atan2(y, x);
|
||
+
|
||
+ if (angle < 0)
|
||
+ angle += TWOPI;
|
||
+
|
||
+ return angle;
|
||
+ }
|
||
+
|
||
+ static inline int AngleToX (float ang)
|
||
+ {
|
||
+ float t = tan (HALFPI - ang);
|
||
+
|
||
+ int x = int (view.sw * t);
|
||
+
|
||
+ x = (view.sw + x) / 2;
|
||
+
|
||
+ if (x < 0)
|
||
+ x = 0;
|
||
+ else if (x > view.sw)
|
||
+ x = view.sw;
|
||
+
|
||
+ return x;
|
||
+ }
|
||
+
|
||
+ static inline float XToAngle (int x)
|
||
+ {
|
||
+ x = x * 2 - view.sw;
|
||
+
|
||
+ float ang = HALFPI + atan (x / float (view.sw));
|
||
+
|
||
+ if (ang < 0)
|
||
+ ang = 0;
|
||
+ else if (ang > ONEPI)
|
||
+ ang = ONEPI;
|
||
+
|
||
+ return ang;
|
||
+ }
|
||
+
|
||
+ static inline int DeltaToX (double iz, float tx)
|
||
+ {
|
||
+ int x = int (view.sw * tx * iz);
|
||
+
|
||
+ x = (x + view.sw) / 2;
|
||
+
|
||
+ return x;
|
||
+ }
|
||
+
|
||
+ static inline float XToDelta (int x, double iz)
|
||
+ {
|
||
+ x = x * 2 - view.sw;
|
||
+
|
||
+ float tx = x / iz / view.sw;
|
||
+
|
||
+ return tx;
|
||
+ }
|
||
+
|
||
+ static inline int DistToY (double iz, int sec_h)
|
||
+ {
|
||
+ if (sec_h > 32770)
|
||
+ return -9999;
|
||
+
|
||
+ if (sec_h < -32770)
|
||
+ return +9999;
|
||
+
|
||
+ sec_h -= view.z;
|
||
+
|
||
+ int y = int (view.sh * sec_h * iz * Y_SLOPE);
|
||
+
|
||
+ y = (view.sh - y) / 2;
|
||
+
|
||
+ return y;
|
||
+ }
|
||
+
|
||
+ static inline float YToDist (int y, int sec_h)
|
||
+ {
|
||
+ sec_h -= view.z;
|
||
+
|
||
+ y = y * 2 - view.sh;
|
||
+
|
||
+ if (y == 0)
|
||
+ return 999999;
|
||
+
|
||
+ return view.sh * sec_h * Y_SLOPE / y;
|
||
+ }
|
||
+
|
||
+ static inline float YToSecH (int y, double iz)
|
||
+ {
|
||
+ y = y * 2 - view.sh;
|
||
+
|
||
+ return view.z - (float (y) / view.sh / iz / Y_SLOPE);
|
||
+ }
|
||
+
|
||
+ void AddLine (int linenum)
|
||
+ {
|
||
+ LineDef *ld = LineDefs + linenum;
|
||
+
|
||
+ if (! is_obj (ld->start) || ! is_obj (ld->end))
|
||
+ return;
|
||
+
|
||
+ float x1 = Vertices[ld->start].x - view.x;
|
||
+ float y1 = Vertices[ld->start].y - view.y;
|
||
+ float x2 = Vertices[ld->end].x - view.x;
|
||
+ float y2 = Vertices[ld->end].y - view.y;
|
||
+
|
||
+ float tx1 = x1 * view.Sin - y1 * view.Cos;
|
||
+ float ty1 = x1 * view.Cos + y1 * view.Sin;
|
||
+ float tx2 = x2 * view.Sin - y2 * view.Cos;
|
||
+ float ty2 = x2 * view.Cos + y2 * view.Sin;
|
||
+
|
||
+ // reject line if complete behind viewplane
|
||
+ if (ty1 <= 0 && ty2 <= 0)
|
||
+ return;
|
||
+
|
||
+ float angle1 = PointToAngle (tx1, ty1);
|
||
+ float angle2 = PointToAngle (tx2, ty2);
|
||
+ float span = angle1 - angle2;
|
||
+
|
||
+ if (span < 0)
|
||
+ span += TWOPI;
|
||
+
|
||
+ int side = 0;
|
||
+ SideDef *sd;
|
||
+
|
||
+ if (span >= ONEPI)
|
||
+ side = 1;
|
||
+
|
||
+ // ignore the line when there is no facing sidedef
|
||
+ if (! is_obj (side ? ld->sidedef2 : ld->sidedef1))
|
||
+ return;
|
||
+
|
||
+ sd = SideDefs + (side ? ld->sidedef2 : ld->sidedef1);
|
||
+
|
||
+ if (! is_obj (sd->sector))
|
||
+ return;
|
||
+
|
||
+ if (side == 1)
|
||
+ {
|
||
+ float tmp = angle1;
|
||
+ angle1 = angle2;
|
||
+ angle2 = tmp;
|
||
+ }
|
||
+
|
||
+ // clip angles to view volume
|
||
+
|
||
+ float base_ang = angle1;
|
||
+
|
||
+ float leftclip = (3 * ONEPI / 4);
|
||
+ float rightclip = ONEPI / 4;
|
||
+
|
||
+ float tspan1 = angle1 - rightclip;
|
||
+ float tspan2 = leftclip - angle2;
|
||
+
|
||
+ if (tspan1 < 0) tspan1 += TWOPI;
|
||
+ if (tspan2 < 0) tspan2 += TWOPI;
|
||
+
|
||
+ if (tspan1 > HALFPI)
|
||
+ {
|
||
+ // Totally off the left edge?
|
||
+ if (tspan2 >= ONEPI)
|
||
+ return;
|
||
+
|
||
+ angle1 = leftclip;
|
||
+ }
|
||
+
|
||
+ if (tspan2 > HALFPI)
|
||
+ {
|
||
+ // Totally off the left edge?
|
||
+ if (tspan1 >= ONEPI)
|
||
+ return;
|
||
+
|
||
+ angle2 = rightclip;
|
||
+ }
|
||
+
|
||
+ // convert angles to on-screen X positions
|
||
+ int sx1 = AngleToX (angle1);
|
||
+ int sx2 = AngleToX (angle2) - 1;
|
||
+
|
||
+ if (sx1 > sx2)
|
||
+ return;
|
||
+
|
||
+ // compute distance from eye to wall
|
||
+ float wdx = x2 - x1;
|
||
+ float wdy = y2 - y1;
|
||
+
|
||
+ float wlen = sqrt (wdx * wdx + wdy * wdy);
|
||
+ float dist = fabs ((y1 * wdx / wlen) - (x1 * wdy / wlen));
|
||
+
|
||
+ if (dist < 0.01)
|
||
+ return;
|
||
+
|
||
+ // compute normal of wall (translated coords)
|
||
+ float normal;
|
||
+
|
||
+ if (side == 1)
|
||
+ normal = PointToAngle (ty2 - ty1, tx1 - tx2);
|
||
+ else
|
||
+ normal = PointToAngle (ty1 - ty2, tx2 - tx1);
|
||
+
|
||
+ // compute inverse distances
|
||
+ double iz1 = cos (normal - angle1) / dist / cos (HALFPI - angle1);
|
||
+ double iz2 = cos (normal - angle2) / dist / cos (HALFPI - angle2);
|
||
+
|
||
+ double diz = (iz2 - iz1) / y_max (1, sx2 - sx1);
|
||
+
|
||
+ // create drawwall structure
|
||
+
|
||
+ DrawWall *dw = new DrawWall;
|
||
+
|
||
+ dw->th = 0;
|
||
+ dw->ld = ld;
|
||
+ dw->sd = sd;
|
||
+ dw->sec = Sectors + sd->sector;
|
||
+
|
||
+ dw->side = side;
|
||
+
|
||
+ dw->base_ang = base_ang;
|
||
+ dw->ang1 = angle1;
|
||
+ dw->dang = (angle2 - angle1) / y_max (1, sx2 - sx1);
|
||
+
|
||
+ dw->dist = dist;
|
||
+ dw->normal = normal;
|
||
+ dw->t_dist = tan (base_ang - normal) * dist;
|
||
+
|
||
+ dw->iz1 = iz1;
|
||
+ dw->diz = diz;
|
||
+ dw->mid_iz = iz1 + (sx2 - sx1 + 1) * diz / 2;
|
||
+
|
||
+ dw->sx1 = sx1; dw->sx2 = sx2;
|
||
+
|
||
+ walls.push_back (dw);
|
||
+ }
|
||
+
|
||
+ void AddThing (int thingnum)
|
||
+ {
|
||
+ Thing *th = Things + thingnum;
|
||
+
|
||
+ float x = th->xpos - view.x;
|
||
+ float y = th->ypos - view.y;
|
||
+
|
||
+ float tx = x * view.Sin - y * view.Cos;
|
||
+ float ty = x * view.Cos + y * view.Sin;
|
||
+
|
||
+ // reject sprite if complete behind viewplane
|
||
+ if (ty < 4)
|
||
+ return;
|
||
+
|
||
+ Img *sprite = view.im_ch->GetSprite (th->type);
|
||
+ if (! sprite)
|
||
+ return;
|
||
+
|
||
+ float tx1 = tx - sprite->width () / 2.0;
|
||
+ float tx2 = tx + sprite->width () / 2.0;
|
||
+
|
||
+ double iz = 1 / ty;
|
||
+
|
||
+ int sx1 = DeltaToX (iz, tx1);
|
||
+ int sx2 = DeltaToX (iz, tx2) - 1;
|
||
+
|
||
+ if (sx1 < 0)
|
||
+ sx1 = 0;
|
||
+
|
||
+ if (sx2 >= view.sw)
|
||
+ sx2 = view.sw - 1;
|
||
+
|
||
+ if (sx1 > sx2)
|
||
+ return;
|
||
+
|
||
+ int h2 = view.thing_floors[thingnum];
|
||
+ int h1 = h2 + sprite->height ();
|
||
+
|
||
+ // create drawwall structure
|
||
+
|
||
+ DrawWall *dw = new DrawWall;
|
||
+
|
||
+ dw->th = th;
|
||
+ dw->ld = 0;
|
||
+ dw->sd = 0;
|
||
+ dw->sec = 0;
|
||
+
|
||
+ dw->spr_tx1 = tx1;
|
||
+
|
||
+ dw->ang1 = dw->dang = 0;
|
||
+
|
||
+ dw->iz1 = dw->mid_iz = iz;
|
||
+ dw->diz = 0;
|
||
+
|
||
+ dw->sx1 = sx1; dw->sx2 = sx2;
|
||
+
|
||
+ dw->ceil.img = sprite;
|
||
+ dw->ceil.h1 = h1;
|
||
+ dw->ceil.h2 = h2;
|
||
+
|
||
+ walls.push_back (dw);
|
||
+ }
|
||
+
|
||
+ void ComputeSurfaces ()
|
||
+ {
|
||
+ DrawWall::vec_t::iterator S;
|
||
+
|
||
+ for (S = walls.begin (); S != walls.end (); S++)
|
||
+ if ((*S)->ld)
|
||
+ (*S)->ComputeWallSurface ();
|
||
+ }
|
||
+
|
||
+ void ClipSolids ()
|
||
+ {
|
||
+ // perform a rough depth sort of the walls and sprites.
|
||
+
|
||
+ std::sort (walls.begin (), walls.end (), DrawWall::MidDistCmp ());
|
||
+
|
||
+ // go forwards, from closest to furthest away
|
||
+
|
||
+ DrawWall::vec_t::iterator S;
|
||
+
|
||
+ for (S = walls.begin (); S != walls.end (); S++)
|
||
+ {
|
||
+ DrawWall *dw = (*S);
|
||
+
|
||
+ if (! dw)
|
||
+ continue;
|
||
+
|
||
+ int one_sided = dw->ld && ! is_obj (dw->ld->sidedef2);
|
||
+ int vis_count = dw->sx2 - dw->sx1 + 1;
|
||
+
|
||
+ for (int x = dw->sx1; x <= dw->sx2; x++)
|
||
+ {
|
||
+ double iz = dw->iz1 + (dw->diz * (x - dw->sx1));
|
||
+
|
||
+ if (iz < depth_x[x])
|
||
+ vis_count--;
|
||
+ else if (one_sided)
|
||
+ depth_x[x] = iz;
|
||
+ }
|
||
+
|
||
+ if (vis_count == 0)
|
||
+ {
|
||
+ delete dw;
|
||
+ (*S) = 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ // remove null pointers
|
||
+
|
||
+ S = std::remove (walls.begin (), walls.end (), (DrawWall *) 0);
|
||
+
|
||
+ walls.erase (S, walls.end ());
|
||
+ }
|
||
+
|
||
+ void RenderFlatColumn (DrawWall *dw, DrawSurf& surf,
|
||
+ int x, int y1, int y2)
|
||
+ {
|
||
+ img_pixel_t *buf = view.screen->wbuf ();
|
||
+ img_pixel_t *wbuf = surf.img->wbuf ();
|
||
+
|
||
+ int tw = surf.img->width ();
|
||
+ int th = surf.img->height ();
|
||
+
|
||
+ float ang = XToAngle (x);
|
||
+ float modv = cos (ang - HALFPI);
|
||
+
|
||
+ float t_cos = cos (ONEPI + -view.angle + ang) / modv;
|
||
+ float t_sin = sin (ONEPI + -view.angle + ang) / modv;
|
||
+
|
||
+ buf += x + y1 * view.sw;
|
||
+
|
||
+ for (; y1 <= y2; y1++, buf += view.sw)
|
||
+ {
|
||
+ float dist = YToDist (y1, surf.tex_h);
|
||
+
|
||
+ int tx = int ( view.x + t_sin * dist) & (tw - 1);
|
||
+ int ty = int (-view.y - t_cos * dist) & (th - 1);
|
||
+
|
||
+ *buf = wbuf[ty * tw + tx];
|
||
+ }
|
||
+ }
|
||
+
|
||
+ void RenderTexColumn (DrawWall *dw, DrawSurf& surf,
|
||
+ int x, int y1, int y2)
|
||
+ {
|
||
+ img_pixel_t *buf = view.screen->wbuf ();
|
||
+ img_pixel_t *wbuf = surf.img->wbuf ();
|
||
+
|
||
+ int tw = surf.img->width ();
|
||
+ int th = surf.img->height ();
|
||
+
|
||
+ /* compute texture X coord */
|
||
+
|
||
+ int tx = int (dw->t_dist - tan (dw->cur_ang - dw->normal) * dw->dist);
|
||
+
|
||
+ tx = (dw->sd->xoff + tx) & (tw - 1);
|
||
+
|
||
+ /* compute texture Y coords */
|
||
+
|
||
+ float base_h = surf.tex_h + dw->sd->yoff;
|
||
+
|
||
+ float h1 = base_h - YToSecH (y1, dw->cur_iz);
|
||
+ float dh = base_h - YToSecH (y2, dw->cur_iz);
|
||
+
|
||
+ dh = (dh - h1) / y_max (1, y2 - y1);
|
||
+
|
||
+ buf += x + y1 * view.sw;
|
||
+ wbuf += tx;
|
||
+
|
||
+ for (; y1 <= y2; y1++, h1 += dh, buf += view.sw)
|
||
+ {
|
||
+ int ty = int (h1) % th;
|
||
+
|
||
+ // handle negative values (use % twice)
|
||
+ ty = (ty + th) % th;
|
||
+
|
||
+ *buf = wbuf[ty * tw];
|
||
+ }
|
||
+ }
|
||
+
|
||
+ void RenderSolidColumn (DrawWall *w, DrawSurf& surf,
|
||
+ int x, int y1, int y2)
|
||
+ {
|
||
+ img_pixel_t *buf = view.screen->wbuf ();
|
||
+
|
||
+ buf += x + y1 * view.sw;
|
||
+
|
||
+ for (; y1 <= y2; y1++, buf += view.sw)
|
||
+ {
|
||
+ *buf = surf.col;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ inline void RenderWallSurface (DrawWall *dw, DrawSurf& surf,
|
||
+ int x)
|
||
+ {
|
||
+ if (surf.kind == DrawSurf::K_INVIS)
|
||
+ return;
|
||
+
|
||
+ int y1 = DistToY (dw->cur_iz, surf.h1);
|
||
+ int y2 = DistToY (dw->cur_iz, surf.h2) - 1;
|
||
+
|
||
+ if (y1 < open_y1)
|
||
+ y1 = open_y1;
|
||
+
|
||
+ if (y2 > open_y2)
|
||
+ y2 = open_y2;
|
||
+
|
||
+ if (y1 > y2)
|
||
+ return;
|
||
+
|
||
+ /* clip the open region */
|
||
+
|
||
+ if (surf.y_clip & DrawSurf::SOLID_ABOVE)
|
||
+ if (y2 > open_y1)
|
||
+ open_y1 = y2;
|
||
+
|
||
+ if (surf.y_clip & DrawSurf::SOLID_BELOW)
|
||
+ if (y1 < open_y2)
|
||
+ open_y2 = y1;
|
||
+
|
||
+ /* fill pixels */
|
||
+
|
||
+ if (! surf.img)
|
||
+ {
|
||
+ RenderSolidColumn (dw, surf, x, y1, y2);
|
||
+ }
|
||
+ else switch (surf.kind)
|
||
+ {
|
||
+ case DrawSurf::K_FLAT:
|
||
+ RenderFlatColumn (dw, surf, x, y1, y2);
|
||
+ break;
|
||
+
|
||
+ case DrawSurf::K_TEXTURE:
|
||
+ RenderTexColumn (dw, surf, x, y1, y2);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ inline void RenderSprite (DrawWall *dw, int x)
|
||
+ {
|
||
+ int y1 = DistToY (dw->cur_iz, dw->ceil.h1);
|
||
+ int y2 = DistToY (dw->cur_iz, dw->ceil.h2) - 1;
|
||
+
|
||
+ if (y1 < dw->oy1)
|
||
+ y1 = dw->oy1;
|
||
+
|
||
+ if (y2 > dw->oy2)
|
||
+ y2 = dw->oy2;
|
||
+
|
||
+ if (y1 > y2)
|
||
+ return;
|
||
+
|
||
+ /* fill pixels */
|
||
+
|
||
+ img_pixel_t *buf = view.screen->wbuf ();
|
||
+ img_pixel_t *wbuf = dw->ceil.img->wbuf ();
|
||
+
|
||
+ int tw = dw->ceil.img->width ();
|
||
+ int th = dw->ceil.img->height ();
|
||
+
|
||
+ int tx = int (XToDelta (x, dw->cur_iz) - dw->spr_tx1);
|
||
+
|
||
+ if (tx < 0 || tx >= tw)
|
||
+ return;
|
||
+
|
||
+ float h1 = dw->ceil.h1 - YToSecH (y1, dw->cur_iz);
|
||
+ float dh = dw->ceil.h1 - YToSecH (y2, dw->cur_iz);
|
||
+
|
||
+ dh = (dh - h1) / y_max (1, y2 - y1);
|
||
+
|
||
+ buf += x + y1 * view.sw;
|
||
+ wbuf += tx;
|
||
+
|
||
+ for (; y1 <= y2; y1++, h1 += dh, buf += view.sw)
|
||
+ {
|
||
+ int ty = int (h1);
|
||
+
|
||
+ if (ty < 0 || ty >= th)
|
||
+ continue;
|
||
+
|
||
+ img_pixel_t pix = wbuf[ty * tw];
|
||
+
|
||
+ if (pix != IMG_TRANSP)
|
||
+ *buf = pix;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ void UpdateActiveList (int x)
|
||
+ {
|
||
+ DrawWall::vec_t::iterator S, E, P;
|
||
+
|
||
+ bool changes = false;
|
||
+
|
||
+ // remove walls that have finished.
|
||
+
|
||
+ S = active.begin ();
|
||
+ E = active.end ();
|
||
+
|
||
+ S = std::remove_if (S, E, DrawWall::SX2Less (x));
|
||
+
|
||
+ if (S != E)
|
||
+ {
|
||
+ active.erase (S, E);
|
||
+ changes = true;
|
||
+ }
|
||
+
|
||
+ // add new walls that start in this column.
|
||
+
|
||
+ S = walls.begin ();
|
||
+ E = walls.end ();
|
||
+
|
||
+ S = std::lower_bound (S, E, x, DrawWall::SX1Cmp ());
|
||
+ E = std::upper_bound (S, E, x, DrawWall::SX1Cmp ());
|
||
+
|
||
+ if (S != E)
|
||
+ changes = true;
|
||
+
|
||
+ for (; S != E; S++)
|
||
+ {
|
||
+ active.push_back (*S);
|
||
+ }
|
||
+
|
||
+ // calculate new depth values
|
||
+
|
||
+ S = active.begin ();
|
||
+ E = active.end ();
|
||
+
|
||
+ for (P=S; (P != E); P++)
|
||
+ {
|
||
+ DrawWall *dw = (*P);
|
||
+
|
||
+ dw->cur_iz = dw->iz1 + dw->diz * (x - dw->sx1);
|
||
+
|
||
+ if (P != S && (*(P-1))->cur_iz < dw->cur_iz)
|
||
+ changes = true;
|
||
+
|
||
+ dw->cur_ang = dw->ang1 + dw->dang * (x - dw->sx1);
|
||
+ }
|
||
+
|
||
+ // if there are changes, re-sort the active list...
|
||
+
|
||
+ if (changes)
|
||
+ {
|
||
+ std::sort (active.begin (), active.end (), DrawWall::DistCmp ());
|
||
+ }
|
||
+ }
|
||
+
|
||
+ void RenderWalls ()
|
||
+ {
|
||
+ // sort walls by their starting column, to allow binary search.
|
||
+
|
||
+ std::sort (walls.begin (), walls.end (), DrawWall::SX1Cmp ());
|
||
+
|
||
+ active.clear ();
|
||
+
|
||
+ for (int x=0; x < view.sw; x++)
|
||
+ {
|
||
+ // clear vertical depth buffer
|
||
+
|
||
+ open_y1 = 0;
|
||
+ open_y2 = view.sh - 1;
|
||
+
|
||
+ UpdateActiveList (x);
|
||
+
|
||
+ // render, front to back
|
||
+
|
||
+ DrawWall::vec_t::iterator S, E, P;
|
||
+
|
||
+ S = active.begin ();
|
||
+ E = active.end ();
|
||
+
|
||
+ for (P=S; P != E; P++)
|
||
+ {
|
||
+ DrawWall *dw = (*P);
|
||
+
|
||
+ // for things, just remember the open space
|
||
+ if (dw->th)
|
||
+ {
|
||
+ dw->oy1 = open_y1;
|
||
+ dw->oy2 = open_y2;
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ RenderWallSurface (dw, dw->ceil, x);
|
||
+ RenderWallSurface (dw, dw->floor, x);
|
||
+ RenderWallSurface (dw, dw->upper, x);
|
||
+ RenderWallSurface (dw, dw->lower, x);
|
||
+
|
||
+ if (open_y1 >= open_y2)
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ // now render things, back to front
|
||
+
|
||
+ if (P == E)
|
||
+ P--;
|
||
+
|
||
+ for (; P != (S-1); P--)
|
||
+ {
|
||
+ DrawWall *dw = (*P);
|
||
+
|
||
+ if (dw->th)
|
||
+ RenderSprite (dw, x);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ void DoRender3D ()
|
||
+ {
|
||
+ view.ClearScreen ();
|
||
+
|
||
+ InitDepthBuf (view.sw);
|
||
+
|
||
+ for (int i=0; i < NumLineDefs; i++)
|
||
+ AddLine (i);
|
||
+
|
||
+ if (view.sprites)
|
||
+ for (int j=0; j < NumThings; j++)
|
||
+ AddThing (j);
|
||
+
|
||
+ ClipSolids ();
|
||
+ ComputeSurfaces ();
|
||
+ RenderWalls ();
|
||
+ }
|
||
+};
|
||
+
|
||
+
|
||
+static Thing *FindPlayer (int typenum)
|
||
+{
|
||
+for (int i=0; i < NumThings; i++)
|
||
+ if (Things[i].type == typenum)
|
||
+ return Things + i;
|
||
+
|
||
+return 0;
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ * Render a 3D view from the player's position.
|
||
+ */
|
||
+
|
||
+void Render3D ()
|
||
+{
|
||
+if (! view.p_type)
|
||
+ {
|
||
+ view.p_type = THING_PLAYER1;
|
||
+ view.px = 99999;
|
||
+ }
|
||
+
|
||
+Thing *player = FindPlayer (view.p_type);
|
||
+
|
||
+if (! player)
|
||
+ {
|
||
+ if (view.p_type != THING_DEATHMATCH)
|
||
+ view.p_type = THING_DEATHMATCH;
|
||
+
|
||
+ player = FindPlayer (view.p_type);
|
||
+
|
||
+ if (! player)
|
||
+ return;
|
||
+ }
|
||
+
|
||
+if (view.px != player->xpos || view.py != player->ypos)
|
||
+ {
|
||
+ // if player moved, re-create view parameters
|
||
+
|
||
+ view.x = view.px = player->xpos;
|
||
+ view.y = view.py = player->ypos;
|
||
+
|
||
+ view.CalcViewZ ();
|
||
+ view.SetAngle (player->angle * ONEPI / 180.0);
|
||
+ }
|
||
+
|
||
+/* create image */
|
||
+
|
||
+view.sw = 320;
|
||
+view.sh = 200;
|
||
+
|
||
+view.screen = new Img ((unsigned short int) view.sw, (unsigned short int) view.sh, false);
|
||
+view.im_ch = new ImageCache;
|
||
+
|
||
+view.FindThingFloors ();
|
||
+
|
||
+bool Redraw = true;
|
||
+
|
||
+/* input loop */
|
||
+
|
||
+for (;;)
|
||
+ {
|
||
+ /* render image */
|
||
+
|
||
+ if (Redraw)
|
||
+ {
|
||
+ if (view.walking)
|
||
+ view.CalcViewZ ();
|
||
+
|
||
+ RendInfo rend;
|
||
+
|
||
+ rend.DoRender3D ();
|
||
+
|
||
+ view.PutScreen (40, 40);
|
||
+
|
||
+ Redraw = false;
|
||
+ }
|
||
+
|
||
+ /* handle keypress */
|
||
+
|
||
+ int key = get_key ();
|
||
+
|
||
+ if (key == YK_ESC || key == 'q')
|
||
+ break;
|
||
+
|
||
+ if ((key & ~YK_SHIFT) == YK_LEFT)
|
||
+ {
|
||
+ view.SetAngle (view.angle + ONEPI / ((key & YK_SHIFT) ? 4 : 8));
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if ((key & ~YK_SHIFT) == YK_RIGHT)
|
||
+ {
|
||
+ view.SetAngle (view.angle -ONEPI / ((key & YK_SHIFT) ? 4 : 8));
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if ((key & ~YK_SHIFT) == YK_UP)
|
||
+ {
|
||
+ view.x += view.Cos * ((key & YK_SHIFT) ? 192 : 32);
|
||
+ view.y += view.Sin * ((key & YK_SHIFT) ? 192 : 32);
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if ((key & ~YK_SHIFT) == YK_DOWN)
|
||
+ {
|
||
+ view.x -= view.Cos * ((key & YK_SHIFT) ? 192 : 32);
|
||
+ view.y -= view.Sin * ((key & YK_SHIFT) ? 192 : 32);
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if (key == 'n' || key == 'N')
|
||
+ {
|
||
+ view.x -= view.Sin * ((key == 'N') ? 192 : 32);
|
||
+ view.y += view.Cos * ((key == 'N') ? 192 : 32);
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if (key == 'm' || key == 'M')
|
||
+ {
|
||
+ view.x += view.Sin * ((key == 'M') ? 192 : 32);
|
||
+ view.y -= view.Cos * ((key == 'M') ? 192 : 32);
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if (key == 'd' || key == 'D')
|
||
+ {
|
||
+ view.z += (key == 'D') ? 128 : 32;
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if (key == 'c' || key == 'C')
|
||
+ {
|
||
+ view.z -= (key == 'C') ? 128 : 32;
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if (key == 't')
|
||
+ {
|
||
+ view.texturing = ! view.texturing;
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if (key == 's')
|
||
+ {
|
||
+ view.sprites = ! view.sprites;
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if (key == 'w')
|
||
+ {
|
||
+ view.walking = ! view.walking;
|
||
+ Redraw = true;
|
||
+ }
|
||
+ else if (key)
|
||
+ {
|
||
+ // key no good, get another one
|
||
+ Beep ();
|
||
+ }
|
||
+ }
|
||
+
|
||
+/* all done */
|
||
+
|
||
+delete view.screen;
|
||
+view.screen = 0;
|
||
+
|
||
+delete view.im_ch;
|
||
+view.im_ch = 0;
|
||
+
|
||
+delete[] view.thing_floors;
|
||
+view.thing_floors = 0;
|
||
+}
|
||
+
|
||
diff -u -r -N yadex-1.7.0/src/r_render.h yadex-1.7.0-all/src/r_render.h
|
||
--- yadex-1.7.0/src/r_render.h 1970-01-01 10:00:00.000000000 +1000
|
||
+++ yadex-1.7.0-all/src/r_render.h 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -0,0 +1,14 @@
|
||
+/*
|
||
+ * r_render.h
|
||
+ * AJA 2002-04-27
|
||
+ */
|
||
+
|
||
+
|
||
+#ifndef YH_R_RENDER /* DO NOT INSERT ANYTHING BEFORE THIS LINE */
|
||
+#define YH_R_RENDER
|
||
+
|
||
+
|
||
+void Render3D ();
|
||
+
|
||
+
|
||
+#endif /* DO NOT ADD ANYTHING AFTER THIS LINE */
|
||
diff -u -r -N yadex-1.7.0/src/s_misc.cc yadex-1.7.0-all/src/s_misc.cc
|
||
--- yadex-1.7.0/src/s_misc.cc 2003-03-28 23:37:32.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/s_misc.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -29,11 +29,15 @@
|
||
|
||
|
||
#include "yadex.h"
|
||
+#include <math.h>
|
||
+
|
||
#include "entry.h"
|
||
#include "gfx.h"
|
||
#include "levels.h"
|
||
#include "objid.h"
|
||
#include "selectn.h"
|
||
+#include "objects.h"
|
||
+#include "dialog.h"
|
||
|
||
|
||
/*
|
||
@@ -179,4 +183,340 @@
|
||
MadeChanges = 1;
|
||
}
|
||
|
||
+
|
||
+static int find_linedef_for_area (int x, int y, int& side)
|
||
+{
|
||
+ int n, m, curx;
|
||
+ int best_match = -1;
|
||
+
|
||
+ curx = 32767; // Oh yes, one more hard-coded constant!
|
||
+
|
||
+ for (n = 0; n < NumLineDefs; n++)
|
||
+ if ((Vertices[LineDefs[n].start].y > y)
|
||
+ != (Vertices[LineDefs[n].end].y > y))
|
||
+ {
|
||
+ int lx0 = Vertices[LineDefs[n].start].x;
|
||
+ int ly0 = Vertices[LineDefs[n].start].y;
|
||
+ int lx1 = Vertices[LineDefs[n].end].x;
|
||
+ int ly1 = Vertices[LineDefs[n].end].y;
|
||
+ m = lx0 + (int) ((long) (y - ly0) * (long) (lx1 - lx0)
|
||
+ / (long) (ly1 - ly0));
|
||
+ if (m >= x && m < curx)
|
||
+ {
|
||
+ curx = m;
|
||
+ best_match = n;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* now look if this linedef has a sidedef bound to one sector */
|
||
+ if (best_match < 0)
|
||
+ return OBJ_NO_NONE;
|
||
+
|
||
+ if (Vertices[LineDefs[best_match].start].y
|
||
+ > Vertices[LineDefs[best_match].end].y)
|
||
+ side = 1;
|
||
+ else
|
||
+ side = 2;
|
||
+
|
||
+ return best_match;
|
||
+}
|
||
+
|
||
+/*
|
||
+ compute the angle between lines AB and BC, going anticlockwise.
|
||
+ result is in degrees 0 - 359. A, B and C are vertex indices.
|
||
+ -AJA- 2001-05-09
|
||
+ */
|
||
+#define DEBUG_ANGLE 0
|
||
+
|
||
+static double angle_between_linedefs (int A, int B, int C)
|
||
+{
|
||
+ int a_dx = Vertices[B].x - Vertices[A].x;
|
||
+ int a_dy = Vertices[B].y - Vertices[A].y;
|
||
+
|
||
+ int c_dx = Vertices[B].x - Vertices[C].x;
|
||
+ int c_dy = Vertices[B].y - Vertices[C].y;
|
||
+
|
||
+ double AB_angle = (a_dx == 0) ? (a_dy >= 0 ? 90 : -90) :
|
||
+ atan2 (a_dy, a_dx) * 180 / M_PI;
|
||
+
|
||
+ double CB_angle = (c_dx == 0) ? (c_dy >= 0 ? 90 : -90) :
|
||
+ atan2 (c_dy, c_dx) * 180 / M_PI;
|
||
+
|
||
+ double result = CB_angle - AB_angle;
|
||
+
|
||
+ if (result >= 360)
|
||
+ result -= 360;
|
||
+
|
||
+ while (result < 0)
|
||
+ result += 360;
|
||
+
|
||
+#if (DEBUG_ANGLE)
|
||
+ fprintf(stderr, "ANGLE %1.6f (%d,%d) -> (%d,%d) -> (%d,%d)\n",
|
||
+ result, Vertices[A].x, Vertices[A].y,
|
||
+ Vertices[B].x, Vertices[B].y, Vertices[C].x, Vertices[C].y);
|
||
+#endif
|
||
+
|
||
+ return result;
|
||
+}
|
||
+
|
||
+/*
|
||
+ follows the path clockwise from the given start line, adding each
|
||
+ line into the appropriate set. If the path is not closed, zero is
|
||
+ returned.
|
||
+
|
||
+ -AJA- 2001-05-09
|
||
+ */
|
||
+#define DEBUG_PATH 0
|
||
+
|
||
+static int select_sides_in_closed_path (bitvec_c& ld_side1,
|
||
+ bitvec_c& ld_side2, int line, int side)
|
||
+{
|
||
+ int cur_vert, prev_vert, final_vert;
|
||
+
|
||
+ if (side == 1)
|
||
+ {
|
||
+ ld_side1.set (line);
|
||
+ cur_vert = LineDefs[line].end;
|
||
+ prev_vert = final_vert = LineDefs[line].start;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ ld_side2.set (line);
|
||
+ cur_vert = LineDefs[line].start;
|
||
+ prev_vert = final_vert = LineDefs[line].end;
|
||
+ }
|
||
+
|
||
+#if (DEBUG_PATH)
|
||
+ fprintf(stderr, "PATH: line %d side %d cur %d final %d\n",
|
||
+ line, side, cur_vert, final_vert);
|
||
+#endif
|
||
+
|
||
+ while (cur_vert != final_vert)
|
||
+ {
|
||
+ int next_line = OBJ_NO_NONE;
|
||
+ int next_vert = OBJ_NO_NONE;
|
||
+ int next_side;
|
||
+ double best_angle = 999;
|
||
+
|
||
+ // Look for the next linedef in the path. It's the linedef that
|
||
+ // uses the current vertex and is not the current one.
|
||
+
|
||
+ for (int n = 0; n < NumLineDefs; n++)
|
||
+ {
|
||
+ if (n == line)
|
||
+ continue;
|
||
+
|
||
+ int other_vert;
|
||
+ int which_side;
|
||
+
|
||
+ if (LineDefs[n].start == cur_vert)
|
||
+ {
|
||
+ other_vert = LineDefs[n].end;
|
||
+ which_side = 1;
|
||
+ }
|
||
+ else if (LineDefs[n].end == cur_vert)
|
||
+ {
|
||
+ other_vert = LineDefs[n].start;
|
||
+ which_side = 2;
|
||
+ }
|
||
+ else
|
||
+ continue;
|
||
+
|
||
+ // found adjoining linedef
|
||
+
|
||
+ double angle = angle_between_linedefs (prev_vert, cur_vert,
|
||
+ other_vert);
|
||
+
|
||
+ if (! is_obj (next_line) || angle < best_angle)
|
||
+ {
|
||
+ next_line = n;
|
||
+ next_vert = other_vert;
|
||
+ next_side = which_side;
|
||
+
|
||
+ best_angle = angle;
|
||
+ }
|
||
+
|
||
+ // Continue the search
|
||
+ }
|
||
+
|
||
+ line = next_line;
|
||
+ side = next_side;
|
||
+
|
||
+#if (DEBUG_PATH)
|
||
+ fprintf(stderr, "PATH NEXT: line %d side %d vert %d angle %1.6f\n",
|
||
+ line, side, next_vert, best_angle);
|
||
+#endif
|
||
+
|
||
+ // None ? Path cannot be closed
|
||
+ if (! is_obj (line))
|
||
+ return 0;
|
||
+
|
||
+ // Line already seen ? Under normal circumstances this won't
|
||
+ // happen, but it _can_ happen and indicates a non-closed
|
||
+ // structure
|
||
+ if (ld_side1.get (line) || ld_side2.get (line))
|
||
+ return 0;
|
||
+
|
||
+ if (side == 1)
|
||
+ ld_side1.set (line);
|
||
+ else
|
||
+ ld_side2.set (line);
|
||
+
|
||
+ prev_vert = cur_vert;
|
||
+ cur_vert = next_vert;
|
||
+ }
|
||
+
|
||
+#if (DEBUG_PATH)
|
||
+ fprintf(stderr, "PATH CLOSED !\n");
|
||
+#endif
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+/*
|
||
+ update the side on a single linedef, using the given sector
|
||
+ reference. Will create a new sidedef if necessary.
|
||
+ */
|
||
+static void super_set_sector_on_side (int line, wad_sdn_t& side,
|
||
+ wad_sdn_t& other, int side_no, int sector)
|
||
+{
|
||
+ if (is_obj (side) && SideDefs[side].sector == sector)
|
||
+ {
|
||
+ // there was no change.
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ int must_flip = 0;
|
||
+
|
||
+ if (! is_obj (side))
|
||
+ {
|
||
+ // if we're adding a sidedef to a line that has no sides, and
|
||
+ // the sidedef would be the 2nd one, then flip the linedef.
|
||
+ // Thus we don't end up with invalid lines -- i.e. ones with a
|
||
+ // left side but no right side.
|
||
+
|
||
+ if (! is_obj (other) && side_no == 2)
|
||
+ must_flip = 1;
|
||
+
|
||
+ InsertObject (OBJ_SIDEDEFS, OBJ_NO_NONE, 0, 0);
|
||
+ side = NumSideDefs - 1;
|
||
+
|
||
+ // if we're adding a second side to the linedef, clear out some
|
||
+ // of the properties that aren't needed anymore: middle texture,
|
||
+ // two-sided flag, and impassible flag.
|
||
+
|
||
+ if (is_obj (other))
|
||
+ {
|
||
+ strncpy (SideDefs[side].tex3, "-", WAD_TEX_NAME);
|
||
+ strncpy (SideDefs[other].tex3, "-", WAD_TEX_NAME);
|
||
+
|
||
+ LineDefs[line].flags |= 4; // Set the 2S bit
|
||
+ LineDefs[line].flags &= ~1; // Clear the Im bit
|
||
+ }
|
||
+ }
|
||
+
|
||
+ SideDefs[side].sector = sector;
|
||
+
|
||
+ if (must_flip)
|
||
+ {
|
||
+ int temp = LineDefs[line].start;
|
||
+ LineDefs[line].start = LineDefs[line].end;
|
||
+ LineDefs[line].end = temp;
|
||
+
|
||
+ temp = side;
|
||
+ side = other;
|
||
+ other = temp;
|
||
+ }
|
||
+
|
||
+ MadeChanges = 1;
|
||
+ MadeMapChanges = 1;
|
||
+}
|
||
+
|
||
+static int super_find_sector_model (bitvec_c& ld_side1,
|
||
+ bitvec_c& ld_side2)
|
||
+{
|
||
+ for (int line=0; line < NumLineDefs; line++)
|
||
+ {
|
||
+ int side1 = LineDefs[line].sidedef1;
|
||
+ int side2 = LineDefs[line].sidedef2;
|
||
+
|
||
+ if (ld_side1.get (line))
|
||
+ if (is_obj (side2))
|
||
+ return SideDefs[side2].sector;
|
||
+
|
||
+ if (ld_side2.get (line))
|
||
+ if (is_obj (side1))
|
||
+ return SideDefs[side1].sector;
|
||
+ }
|
||
+
|
||
+ return OBJ_NO_NONE;
|
||
+}
|
||
+
|
||
+
|
||
+/*
|
||
+ Change the closed sector at the pointer
|
||
+
|
||
+ "sector" here really means a bunch of sidedefs that all face
|
||
+ inward to the current area under the mouse cursor. Two basic
|
||
+ operations: (a) set the sidedef sector references to a completely
|
||
+ new sector, or (b) set them to an existing sector. This is
|
||
+ controlled by the `new_sec' parameter.
|
||
+
|
||
+ -AJA- 2001-05-08
|
||
+ */
|
||
+
|
||
+void SuperSectorSelector (int map_x, int map_y, int new_sec)
|
||
+{
|
||
+ int line, side;
|
||
+ char msg_buf[200];
|
||
+
|
||
+ line = find_linedef_for_area (map_x, map_y, side);
|
||
+
|
||
+ if (! is_obj (line))
|
||
+ {
|
||
+ Beep ();
|
||
+ sprintf (msg_buf, "Chosen area is not closed");
|
||
+ Notify (-1, -1, msg_buf, NULL);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ bitvec_c ld_side1 (NumLineDefs);
|
||
+ bitvec_c ld_side2 (NumLineDefs);
|
||
+
|
||
+ int closed = select_sides_in_closed_path (ld_side1, ld_side2,
|
||
+ line, side);
|
||
+
|
||
+ if (! closed)
|
||
+ {
|
||
+ Beep ();
|
||
+ sprintf (msg_buf, "Area chosen is not closed");
|
||
+ Notify (-1, -1, msg_buf, NULL);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ // -AJA- FIXME: look for "islands", closed linedef paths that lie
|
||
+ // completely inside the area, i.e. not connected to the main path.
|
||
+ // Example: the two pillars at the start of MAP01 of DOOM 2. See
|
||
+ // GetOppositeSector() and the end of SplitSector() for a possible
|
||
+ // algorithm.
|
||
+
|
||
+ if (! is_obj (new_sec))
|
||
+ {
|
||
+ int model = super_find_sector_model (ld_side1, ld_side2);
|
||
+ InsertObject (OBJ_SECTORS, model, 0, 0);
|
||
+ new_sec = NumSectors - 1;
|
||
+ }
|
||
+
|
||
+ for (line=0; line < NumLineDefs; line++)
|
||
+ {
|
||
+ if (ld_side1.get (line))
|
||
+ super_set_sector_on_side (line, LineDefs[line].sidedef1,
|
||
+ LineDefs[line].sidedef2, 1, new_sec);
|
||
+
|
||
+ else if (ld_side2.get (line))
|
||
+ super_set_sector_on_side (line, LineDefs[line].sidedef2,
|
||
+ LineDefs[line].sidedef1, 2, new_sec);
|
||
+ }
|
||
+}
|
||
+
|
||
/* end of file */
|
||
diff -u -r -N yadex-1.7.0/src/s_prop.cc yadex-1.7.0-all/src/s_prop.cc
|
||
--- yadex-1.7.0/src/s_prop.cc 2003-03-28 23:37:32.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/s_prop.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -259,4 +259,67 @@
|
||
}
|
||
}
|
||
|
||
+/*
|
||
+ * InputSectorType
|
||
+ * Let the user select a sector type number and return it
|
||
+ * Returns 0 if OK, <>0 if cancelled
|
||
+ */
|
||
+int InputSectorType (int x0, int y0, int *number)
|
||
+{
|
||
+ int val;
|
||
+ val = 0;
|
||
+ *number = 0;
|
||
+ Menu_data_st menudata (stdef);
|
||
+ if (DisplayMenuList (x0 , y0, "Select type", menudata, &val)
|
||
+ < 0)
|
||
+ return 1;
|
||
+ // KLUDGE last element of stdef means "enter value"
|
||
+ if (val == al_lcount (stdef) - 1)
|
||
+ {
|
||
+ val = InputIntegerValue (x0 + 84,
|
||
+ y0 + BOX_BORDER + (3 + val) * FONTH,
|
||
+ -32768, 32767, 0);
|
||
+ if (val == IIV_CANCEL) // [Esc]
|
||
+ return 1;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (al_lseek (stdef, val, SEEK_SET))
|
||
+ fatal_error ("%s SP1 (%s)\n",
|
||
+ msg_unexpected, al_astrerror (al_aerrno));
|
||
+ val = CUR_STDEF->number;
|
||
+ }
|
||
+ if (val < 0) return 1; //unsuccessful
|
||
+ *number = val;
|
||
+ return 0; //successful
|
||
+}
|
||
+
|
||
+/*
|
||
+ * TransferSectorProperties
|
||
+ *
|
||
+ * -AJA- 2001-05-27
|
||
+ */
|
||
+void TransferSectorProperties (int src_sector, SelPtr sectors)
|
||
+{
|
||
+ SelPtr cur;
|
||
+
|
||
+ for (cur=sectors; cur; cur=cur->next)
|
||
+ {
|
||
+ if (! is_obj(cur->objnum))
|
||
+ continue;
|
||
+
|
||
+ strncpy (Sectors[cur->objnum].floort, Sectors[src_sector].floort,
|
||
+ WAD_FLAT_NAME);
|
||
+ strncpy (Sectors[cur->objnum].ceilt, Sectors[src_sector].ceilt,
|
||
+ WAD_FLAT_NAME);
|
||
+
|
||
+ Sectors[cur->objnum].floorh = Sectors[src_sector].floorh;
|
||
+ Sectors[cur->objnum].ceilh = Sectors[src_sector].ceilh;
|
||
+ Sectors[cur->objnum].light = Sectors[src_sector].light;
|
||
+ Sectors[cur->objnum].special = Sectors[src_sector].special;
|
||
+ Sectors[cur->objnum].tag = Sectors[src_sector].tag;
|
||
+
|
||
+ MadeChanges = 1;
|
||
+ }
|
||
+}
|
||
|
||
diff -u -r -N yadex-1.7.0/src/s_split.cc yadex-1.7.0-all/src/s_split.cc
|
||
--- yadex-1.7.0/src/s_split.cc 2003-03-28 23:37:32.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/s_split.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -36,6 +36,7 @@
|
||
#include "s_linedefs.h"
|
||
#include "selectn.h"
|
||
#include "x_hover.h"
|
||
+#include "entry.h"
|
||
|
||
|
||
/*
|
||
diff -u -r -N yadex-1.7.0/src/t_prop.cc yadex-1.7.0-all/src/t_prop.cc
|
||
--- yadex-1.7.0/src/t_prop.cc 2003-03-28 23:37:32.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/t_prop.cc 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -36,16 +36,17 @@
|
||
#include "gfx.h"
|
||
#include "levels.h"
|
||
#include "oldmenus.h"
|
||
+#include "objid.h"
|
||
+#include "objects.h"
|
||
#include "selectn.h"
|
||
#include "things.h"
|
||
|
||
-
|
||
/*
|
||
* Private functions prototypes
|
||
*/
|
||
-static int InputThingType (int x0, int y0, int *number);
|
||
static const char *PrintThinggroup (void *ptr);
|
||
static const char *PrintThingdef (void *ptr);
|
||
+int InputThingType (int x0, int y0, int *number);
|
||
|
||
|
||
/*
|
||
@@ -250,7 +251,7 @@
|
||
* Let the user select a thing number and return it.
|
||
* Returns 0 if OK, <>0 if cancelled
|
||
*/
|
||
-static int InputThingType (int x0, int y0, int *number)
|
||
+int InputThingType (int x0, int y0, int *number)
|
||
{
|
||
int r;
|
||
int tgno = 0;
|
||
@@ -331,4 +332,30 @@
|
||
}
|
||
|
||
|
||
+/*
|
||
+ * TransferThingProperties
|
||
+ *
|
||
+ * -AJA- 2001-05-27
|
||
+ */
|
||
+void TransferThingProperties (int src_thing, SelPtr things)
|
||
+{
|
||
+ SelPtr cur;
|
||
+
|
||
+ for (cur=things; cur; cur=cur->next)
|
||
+ {
|
||
+ if (! is_obj(cur->objnum))
|
||
+ continue;
|
||
+
|
||
+ Things[cur->objnum].angle = Things[src_thing].angle;
|
||
+ Things[cur->objnum].type = Things[src_thing].type;
|
||
+ Things[cur->objnum].when = Things[src_thing].when;
|
||
+
|
||
+ MadeChanges = 1;
|
||
+
|
||
+ things_types++;
|
||
+ things_angles++;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
/* end of file */
|
||
diff -u -r -N yadex-1.7.0/src/yadex.h yadex-1.7.0-all/src/yadex.h
|
||
--- yadex-1.7.0/src/yadex.h 2003-12-15 11:37:45.000000000 +1100
|
||
+++ yadex-1.7.0-all/src/yadex.h 2005-01-10 14:30:53.000000000 +1100
|
||
@@ -479,6 +479,7 @@
|
||
|
||
// l_prop.cc (previously in editobj.cc)
|
||
void LinedefProperties (int x0, int y0, SelPtr obj);
|
||
+void TransferLinedefProperties (int src_linedef, SelPtr linedefs);
|
||
|
||
// l_unlink.cc
|
||
void unlink_sidedef (SelPtr linedefs, int side1, int side2);
|
||
@@ -541,13 +542,16 @@
|
||
void DistributeSectorCeilings (SelPtr); /* SWAP! */
|
||
void RaiseOrLowerSectors (SelPtr obj);
|
||
void BrightenOrDarkenSectors (SelPtr obj);
|
||
+void SuperSectorSelector (int map_x, int map_y, int new_sec);
|
||
|
||
// s_prop.cc (previously in editobj.cc)
|
||
void SectorProperties (int x0, int y0, SelPtr obj);
|
||
+void TransferSectorProperties (int src_sector, SelPtr sectors);
|
||
|
||
// s_split.cc (previously in objects.cc)
|
||
void SplitSector (int, int); /* SWAP! */
|
||
void SplitLineDefsAndSector (int, int); /* SWAP! */
|
||
+void MultiSplitLineDefsAndSector (int, int); /* SWAP! */
|
||
|
||
// swapmem.cc
|
||
void InitSwap (void);
|
||
@@ -560,6 +564,7 @@
|
||
// selrect.cc
|
||
// t_prop.c (previously in editobj.c)
|
||
void ThingProperties (int x0, int y0, SelPtr obj);
|
||
+void TransferThingProperties (int src_thing, SelPtr things);
|
||
|
||
// v_merge.cc
|
||
void DeleteVerticesJoinLineDefs (SelPtr ); /* SWAP! */
|