void FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2) { double palcol, palstep; if (start > end) { swapvalues (start, end); swapvalues (pal1, pal2); } else if (start == end) { start = GPalette.Remap[start]; pal1 = GPalette.Remap[pal1]; Remap[start] = pal1; Palette[start] = GPalette.BaseColors[pal1]; Palette[start].a = start == 0 ? 0 : 255; return; } palcol = pal1; palstep = (pal2 - palcol) / (end - start); for (int i = start; i <= end; palcol += palstep, ++i) { int j = GPalette.Remap[i], k = GPalette.Remap[int(palcol)]; Remap[j] = k; Palette[j] = GPalette.BaseColors[k]; Palette[j].a = j == 0 ? 0 : 255; } }
FAnimDef *FTextureManager::ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing) { int type; FTextureID framenum; DWORD min, max; type = FAnimDef::ANIM_Forward; framenum = ParseFramenum (sc, picnum, usetype, missing); ParseTime (sc, min, max); if (framenum == picnum || !picnum.Exists() || !framenum.Exists()) { return NULL; // Animation is only one frame or does not exist } if (Texture(framenum)->Name.IsEmpty()) { // long texture name: We cannot do ranged anims on these because they have no defined order sc.ScriptError ("You cannot use \"range\" for long texture names."); } if (framenum < picnum) { type = FAnimDef::ANIM_Backward; Texture(framenum)->bNoDecals = Texture(picnum)->bNoDecals; swapvalues (framenum, picnum); } FAnimDef *ani = AddSimpleAnim (picnum, framenum - picnum + 1, min, max - min); if (ani != NULL) ani->AnimType = type; return ani; }
// // FWallCoords :: Init // // Transform and clip coordinates. Returns true if it was clipped away // bool FWallCoords::Init(int x1, int y1, int x2, int y2, int too_close) { tx1 = DMulScale20(x1, viewsin, -y1, viewcos); tx2 = DMulScale20(x2, viewsin, -y2, viewcos); ty1 = DMulScale20(x1, viewtancos, y1, viewtansin); ty2 = DMulScale20(x2, viewtancos, y2, viewtansin); if (MirrorFlags & RF_XFLIP) { int t = 256 - tx1; tx1 = 256 - tx2; tx2 = t; swapvalues(ty1, ty2); } if (tx1 >= -ty1) { if (tx1 > ty1) return true; // left edge is off the right side if (ty1 == 0) return true; sx1 = (centerxfrac + Scale(tx1, centerxfrac, ty1)) >> FRACBITS; if (tx1 >= 0) sx1 = MIN(viewwidth, sx1+1); // fix for signed divide sz1 = ty1; } else { if (tx2 < -ty2) return true; // wall is off the left side
void FTextureManager::ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing) { int type; FTextureID framenum; DWORD min, max; type = FAnimDef::ANIM_Forward; framenum = ParseFramenum (sc, picnum, usetype, missing); ParseTime (sc, min, max); if (framenum == picnum || !picnum.Exists()) { return; // Animation is only one frame or does not exist } if (framenum < picnum) { type = FAnimDef::ANIM_Backward; Texture(framenum)->bNoDecals = Texture(picnum)->bNoDecals; swapvalues (framenum, picnum); } if (sc.GetString()) { if (sc.Compare ("Oscillate")) { type = type == FAnimDef::ANIM_Forward ? FAnimDef::ANIM_OscillateUp : FAnimDef::ANIM_OscillateDown; } else { sc.UnGet (); } } AddSimpleAnim (picnum, framenum - picnum + 1, type, min, max - min); }
void FRemapTable::AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2) { if (IndexOutOfRange(start, end)) { return; } r1 = clamp(r1, 0.0, 2.0); g1 = clamp(g1, 0.0, 2.0); b1 = clamp(b1, 0.0, 2.0); r2 = clamp(r2, 0.0, 2.0); g2 = clamp(g2, 0.0, 2.0); b2 = clamp(b2, 0.0, 2.0); if (start > end) { swapvalues(start, end); swapvalues(r1, r2); swapvalues(g1, g2); swapvalues(b1, b2); } r2 -= r1; g2 -= g1; b2 -= b1; r1 *= 255; g1 *= 255; b1 *= 255; for(int c = start; c <= end; c++) { double intensity = (GPalette.BaseColors[c].r * 77 + GPalette.BaseColors[c].g * 143 + GPalette.BaseColors[c].b * 37) / 256.0; PalEntry pe = PalEntry( MIN(255, int(r1 + intensity*r2)), MIN(255, int(g1 + intensity*g2)), MIN(255, int(b1 + intensity*b2))); int cc = GPalette.Remap[c]; Remap[cc] = ColorMatcher.Pick(pe); Palette[cc] = pe; Palette[cc].a = cc == 0 ? 0:255; } }
void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, int _r2, int _g2, int _b2) { if (IndexOutOfRange(start, end)) { return; } double r1 = _r1; double g1 = _g1; double b1 = _b1; double r2 = _r2; double g2 = _g2; double b2 = _b2; double r, g, b; double rs, gs, bs; if (start > end) { swapvalues (start, end); r = r2; g = g2; b = b2; rs = r1 - r2; gs = g1 - g2; bs = b1 - b2; } else { r = r1; g = g1; b = b1; rs = r2 - r1; gs = g2 - g1; bs = b2 - b1; } if (start == end) { start = GPalette.Remap[start]; Palette[start] = PalEntry(start == 0 ? 0 : 255, int(r), int(g), int(b)); Remap[start] = ColorMatcher.Pick(Palette[start]); } else { rs /= (end - start); gs /= (end - start); bs /= (end - start); for (int i = start; i <= end; ++i) { int j = GPalette.Remap[i]; Palette[j] = PalEntry(j == 0 ? 0 : 255, int(r), int(g), int(b)); Remap[j] = ColorMatcher.Pick(Palette[j]); r += rs; g += gs; b += bs; } } }
// // FWallCoords :: Init // // Transform and clip coordinates. Returns true if it was clipped away // bool FWallCoords::Init(const DVector2 &pt1, const DVector2 &pt2, double too_close) { tleft.X = float(pt1.X * ViewSin - pt1.Y * ViewCos); tright.X = float(pt2.X * ViewSin - pt2.Y * ViewCos); tleft.Y = float(pt1.X * ViewTanCos + pt1.Y * ViewTanSin); tright.Y = float(pt2.X * ViewTanCos + pt2.Y * ViewTanSin); if (MirrorFlags & RF_XFLIP) { float t = -tleft.X; tleft.X = -tright.X; tright.X = t; swapvalues(tleft.Y, tright.Y); } if (tleft.X >= -tleft.Y) { if (tleft.X > tleft.Y) return true; // left edge is off the right side if (tleft.Y == 0) return true; sx1 = xs_RoundToInt(CenterX + tleft.X * CenterX / tleft.Y); sz1 = tleft.Y; } else { if (tright.X < -tright.Y) return true; // wall is off the left side float den = tleft.X - tright.X - tright.Y + tleft.Y; if (den == 0) return true; sx1 = 0; sz1 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X + tleft.Y) / den; } if (sz1 < too_close) return true; if (tright.X <= tright.Y) { if (tright.X < -tright.Y) return true; // right edge is off the left side if (tright.Y == 0) return true; sx2 = xs_RoundToInt(CenterX + tright.X * CenterX / tright.Y); sz2 = tright.Y; } else { if (tleft.X > tleft.Y) return true; // wall is off the right side float den = tright.Y - tleft.Y - tright.X + tleft.X; if (den == 0) return true; sx2 = viewwidth; sz2 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X - tleft.Y) / den; } if (sz2 < too_close || sx2 <= sx1) return true; return false; }
// Shuffles the playlist and resets the position to the start void FPlayList::Shuffle () { unsigned int numsongs = Songs.Size(); unsigned int i; for (i = 0; i < numsongs; ++i) { swapvalues (Songs[i], Songs[(rand() % (numsongs - i)) + i]); } Position = 0; }
void FWallTmapVals::InitFromWallCoords(const FWallCoords *wallc) { const FVector2 *left = &wallc->tleft; const FVector2 *right = &wallc->tright; if (MirrorFlags & RF_XFLIP) { swapvalues(left, right); } UoverZorg = left->X * centerx; UoverZstep = -left->Y; InvZorg = (left->X - right->X) * centerx; InvZstep = right->Y - left->Y; }
void D3DFB::WipeEndScreen() { if (!Accel2D) { Super::WipeEndScreen(); return; } // Don't do anything if there is no starting point. if (InitialWipeScreen == NULL) { return; } // If the whole screen was drawn without 2D accel, get it in to // video memory now. if (!In2D) { Begin2D(true); } EndBatch(); // Make sure all batched primitives have been drawn. // Don't do anything if there is no ending point. if (OldRenderTarget == NULL) { return; } // If these are different, reverse their roles so we don't need to // waste time copying from TempRenderTexture to FinalWipeScreen. if (FinalWipeScreen != TempRenderTexture) { swapvalues(RenderTexture[CurrRenderTexture], FinalWipeScreen); TempRenderTexture = RenderTexture[CurrRenderTexture]; } // At this point, InitialWipeScreen holds the screen we are wiping from. // FinalWipeScreen holds the screen we are wiping to, which may be the // same texture as TempRenderTexture. }
void PClass::StaticInit () { atterm (StaticShutdown); // Sort classes by name to remove dependance on how the compiler ordered them. REGINFO *head = &CRegHead; REGINFO *tail = &CRegTail; // MinGW's linker is linking the object files backwards for me now... if (head > tail) { swapvalues (head, tail); } qsort (head + 1, tail - head - 1, sizeof(REGINFO), cregcmp); FAutoSegIterator probe(CRegHead, CRegTail); while (*++probe != NULL) { ((ClassReg *)*probe)->RegisterClass (); } }
void FTextureManager::InitAnimated (void) { const BITFIELD texflags = TEXMAN_Overridable; // I think better not! This is only for old ANIMATED definitions that // don't know about ZDoom's more flexible texture system. // | FTextureManager::TEXMAN_TryAny; int lumpnum = Wads.CheckNumForName ("ANIMATED"); if (lumpnum != -1) { FMemLump animatedlump = Wads.ReadLump (lumpnum); int animatedlen = Wads.LumpLength(lumpnum); const char *animdefs = (const char *)animatedlump.GetMem(); const char *anim_p; FTextureID pic1, pic2; int animtype; DWORD animspeed; // Init animation animtype = FAnimDef::ANIM_Forward; for (anim_p = animdefs; *anim_p != -1; anim_p += 23) { // make sure the current chunk of data is inside the lump boundaries. if (anim_p + 22 >= animdefs + animatedlen) { I_Error("Tried to read past end of ANIMATED lump."); } if (*anim_p /* .istexture */ & 1) { // different episode ? if (!(pic1 = CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Wall, texflags)).Exists() || !(pic2 = CheckForTexture (anim_p + 1 /* .endname */, FTexture::TEX_Wall, texflags)).Exists()) continue; // [RH] Bit 1 set means allow decals on walls with this texture Texture(pic2)->bNoDecals = Texture(pic1)->bNoDecals = !(*anim_p & 2); } else { if (!(pic1 = CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Flat, texflags)).Exists() || !(pic2 = CheckForTexture (anim_p + 1 /* .startname */, FTexture::TEX_Flat, texflags)).Exists()) continue; } FTexture *tex1 = Texture(pic1); FTexture *tex2 = Texture(pic2); animspeed = (BYTE(anim_p[19]) << 0) | (BYTE(anim_p[20]) << 8) | (BYTE(anim_p[21]) << 16) | (BYTE(anim_p[22]) << 24); // SMMU-style swirly hack? Don't apply on already-warping texture if (animspeed > 65535 && tex1 != NULL && !tex1->bWarped) { FTexture *warper = new FWarp2Texture (tex1); ReplaceTexture (pic1, warper, false); } // These tests were not really relevant for swirling textures, or even potentially // harmful, so they have been moved to the else block. else { if (tex1->UseType != tex2->UseType) { // not the same type - continue; } if (debuganimated) { Printf("Defining animation '%s' (texture %d, lump %d, file %d) to '%s' (texture %d, lump %d, file %d)\n", tex1->Name, pic1.GetIndex(), tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()), tex2->Name, pic2.GetIndex(), tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump())); } if (pic1 == pic2) { // This animation only has one frame. Skip it. (Doom aborted instead.) Printf ("Animation %s in ANIMATED has only one frame\n", anim_p + 10); continue; } // [RH] Allow for backward animations as well as forward. else if (pic1 > pic2) { swapvalues (pic1, pic2); animtype = FAnimDef::ANIM_Backward; } // Speed is stored as tics, but we want ms so scale accordingly. AddSimpleAnim (pic1, pic2 - pic1 + 1, animtype, Scale (animspeed, 1000, 35)); } } } }
static void DoPrintStr(const char *cp, HWND edit, HANDLE StdOut) { if (edit == NULL && StdOut == NULL) return; char buf[256]; wchar_t wbuf[countof(buf)]; int bpos = 0; CHARRANGE selection; CHARRANGE endselection; LONG lines_before = 0, lines_after; CHARFORMAT format; if (edit != NULL) { // Store the current selection and set it to the end so we can append text. SendMessage(edit, EM_EXGETSEL, 0, (LPARAM)&selection); endselection.cpMax = endselection.cpMin = GetWindowTextLength(edit); SendMessage(edit, EM_EXSETSEL, 0, (LPARAM)&endselection); // GetWindowTextLength and EM_EXSETSEL can disagree on where the end of // the text is. Find out what EM_EXSETSEL thought it was and use that later. SendMessage(edit, EM_EXGETSEL, 0, (LPARAM)&endselection); // Remember how many lines there were before we added text. lines_before = (LONG)SendMessage(edit, EM_GETLINECOUNT, 0, 0); } while (*cp != 0) { // 28 is the escape code for a color change. if ((*cp == 28 && bpos != 0) || bpos == 255) { buf[bpos] = 0; if (edit != NULL) { ToEditControl(edit, buf, wbuf, bpos); } if (StdOut != NULL) { DWORD bytes_written; WriteFile(StdOut, buf, bpos, &bytes_written, NULL); } bpos = 0; } if (*cp != 28) { buf[bpos++] = *cp++; } else { const BYTE *color_id = (const BYTE *)cp + 1; EColorRange range = V_ParseFontColor(color_id, CR_UNTRANSLATED, CR_YELLOW); cp = (const char *)color_id; if (range != CR_UNDEFINED) { // Change the color of future text added to the control. PalEntry color = V_LogColorFromColorRange(range); if (StdOut != NULL && FancyStdOut) { // Unfortunately, we are pretty limited here: There are only // eight basic colors, and each comes in a dark and a bright // variety. float h, s, v, r, g, b; WORD attrib = 0; RGBtoHSV(color.r / 255.f, color.g / 255.f, color.b / 255.f, &h, &s, &v); if (s != 0) { // color HSVtoRGB(&r, &g, &b, h, 1, 1); if (r == 1) attrib = FOREGROUND_RED; if (g == 1) attrib |= FOREGROUND_GREEN; if (b == 1) attrib |= FOREGROUND_BLUE; if (v > 0.6) attrib |= FOREGROUND_INTENSITY; } else { // gray if (v < 0.33) attrib = FOREGROUND_INTENSITY; else if (v < 0.90) attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; else attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; } SetConsoleTextAttribute(StdOut, attrib); } if (edit != NULL) { // GDI uses BGR colors, but color is RGB, so swap the R and the B. swapvalues(color.r, color.b); // Change the color. format.cbSize = sizeof(format); format.dwMask = CFM_COLOR; format.dwEffects = 0; format.crTextColor = color; SendMessage(edit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); } } } } if (bpos != 0) { buf[bpos] = 0; if (edit != NULL) { ToEditControl(edit, buf, wbuf, bpos); } if (StdOut != NULL) { DWORD bytes_written; WriteFile(StdOut, buf, bpos, &bytes_written, NULL); } } if (edit != NULL) { // If the old selection was at the end of the text, keep it at the end and // scroll. Don't scroll if the selection is anywhere else. if (selection.cpMin == endselection.cpMin && selection.cpMax == endselection.cpMax) { selection.cpMax = selection.cpMin = GetWindowTextLength (edit); lines_after = (LONG)SendMessage(edit, EM_GETLINECOUNT, 0, 0); if (lines_after > lines_before) { SendMessage(edit, EM_LINESCROLL, 0, lines_after - lines_before); } } // Restore the previous selection. SendMessage(edit, EM_EXSETSEL, 0, (LPARAM)&selection); // Give the edit control a chance to redraw itself. I_GetEvent(); } if (StdOut != NULL && FancyStdOut) { // Set text back to gray, in case it was changed. SetConsoleTextAttribute(StdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); } }
static bool R_CheckBBox (fixed_t *bspcoord) // killough 1/28/98: static { int boxx; int boxy; int boxpos; double x1, y1, x2, y2; double rx1, ry1, rx2, ry2; int sx1, sx2; cliprange_t* start; // Find the corners of the box // that define the edges from current viewpoint. if (ViewPos.X <= FIXED2DBL(bspcoord[BOXLEFT])) boxx = 0; else if (ViewPos.X < FIXED2DBL(bspcoord[BOXRIGHT])) boxx = 1; else boxx = 2; if (ViewPos.Y >= FIXED2DBL(bspcoord[BOXTOP])) boxy = 0; else if (ViewPos.Y > FIXED2DBL(bspcoord[BOXBOTTOM])) boxy = 1; else boxy = 2; boxpos = (boxy<<2)+boxx; if (boxpos == 5) return true; x1 = FIXED2DBL(bspcoord[checkcoord[boxpos][0]]) - ViewPos.X; y1 = FIXED2DBL(bspcoord[checkcoord[boxpos][1]]) - ViewPos.Y; x2 = FIXED2DBL(bspcoord[checkcoord[boxpos][2]]) - ViewPos.X; y2 = FIXED2DBL(bspcoord[checkcoord[boxpos][3]]) - ViewPos.Y; // check clip list for an open space // Sitting on a line? if (y1 * (x1 - x2) + x1 * (y2 - y1) >= -EQUAL_EPSILON) return true; rx1 = x1 * ViewSin - y1 * ViewCos; rx2 = x2 * ViewSin - y2 * ViewCos; ry1 = x1 * ViewTanCos + y1 * ViewTanSin; ry2 = x2 * ViewTanCos + y2 * ViewTanSin; if (MirrorFlags & RF_XFLIP) { double t = -rx1; rx1 = -rx2; rx2 = t; swapvalues(ry1, ry2); } if (rx1 >= -ry1) { if (rx1 > ry1) return false; // left edge is off the right side if (ry1 == 0) return false; sx1 = xs_RoundToInt(CenterX + rx1 * CenterX / ry1); } else { if (rx2 < -ry2) return false; // wall is off the left side if (rx1 - rx2 - ry2 + ry1 == 0) return false; // wall does not intersect view volume sx1 = 0; } if (rx2 <= ry2) { if (rx2 < -ry2) return false; // right edge is off the left side if (ry2 == 0) return false; sx2 = xs_RoundToInt(CenterX + rx2 * CenterX / ry2); } else { if (rx1 > ry1) return false; // wall is off the right side if (ry2 - ry1 - rx2 + rx1 == 0) return false; // wall does not intersect view volume sx2 = viewwidth; } // Find the first clippost that touches the source post // (adjacent pixels are touching). // Does not cross a pixel. if (sx2 <= sx1) return false; start = solidsegs; while (start->last < sx2) start++; if (sx1 >= start->first && sx2 <= start->last) { // The clippost contains the new span. return false; } return true; }
void R_AddLine (seg_t *line) { static sector_t tempsec; // killough 3/8/98: ceiling/water hack bool solid; fixed_t tx1, tx2, ty1, ty2; curline = line; // [RH] Color if not texturing line dc_color = (((int)(line - segs) * 8) + 4) & 255; tx1 = line->v1->x - viewx; tx2 = line->v2->x - viewx; ty1 = line->v1->y - viewy; ty2 = line->v2->y - viewy; // Reject lines not facing viewer if (DMulScale32 (ty1, tx1-tx2, tx1, ty2-ty1) >= 0) return; if (WallC.Init(tx1, ty1, tx2, ty2, 32)) return; if (WallC.sx1 >= WindowRight || WallC.sx2 <= WindowLeft) return; if (line->linedef == NULL) { if (R_CheckClipWallSegment (WallC.sx1, WallC.sx2)) { InSubsector->flags |= SSECF_DRAWN; } return; } // reject lines that aren't seen from the portal (if any) // [ZZ] 10.01.2016: lines inside a skybox shouldn't be clipped, although this imposes some limitations on portals in skyboxes. if (!CurrentPortalInSkybox && CurrentPortal && P_ClipLineToPortal(line->linedef, CurrentPortal->dst, viewx, viewy)) return; vertex_t *v1, *v2; v1 = line->linedef->v1; v2 = line->linedef->v2; if ((v1 == line->v1 && v2 == line->v2) || (v2 == line->v1 && v1 == line->v2)) { // The seg is the entire wall. WallT.InitFromWallCoords(&WallC); } else { // The seg is only part of the wall. if (line->linedef->sidedef[0] != line->sidedef) { swapvalues (v1, v2); } WallT.InitFromLine(v1->x - viewx, v1->y - viewy, v2->x - viewx, v2->y - viewy); } if (!(fake3D & FAKE3D_FAKEBACK)) { backsector = line->backsector; } rw_frontcz1 = frontsector->ceilingplane.ZatPoint (line->v1->x, line->v1->y); rw_frontfz1 = frontsector->floorplane.ZatPoint (line->v1->x, line->v1->y); rw_frontcz2 = frontsector->ceilingplane.ZatPoint (line->v2->x, line->v2->y); rw_frontfz2 = frontsector->floorplane.ZatPoint (line->v2->x, line->v2->y); rw_mustmarkfloor = rw_mustmarkceiling = false; rw_havehigh = rw_havelow = false; // Single sided line? if (backsector == NULL || (line->linedef->isVisualPortal() && line->sidedef == line->linedef->sidedef[0])) { solid = true; } else { // kg3D - its fake, no transfer_heights if (!(fake3D & FAKE3D_FAKEBACK)) { // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water backsector = R_FakeFlat (backsector, &tempsec, NULL, NULL, true); } doorclosed = 0; // killough 4/16/98 rw_backcz1 = backsector->ceilingplane.ZatPoint (line->v1->x, line->v1->y); rw_backfz1 = backsector->floorplane.ZatPoint (line->v1->x, line->v1->y); rw_backcz2 = backsector->ceilingplane.ZatPoint (line->v2->x, line->v2->y); rw_backfz2 = backsector->floorplane.ZatPoint (line->v2->x, line->v2->y); // Cannot make these walls solid, because it can result in // sprite clipping problems for sprites near the wall if (rw_frontcz1 > rw_backcz1 || rw_frontcz2 > rw_backcz2) { rw_havehigh = true; WallMost (wallupper, backsector->ceilingplane, &WallC); } if (rw_frontfz1 < rw_backfz1 || rw_frontfz2 < rw_backfz2) { rw_havelow = true; WallMost (walllower, backsector->floorplane, &WallC); } // Closed door. if ((rw_backcz1 <= rw_frontfz1 && rw_backcz2 <= rw_frontfz2) || (rw_backfz1 >= rw_frontcz1 && rw_backfz2 >= rw_frontcz2)) { solid = true; } else if ( // properly render skies (consider door "open" if both ceilings are sky): (backsector->GetTexture(sector_t::ceiling) != skyflatnum || frontsector->GetTexture(sector_t::ceiling) != skyflatnum) // if door is closed because back is shut: && rw_backcz1 <= rw_backfz1 && rw_backcz2 <= rw_backfz2 // preserve a kind of transparent door/lift special effect: && ((rw_backcz1 >= rw_frontcz1 && rw_backcz2 >= rw_frontcz2) || line->sidedef->GetTexture(side_t::top).isValid()) && ((rw_backfz1 <= rw_frontfz1 && rw_backfz2 <= rw_frontfz2) || line->sidedef->GetTexture(side_t::bottom).isValid())) { // killough 1/18/98 -- This function is used to fix the automap bug which // showed lines behind closed doors simply because the door had a dropoff. // // It assumes that Doom has already ruled out a door being closed because // of front-back closure (e.g. front floor is taller than back ceiling). // This fixes the automap floor height bug -- killough 1/18/98: // killough 4/7/98: optimize: save result in doorclosed for use in r_segs.c doorclosed = true; solid = true; } else if (frontsector->ceilingplane != backsector->ceilingplane || frontsector->floorplane != backsector->floorplane) { // Window. solid = false; } else if (backsector->lightlevel != frontsector->lightlevel || backsector->GetTexture(sector_t::floor) != frontsector->GetTexture(sector_t::floor) || backsector->GetTexture(sector_t::ceiling) != frontsector->GetTexture(sector_t::ceiling) || curline->sidedef->GetTexture(side_t::mid).isValid() // killough 3/7/98: Take flats offsets into account: || backsector->GetXOffset(sector_t::floor) != frontsector->GetXOffset(sector_t::floor) || backsector->GetYOffset(sector_t::floor) != frontsector->GetYOffset(sector_t::floor) || backsector->GetXOffset(sector_t::ceiling) != frontsector->GetXOffset(sector_t::ceiling) || backsector->GetYOffset(sector_t::ceiling) != frontsector->GetYOffset(sector_t::ceiling) || backsector->GetPlaneLight(sector_t::floor) != frontsector->GetPlaneLight(sector_t::floor) || backsector->GetPlaneLight(sector_t::ceiling) != frontsector->GetPlaneLight(sector_t::ceiling) || backsector->GetFlags(sector_t::floor) != frontsector->GetFlags(sector_t::floor) || backsector->GetFlags(sector_t::ceiling) != frontsector->GetFlags(sector_t::ceiling) // [RH] Also consider colormaps || backsector->ColorMap != frontsector->ColorMap // [RH] and scaling || backsector->GetXScale(sector_t::floor) != frontsector->GetXScale(sector_t::floor) || backsector->GetYScale(sector_t::floor) != frontsector->GetYScale(sector_t::floor) || backsector->GetXScale(sector_t::ceiling) != frontsector->GetXScale(sector_t::ceiling) || backsector->GetYScale(sector_t::ceiling) != frontsector->GetYScale(sector_t::ceiling) // [RH] and rotation || backsector->GetAngle(sector_t::floor) != frontsector->GetAngle(sector_t::floor) || backsector->GetAngle(sector_t::ceiling) != frontsector->GetAngle(sector_t::ceiling) // kg3D - and fake lights || (frontsector->e && frontsector->e->XFloor.lightlist.Size()) || (backsector->e && backsector->e->XFloor.lightlist.Size()) ) { solid = false; } else { // Reject empty lines used for triggers and special events. // Identical floor and ceiling on both sides, identical light levels // on both sides, and no middle texture. // When using GL nodes, do a clipping test for these lines so we can // mark their subsectors as visible for automap texturing. if (hasglnodes && !(InSubsector->flags & SSECF_DRAWN)) { if (R_CheckClipWallSegment(WallC.sx1, WallC.sx2)) { InSubsector->flags |= SSECF_DRAWN; } } return; } } rw_prepped = false; if (line->linedef->special == Line_Horizon) { // Be aware: Line_Horizon does not work properly with sloped planes clearbufshort (walltop+WallC.sx1, WallC.sx2 - WallC.sx1, centery); clearbufshort (wallbottom+WallC.sx1, WallC.sx2 - WallC.sx1, centery); } else { rw_ceilstat = WallMost (walltop, frontsector->ceilingplane, &WallC); rw_floorstat = WallMost (wallbottom, frontsector->floorplane, &WallC); // [RH] treat off-screen walls as solid #if 0 // Maybe later... if (!solid) { if (rw_ceilstat == 12 && line->sidedef->GetTexture(side_t::top) != 0) { rw_mustmarkceiling = true; solid = true; } if (rw_floorstat == 3 && line->sidedef->GetTexture(side_t::bottom) != 0) { rw_mustmarkfloor = true; solid = true; } } #endif } if (R_ClipWallSegment (WallC.sx1, WallC.sx2, solid)) { InSubsector->flags |= SSECF_DRAWN; } }
FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad) { const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; FSwitchDef *def; TArray<FSwitchDef::frame> frames; FSwitchDef::frame thisframe; FTextureID picnum; bool bad; FSoundID sound; bad = false; while (sc.GetString ()) { if (sc.Compare ("sound")) { if (sound != 0) { sc.ScriptError ("Switch state already has a sound"); } sc.MustGetString (); sound = sc.String; } else if (sc.Compare ("pic")) { sc.MustGetString (); picnum = CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); if (!picnum.Exists() && !ignoreBad) { //Printf ("Unknown switch texture %s\n", sc.String); bad = true; } thisframe.Texture = picnum; sc.MustGetString (); if (sc.Compare ("tics")) { sc.MustGetNumber (); thisframe.TimeMin = sc.Number & 65535; thisframe.TimeRnd = 0; } else if (sc.Compare ("rand")) { int min, max; sc.MustGetNumber (); min = sc.Number & 65535; sc.MustGetNumber (); max = sc.Number & 65535; if (min > max) { swapvalues (min, max); } thisframe.TimeMin = min; thisframe.TimeRnd = (max - min + 1); } else { thisframe.TimeMin = 0; // Shush, GCC. thisframe.TimeRnd = 0; sc.ScriptError ("Must specify a duration for switch frame"); } frames.Push(thisframe); } else { sc.UnGet (); break; } } if (frames.Size() == 0) { sc.ScriptError ("Switch state needs at least one frame"); } if (bad) { return NULL; } def = (FSwitchDef *)M_Malloc (myoffsetof (FSwitchDef, frames[0]) + frames.Size()*sizeof(frames[0])); def->Sound = sound; def->NumFrames = frames.Size(); memcpy (&def->frames[0], &frames[0], frames.Size() * sizeof(frames[0])); def->PairDef = NULL; return def; }
//========================================================================== //*** // ParseStates // parses a state block // //========================================================================== void ParseStates(FScanner &sc, FActorInfo * actor, AActor * defaults, Baggage &bag) { FString statestring; FState state; char lastsprite[5]=""; sc.MustGetStringName ("{"); sc.SetEscape(false); // disable escape sequences in the state parser while (!sc.CheckString ("}") && !sc.End) { memset(&state,0,sizeof(state)); statestring = ParseStateString(sc); if (!statestring.CompareNoCase("GOTO")) { do_goto: statestring = ParseStateString(sc); if (sc.CheckString ("+")) { sc.MustGetNumber (); statestring += '+'; statestring += sc.String; } if (!bag.statedef.SetGotoLabel(statestring)) { sc.ScriptError("GOTO before first state"); } } else if (!statestring.CompareNoCase("STOP")) { do_stop: if (!bag.statedef.SetStop()) { sc.ScriptError("STOP before first state"); continue; } } else if (!statestring.CompareNoCase("WAIT") || !statestring.CompareNoCase("FAIL")) { if (!bag.statedef.SetWait()) { sc.ScriptError("%s before first state", sc.String); continue; } } else if (!statestring.CompareNoCase("LOOP")) { if (!bag.statedef.SetLoop()) { sc.ScriptError("LOOP before first state"); continue; } } else { sc.MustGetString(); if (sc.Compare (":")) { do { bag.statedef.AddStateLabel(statestring); statestring = ParseStateString(sc); if (!statestring.CompareNoCase("GOTO")) { goto do_goto; } else if (!statestring.CompareNoCase("STOP")) { goto do_stop; } sc.MustGetString (); } while (sc.Compare (":")); // continue; } sc.UnGet (); if (statestring.Len() != 4) { sc.ScriptError ("Sprite names must be exactly 4 characters\n"); } state.sprite = GetSpriteIndex(statestring); state.Misc1 = state.Misc2 = 0; state.ParameterIndex = 0; sc.MustGetString(); statestring = sc.String; if (sc.CheckString("RANDOM")) { int min, max; sc.MustGetStringName("("); sc.MustGetNumber(); min = clamp<int>(sc.Number, -1, SHRT_MAX); sc.MustGetStringName(","); sc.MustGetNumber(); max = clamp<int>(sc.Number, -1, SHRT_MAX); sc.MustGetStringName(")"); if (min > max) { swapvalues(min, max); } state.Tics = min; state.TicRange = max - min; } else { sc.MustGetNumber(); state.Tics = clamp<int>(sc.Number, -1, SHRT_MAX); state.TicRange = 0; } while (sc.GetString() && !sc.Crossed) { if (sc.Compare("BRIGHT")) { state.Fullbright = true; continue; } if (sc.Compare("FAST")) { state.Fast = true; continue; } if (sc.Compare("SLOW")) { state.Slow = true; continue; } if (sc.Compare("NODELAY")) { if (bag.statedef.GetStateLabelIndex(NAME_Spawn) == bag.statedef.GetStateCount()) { state.NoDelay = true; } else { sc.ScriptMessage("NODELAY may only be used immediately after Spawn:"); } continue; } if (sc.Compare("OFFSET")) { // specify a weapon offset sc.MustGetStringName("("); sc.MustGetNumber(); state.Misc1 = sc.Number; sc.MustGetStringName (","); sc.MustGetNumber(); state.Misc2 = sc.Number; sc.MustGetStringName(")"); continue; } if (sc.Compare("LIGHT")) { sc.MustGetStringName("("); do { sc.MustGetString(); #ifdef DYNLIGHT AddStateLight(&state, sc.String); #endif } while (sc.CheckString(",")); sc.MustGetStringName(")"); continue; } if (sc.Compare("CANRAISE")) { state.CanRaise = true; continue; } // Make the action name lowercase strlwr (sc.String); if (DoActionSpecials(sc, state, bag)) { goto endofstate; } FName funcname = FName(sc.String, true); PSymbol *sym = bag.Info->Class->Symbols.FindSymbol (funcname, true); if (sym != NULL && sym->SymbolType == SYM_ActionFunction) { PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym); state.SetAction(afd, false); if (!afd->Arguments.IsEmpty()) { const char *params = afd->Arguments.GetChars(); int numparams = (int)afd->Arguments.Len(); int v; if (!islower(*params)) { sc.MustGetStringName("("); } else { if (!sc.CheckString("(")) { state.ParameterIndex = afd->defaultparameterindex+1; goto endofstate; } } int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class); int paramstart = paramindex; bool varargs = params[numparams - 1] == '+'; int varargcount = 0; if (varargs) { paramindex++; } else if (afd->defaultparameterindex > -1) { StateParams.Copy(paramindex, afd->defaultparameterindex, int(afd->Arguments.Len())); } while (*params) { FxExpression *x; if ((*params == 'l' || *params == 'L') && sc.CheckNumber()) { // Special case: State label as an offset if (sc.Number > 0 && statestring.Len() > 1) { sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); } v=sc.Number; if (v<0) { sc.ScriptError("Negative jump offsets are not allowed"); } if (v > 0) { x = new FxStateByIndex(bag.statedef.GetStateCount() + v, sc); } else { x = new FxConstant((FState*)NULL, sc); } } else { // Use the generic parameter parser for everything else x = ParseParameter(sc, bag.Info->Class, *params, false); } StateParams.Set(paramindex++, x); params++; if (varargs) { varargcount++; } if (*params) { if (*params == '+') { if (sc.CheckString(")")) { StateParams.Set(paramstart, new FxConstant(varargcount, sc)); goto endofstate; } params--; StateParams.Reserve(1, bag.Info->Class); } else if ((islower(*params) || *params=='!') && sc.CheckString(")")) { goto endofstate; } sc.MustGetStringName (","); } } sc.MustGetStringName(")"); } else { sc.MustGetString(); if (sc.Compare("(")) { sc.ScriptError("You cannot pass parameters to '%s'\n", funcname.GetChars()); } sc.UnGet(); } goto endofstate; } sc.ScriptError("Invalid state parameter %s\n", sc.String); } sc.UnGet(); endofstate: if (!bag.statedef.AddStates(&state, statestring)) { sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); } } } sc.SetEscape(true); // re-enable escape sequences }