1 /*
2 ** p_3dmidtex.cpp
3 **
4 ** Eternity-style 3D-midtex handling
5 ** (No original Eternity code here!)
6 **
7 **---------------------------------------------------------------------------
8 ** Copyright 2008 Christoph Oelckers
9 ** All rights reserved.
10 **
11 ** Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions
13 ** are met:
14 **
15 ** 1. Redistributions of source code must retain the above copyright
16 **    notice, this list of conditions and the following disclaimer.
17 ** 2. Redistributions in binary form must reproduce the above copyright
18 **    notice, this list of conditions and the following disclaimer in the
19 **    documentation and/or other materials provided with the distribution.
20 ** 3. The name of the author may not be used to endorse or promote products
21 **    derived from this software without specific prior written permission.
22 **
23 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 **---------------------------------------------------------------------------
34 **
35 */
36 
37 
38 #include "templates.h"
39 #include "p_local.h"
40 #include "p_terrain.h"
41 
42 
43 //============================================================================
44 //
45 // P_Scroll3dMidtex
46 //
47 // Scrolls all sidedefs belonging to 3dMidtex lines attached to this sector
48 //
49 //============================================================================
50 
P_Scroll3dMidtex(sector_t * sector,int crush,fixed_t move,bool ceiling)51 bool P_Scroll3dMidtex(sector_t *sector, int crush, fixed_t move, bool ceiling)
52 {
53 	extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor;
54 
55 	// First step: Change all lines' texture offsets
56 	for(unsigned i = 0; i < scrollplane.AttachedLines.Size(); i++)
57 	{
58 		line_t *l = scrollplane.AttachedLines[i];
59 
60 		l->sidedef[0]->AddTextureYOffset(side_t::mid, move);
61 		l->sidedef[1]->AddTextureYOffset(side_t::mid, move);
62 	}
63 
64 	// Second step: Check all sectors whether the move is ok.
65 	bool res = false;
66 
67 	for(unsigned i = 0; i < scrollplane.AttachedSectors.Size(); i++)
68 	{
69 		res |= P_ChangeSector(scrollplane.AttachedSectors[i], crush, move, 2, true);
70 	}
71 	return !res;
72 }
73 
74 //============================================================================
75 //
76 // P_Start3DMidtexInterpolations
77 //
78 // Starts interpolators for every sidedef that is being changed by moving
79 // this sector
80 //
81 //============================================================================
82 
P_Start3dMidtexInterpolations(TArray<DInterpolation * > & list,sector_t * sector,bool ceiling)83 void P_Start3dMidtexInterpolations(TArray<DInterpolation *> &list, sector_t *sector, bool ceiling)
84 {
85 	extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor;
86 
87 	for(unsigned i = 0; i < scrollplane.AttachedLines.Size(); i++)
88 	{
89 		line_t *l = scrollplane.AttachedLines[i];
90 
91 		list.Push(l->sidedef[0]->SetInterpolation(side_t::mid));
92 		list.Push(l->sidedef[1]->SetInterpolation(side_t::mid));
93 	}
94 }
95 
96 //============================================================================
97 //
98 // P_Attach3dMidtexLinesToSector
99 //
100 // Attaches 3dMidtex lines to a sector.
101 // If lineid is != 0, all lines with the matching line id will be added
102 // If tag is != 0, all lines touching a sector with the matching tag will be added
103 // If both are != 0, all lines with the matching line id that touch a sector with
104 // the matching tag will be added.
105 //
106 //============================================================================
107 
P_Attach3dMidtexLinesToSector(sector_t * sector,int lineid,int tag,bool ceiling)108 void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool ceiling)
109 {
110 	int v;
111 
112 	if (lineid == 0 && tag == 0)
113 	{
114 		// invalid set of parameters
115 		return;
116 	}
117 
118 	extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor;
119 
120 	// Bit arrays that mark whether a line or sector is to be attached.
121 	BYTE *found_lines = new BYTE[(numlines+7)/8];
122 	BYTE *found_sectors = new BYTE[(numsectors+7)/8];
123 
124 	memset(found_lines, 0, sizeof (BYTE) * ((numlines+7)/8));
125 	memset(found_sectors, 0, sizeof (BYTE) * ((numsectors+7)/8));
126 
127 	// mark all lines and sectors that are already attached to this one
128 	// and clear the arrays. The old data will be re-added automatically
129 	// from the marker arrays.
130 	for (unsigned i=0; i < scrollplane.AttachedLines.Size(); i++)
131 	{
132 		int line = int(scrollplane.AttachedLines[i] - lines);
133 		found_lines[line>>3] |= 1 << (line&7);
134 	}
135 
136 	for (unsigned i=0; i < scrollplane.AttachedSectors.Size(); i++)
137 	{
138 		int sec = int(scrollplane.AttachedSectors[i] - sectors);
139 		found_sectors[sec>>3] |= 1 << (sec&7);
140 	}
141 
142 	scrollplane.AttachedLines.Clear();
143 	scrollplane.AttachedSectors.Clear();
144 
145 	if (tag == 0)
146 	{
147 		FLineIdIterator itr(lineid);
148 		int line;
149 		while ((line = itr.Next()) >= 0)
150 		{
151 			line_t *ln = &lines[line];
152 
153 			if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
154 			{
155 				// Only consider two-sided lines with the 3DMIDTEX flag
156 				continue;
157 			}
158 			found_lines[line>>3] |= 1 << (line&7);
159 		}
160 	}
161 	else
162 	{
163 		FSectorTagIterator it(tag);
164 		int sec;
165 		while ((sec = it.Next()) >= 0)
166 		{
167 			for (int line = 0; line < sectors[sec].linecount; line ++)
168 			{
169 				line_t *ln = sectors[sec].lines[line];
170 
171 				if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue;
172 
173 				if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
174 				{
175 					// Only consider two-sided lines with the 3DMIDTEX flag
176 					continue;
177 				}
178 				int lineno = int(ln-lines);
179 				found_lines[lineno>>3] |= 1 << (lineno&7);
180 			}
181 		}
182 	}
183 
184 
185 	for(int i=0; i < numlines; i++)
186 	{
187 		if (found_lines[i>>3] & (1 << (i&7)))
188 		{
189 			scrollplane.AttachedLines.Push(&lines[i]);
190 
191 			v = int(lines[i].frontsector - sectors);
192 			assert(v < numsectors);
193 			found_sectors[v>>3] |= 1 << (v&7);
194 
195 			v = int(lines[i].backsector - sectors);
196 			assert(v < numsectors);
197 			found_sectors[v>>3] |= 1 << (v&7);
198 		}
199 	}
200 
201 	for (int i=0; i < numsectors; i++)
202 	{
203 		if (found_sectors[i>>3] & (1 << (i&7)))
204 		{
205 			scrollplane.AttachedSectors.Push(&sectors[i]);
206 		}
207 	}
208 
209 	delete[] found_lines;
210 	delete[] found_sectors;
211 }
212 
213 
214 //============================================================================
215 //
216 // P_GetMidTexturePosition
217 //
218 // Retrieves top and bottom of the current line's mid texture.
219 //
220 //============================================================================
P_GetMidTexturePosition(const line_t * line,int sideno,fixed_t * ptextop,fixed_t * ptexbot)221 bool P_GetMidTexturePosition(const line_t *line, int sideno, fixed_t *ptextop, fixed_t *ptexbot)
222 {
223 	if (line->sidedef[0]==NULL || line->sidedef[1]==NULL) return false;
224 
225 	side_t *side = line->sidedef[sideno];
226 	FTextureID texnum = side->GetTexture(side_t::mid);
227 	if (!texnum.isValid()) return false;
228 	FTexture * tex= TexMan(texnum);
229 	if (!tex) return false;
230 
231 	fixed_t totalscale = abs(FixedMul(side->GetTextureYScale(side_t::mid), tex->yScale));
232 	fixed_t y_offset = side->GetTextureYOffset(side_t::mid);
233 	fixed_t textureheight = tex->GetScaledHeight(totalscale) << FRACBITS;
234 	if (totalscale != FRACUNIT && !tex->bWorldPanning)
235 	{
236 		y_offset = FixedDiv(y_offset, totalscale);
237 	}
238 
239 	if(line->flags & ML_DONTPEGBOTTOM)
240 	{
241 		*ptexbot = y_offset +
242 			MAX<fixed_t>(line->frontsector->GetPlaneTexZ(sector_t::floor), line->backsector->GetPlaneTexZ(sector_t::floor));
243 
244 		*ptextop = *ptexbot + textureheight;
245 	}
246 	else
247 	{
248 		*ptextop = y_offset +
249 		   MIN<fixed_t>(line->frontsector->GetPlaneTexZ(sector_t::ceiling), line->backsector->GetPlaneTexZ(sector_t::ceiling));
250 
251 		*ptexbot = *ptextop - textureheight;
252 	}
253 	return true;
254 }
255 
256 
257 //============================================================================
258 //
259 // P_LineOpening_3dMidtex
260 //
261 // 3dMidtex part of P_LineOpening
262 //
263 //============================================================================
264 
P_LineOpening_3dMidtex(AActor * thing,const line_t * linedef,FLineOpening & open,bool restrict)265 bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening &open, bool restrict)
266 {
267 	// [TP] Impassible-like 3dmidtextures do not block missiles
268 	if ((linedef->flags & ML_3DMIDTEX_IMPASS)
269 		&& (thing->flags & MF_MISSILE || thing->BounceFlags & BOUNCE_MBF))
270 	{
271 		return false;
272 	}
273 
274 	fixed_t tt, tb;
275 
276 	open.abovemidtex = false;
277 	if (P_GetMidTexturePosition(linedef, 0, &tt, &tb))
278 	{
279 		if (thing->Z() + (thing->height/2) < (tt + tb)/2)
280 		{
281 			if (tb < open.top)
282 			{
283 				open.top = tb;
284 				open.ceilingpic = linedef->sidedef[0]->GetTexture(side_t::mid);
285 			}
286 		}
287 		else
288 		{
289 			if (tt > open.bottom && (!restrict || thing->Z() >= tt))
290 			{
291 				open.bottom = tt;
292 				open.abovemidtex = true;
293 				open.floorpic = linedef->sidedef[0]->GetTexture(side_t::mid);
294 				open.floorterrain = TerrainTypes[open.floorpic];
295 
296 			}
297 			// returns true if it touches the midtexture
298 			return (abs(thing->Z() - tt) <= thing->MaxStepHeight);
299 		}
300 	}
301 	return false;
302 
303 	/* still have to figure out what this code from Eternity means...
304 	if((linedef->flags & ML_BLOCKMONSTERS) &&
305 		!(mo->flags & (MF_FLOAT | MF_DROPOFF)) &&
306 		D_abs(mo->z - textop) <= 24*FRACUNIT)
307 	{
308 		opentop = openbottom;
309 		openrange = 0;
310 		return;
311 	}
312 	*/
313 }
314