bool GetIntersection(FCoverageVertex *v1, FCoverageVertex *v2, node_t *bsp, FCoverageVertex *v) { double frac; double num; double den; double v2x = (double)v1->x; double v2y = (double)v1->y; double v2dx = (double)(v2->x - v1->x); double v2dy = (double)(v2->y - v1->y); double v1x = (double)bsp->x; double v1y = (double)bsp->y; double v1dx = (double)bsp->dx; double v1dy = (double)bsp->dy; den = v1dy*v2dx - v1dx*v2dy; if (den == 0) return false; // parallel num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx; frac = num / den; if (frac < 0. || frac > 1.) return false; v->x = xs_RoundToInt(v2x + frac * v2dx); v->y = xs_RoundToInt(v2y + frac * v2dy); return true; }
// // 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; }
void DIntermissionScreenFader::Drawer () { if (!mFlatfill && mBackground.isValid()) { double factor = clamp(double(mTicker) / mDuration, 0., 1.); if (mType == FADE_In) factor = 1.0 - factor; int color = MAKEARGB(xs_RoundToInt(factor*255), 0,0,0); if (screen->Begin2D(false)) { screen->DrawTexture (TexMan[mBackground], 0, 0, DTA_Fullscreen, true, DTA_ColorOverlay, color, TAG_DONE); for (unsigned i=0; i < mOverlays.Size(); i++) { if (CheckOverlay(i)) screen->DrawTexture (TexMan[mOverlays[i].mPic], mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, DTA_ColorOverlay, color, TAG_DONE); } screen->FillBorder (NULL); } else { V_SetBlend (0,0,0,int(256*factor)); Super::Drawer(); } } }
static bool Configure(SoundTemplate &self, const tinyxml2::XMLElement *element, unsigned int id) { // get sound length float length; element->QueryFloatAttribute("length", &length); size_t count = xs_CeilToInt(length * AUDIO_FREQUENCY); // reserve space self.Reserve(count); // get expression std::vector<unsigned int> buffer; Expression::Loader<float>::ConfigureRoot(element, buffer, sScalarNames, sScalarDefault); // set up a context EntityContext context(&buffer[0], buffer.size(), 0, id); // for each sample... for (size_t i = 0; i < count; ++i, context.Restart()) { // evaluate the expression context.mParam = float(i) / AUDIO_FREQUENCY; float value = Expression::Evaluate<float>(context); // add a sample self.Append(short(Clamp(xs_RoundToInt(value * SHRT_MAX), SHRT_MIN, SHRT_MAX))); } return true; }
static int segcmp(const void *a, const void *b) { seg_t *A = *(seg_t**)a; seg_t *B = *(seg_t**)b; return xs_RoundToInt(FRACUNIT*(A->sidefrac - B->sidefrac)); }
//========================================================================== // // // //========================================================================== void GLWall::DrawDecal(DBaseDecal *decal) { line_t * line=seg->linedef; side_t * side=seg->sidedef; int i; fixed_t zpos; int light; int rel; float a; bool flipx, flipy, loadAlpha; DecalVertex dv[4]; FTextureID decalTile; if (decal->RenderFlags & RF_INVISIBLE) return; if (type==RENDERWALL_FFBLOCK && gltexture->isMasked()) return; // No decals on 3D floors with transparent textures. //if (decal->sprite != 0xffff) { decalTile = decal->PicNum; flipx = !!(decal->RenderFlags & RF_XFLIP); flipy = !!(decal->RenderFlags & RF_YFLIP); } /* else { decalTile = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].lump[0]; flipx = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].flip & 1; } */ FTexture *texture = TexMan[decalTile]; if (texture == NULL) return; FMaterial *tex; if (texture->UseType == FTexture::TEX_MiscPatch) { // We need to create a clone of this texture where we can force the // texture filtering offset in. if (texture->gl_info.DecalTexture == NULL) { texture->gl_info.DecalTexture = new FCloneTexture(texture, FTexture::TEX_Decal); } tex = FMaterial::ValidateTexture(texture->gl_info.DecalTexture); } else tex = FMaterial::ValidateTexture(texture); // the sectors are only used for their texture origin coordinates // so we don't need the fake sectors for deep water etc. // As this is a completely split wall fragment no further splits are // necessary for the decal. sector_t *frontsector; // for 3d-floor segments use the model sector as reference if ((decal->RenderFlags&RF_CLIPMASK)==RF_CLIPMID) frontsector=decal->Sector; else frontsector=seg->frontsector; switch (decal->RenderFlags & RF_RELMASK) { default: // No valid decal can have this type. If one is encountered anyway // it is in some way invalid so skip it. return; //zpos = decal->z; //break; case RF_RELUPPER: if (type!=RENDERWALL_TOP) return; if (line->flags & ML_DONTPEGTOP) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } else { zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::ceiling); } break; case RF_RELLOWER: if (type!=RENDERWALL_BOTTOM) return; if (line->flags & ML_DONTPEGBOTTOM) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } else { zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::floor); } break; case RF_RELMID: if (type==RENDERWALL_TOP || type==RENDERWALL_BOTTOM) return; if (line->flags & ML_DONTPEGBOTTOM) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::floor); } else { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } } if (decal->RenderFlags & RF_FULLBRIGHT) { light = 255; rel = 0; } else { light = lightlevel; rel = rellight + getExtraLight(); } int r = RPART(decal->AlphaColor); int g = GPART(decal->AlphaColor); int b = BPART(decal->AlphaColor); FColormap p = Colormap; if (glset.nocoloredspritelighting) { int v = (Colormap.LightColor.r * 77 + Colormap.LightColor.g*143 + Colormap.LightColor.b*35)/255; p.LightColor = PalEntry(p.colormap, v, v, v); } float red, green, blue; if (decal->RenderStyle.Flags & STYLEF_RedIsAlpha) { loadAlpha = true; p.colormap=CM_SHADE; if (glset.lightmode != 8) { gl_GetLightColor(light, rel, &p, &red, &green, &blue); } else { gl_GetLightColor(lightlevel, rellight, &p, &red, &green, &blue); } if (gl_lights && GLRenderer->mLightCount && !gl_fixedcolormap && gl_light_sprites) { float result[3]; fixed_t x, y; decal->GetXY(seg->sidedef, x, y); gl_GetSpriteLight(NULL, x, y, zpos, sub, Colormap.colormap-CM_DESAT0, result, line, side == line->sidedef[0]? 0:1); if (glset.lightmode != 8) { red = clamp<float>(result[0]+red, 0, 1.0f); green = clamp<float>(result[1]+green, 0, 1.0f); blue = clamp<float>(result[2]+blue, 0, 1.0f); } else { gl_RenderState.SetDynLight(result[0], result[1], result[2]); } } BYTE R = xs_RoundToInt(r * red); BYTE G = xs_RoundToInt(g * green); BYTE B = xs_RoundToInt(b * blue); gl_ModifyColor(R,G,B, Colormap.colormap); red = R/255.f; green = G/255.f; blue = B/255.f; } else { loadAlpha = false; red = 1.f; green = 1.f; blue = 1.f; } a = FIXED2FLOAT(decal->Alpha); // now clip the decal to the actual polygon float decalwidth = tex->TextureWidth(GLUSE_PATCH) * FIXED2FLOAT(decal->ScaleX); float decalheight= tex->TextureHeight(GLUSE_PATCH) * FIXED2FLOAT(decal->ScaleY); float decallefto = tex->GetLeftOffset(GLUSE_PATCH) * FIXED2FLOAT(decal->ScaleX); float decaltopo = tex->GetTopOffset(GLUSE_PATCH) * FIXED2FLOAT(decal->ScaleY); float leftedge = glseg.fracleft * side->TexelLength; float linelength = glseg.fracright * side->TexelLength - leftedge; // texel index of the decal's left edge float decalpixpos = (float)side->TexelLength * decal->LeftDistance / (1<<30) - (flipx? decalwidth-decallefto : decallefto) - leftedge; float left,right; float lefttex,righttex; // decal is off the left edge if (decalpixpos < 0) { left = 0; lefttex = -decalpixpos; } else { left = decalpixpos; lefttex = 0; } // decal is off the right edge if (decalpixpos + decalwidth > linelength) { right = linelength; righttex = right - decalpixpos; } else { right = decalpixpos + decalwidth; righttex = decalwidth; } if (right<=left) return; // nothing to draw // one texture unit on the wall as vector float vx=(glseg.x2-glseg.x1)/linelength; float vy=(glseg.y2-glseg.y1)/linelength; dv[1].x=dv[0].x=glseg.x1+vx*left; dv[1].y=dv[0].y=glseg.y1+vy*left; dv[3].x=dv[2].x=glseg.x1+vx*right; dv[3].y=dv[2].y=glseg.y1+vy*right; zpos+= FRACUNIT*(flipy? decalheight-decaltopo : decaltopo); tex->BindPatch(p.colormap, decal->Translation); dv[1].z=dv[2].z = FIXED2FLOAT(zpos); dv[0].z=dv[3].z = dv[1].z - decalheight; dv[1].v=dv[2].v = tex->GetVT(); dv[1].u=dv[0].u = tex->GetU(lefttex / FIXED2FLOAT(decal->ScaleX)); dv[3].u=dv[2].u = tex->GetU(righttex / FIXED2FLOAT(decal->ScaleX)); dv[0].v=dv[3].v = tex->GetVB(); // now clip to the top plane float vzt=(ztop[1]-ztop[0])/linelength; float topleft=this->ztop[0]+vzt*left; float topright=this->ztop[0]+vzt*right; // completely below the wall if (topleft<dv[0].z && topright<dv[3].z) return; if (topleft<dv[1].z || topright<dv[2].z) { // decal has to be clipped at the top // let texture clamping handle all extreme cases dv[1].v=(dv[1].z-topleft)/(dv[1].z-dv[0].z)*dv[0].v; dv[2].v=(dv[2].z-topright)/(dv[2].z-dv[3].z)*dv[3].v; dv[1].z=topleft; dv[2].z=topright; } // now clip to the bottom plane float vzb=(zbottom[1]-zbottom[0])/linelength; float bottomleft=this->zbottom[0]+vzb*left; float bottomright=this->zbottom[0]+vzb*right; // completely above the wall if (bottomleft>dv[1].z && bottomright>dv[2].z) return; if (bottomleft>dv[0].z || bottomright>dv[3].z) { // decal has to be clipped at the bottom // let texture clamping handle all extreme cases dv[0].v=(dv[1].z-bottomleft)/(dv[1].z-dv[0].z)*(dv[0].v-dv[1].v) + dv[1].v; dv[3].v=(dv[2].z-bottomright)/(dv[2].z-dv[3].z)*(dv[3].v-dv[2].v) + dv[2].v; dv[0].z=bottomleft; dv[3].z=bottomright; } if (flipx) { float ur = tex->GetUR(); for(i=0;i<4;i++) dv[i].u=ur-dv[i].u; } if (flipy) { float vb = tex->GetVB(); for(i=0;i<4;i++) dv[i].v=vb-dv[i].v; } // fog is set once per wall in the calling function and not per decal! if (loadAlpha) { glColor4f(red, green, blue, a); if (glset.lightmode == 8) { if (gl_fixedcolormap) glVertexAttrib1f(VATTR_LIGHTLEVEL, 1.0); else glVertexAttrib1f(VATTR_LIGHTLEVEL, gl_CalcLightLevel(light, rel, false) / 255.0); } } else { if (glset.lightmode == 8) { gl_SetColor(light, rel, &p, a, extralight); // Korshun. } else { gl_SetColor(light, rel, &p, a); } } PalEntry fc = gl_RenderState.GetFogColor(); if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One) { gl_RenderState.SetFog(0,-1); } gl_SetRenderStyle(decal->RenderStyle, false, false); // If srcalpha is one it looks better with a higher alpha threshold if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold); else gl_RenderState.AlphaFunc(GL_GREATER, 0.f); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); for(i=0;i<4;i++) { glTexCoord2f(dv[i].u,dv[i].v); glVertex3f(dv[i].x,dv[i].z,dv[i].y); } glEnd(); rendered_decals++; gl_RenderState.SetFog(fc,-1); gl_RenderState.SetDynLight(0,0,0); }
void ShellMenuAudioEnter() { shellmenuaudiosoundchannelsonenter = SOUND_CHANNELS; VarItem *varsoundchannels = VarItem::CreateInteger("shell.menu.audio.channels", SOUND_CHANNELS, 1); TIXML_SNPRINTF(shellmenuaudiosoundchannelstext, sizeof(shellmenuaudiosoundchannelstext), "%d", varsoundchannels->GetInteger()); shellmenuaudiosoundvolumeeffectonenter = SOUND_VOLUME_EFFECT; VarItem *varsoundvolumeeffect = VarItem::CreateInteger("shell.menu.audio.volume.effect", xs_RoundToInt(SOUND_VOLUME_EFFECT * 10), 0, 20); TIXML_SNPRINTF(shellmenuaudiosoundvolumeeffecttext, sizeof(shellmenuaudiosoundvolumeeffecttext), "%d%%", varsoundvolumeeffect->GetInteger() * 10); shellmenuaudiosoundvolumemusiconenter = SOUND_VOLUME_MUSIC; VarItem *varsoundvolumemusic = VarItem::CreateInteger("shell.menu.audio.volume.music", xs_RoundToInt(SOUND_VOLUME_MUSIC * 10), 0, 20); TIXML_SNPRINTF(shellmenuaudiosoundvolumemusictext, sizeof(shellmenuaudiosoundvolumemusictext), "%d%%", varsoundvolumemusic->GetInteger() * 10); }
void ShellMenuVideoEnter() { ShellMenuVideoUpdateResolutionList(); shellmenuvideoresolutionindex = 0; for (int i = 0; i < shellmenuvideoresolutioncount; ++i) { if (SCREEN_WIDTH >= shellmenuvideoresolutionlist[i].w && SCREEN_HEIGHT >= shellmenuvideoresolutionlist[i].h) shellmenuvideoresolutionindex = i; } ShellMenuVideoUpdateResolutionText(); VarItem::CreateInteger("shell.menu.video.fullscreen", SCREEN_FULLSCREEN, 0, 1); VarItem::CreateInteger("shell.menu.video.verticalsync", OPENGL_SWAPCONTROL, 0, 1); VarItem *varmultisample = VarItem::CreateInteger("shell.menu.video.multisample", OPENGL_MULTISAMPLE, 1, 16); TIXML_SNPRINTF(shellmenuvideomultisampletext, sizeof(shellmenuvideomultisampletext), "%dx", varmultisample->GetInteger()); VarItem *varmotionblursteps = VarItem::CreateInteger("shell.menu.video.motionblur", MOTIONBLUR_STEPS, 1); TIXML_SNPRINTF(shellmenuvideomotionblurstepstext, sizeof(shellmenuvideomotionblurstepstext), "%d", varmotionblursteps->GetInteger()); VarItem *varmotionblurtime = VarItem::CreateInteger("shell.menu.video.motionblurtime", xs_RoundToInt(MOTIONBLUR_TIME * 600), 0, 10); TIXML_SNPRINTF(shellmenuvideomotionblurtimetext, sizeof(shellmenuvideomotionblurtimetext), "%d%%", varmotionblurtime->GetInteger() * 10); }
// draw title void ShellTitle::Render(unsigned int aId, float aTime, const Transform2 &aTransform) { //#define USE_TITLE_VERTEX_ARRAY #ifdef USE_TITLE_VERTEX_ARRAY static Vector2 vertexarray[32768]; static unsigned int colorarray[32768]; Vector2 *vertexptr = vertexarray; unsigned int *colorptr = colorarray; #else glBegin(GL_QUADS); #endif // draw title bar for (int row = 0; row < SDL_arraysize(titlemap); ++row) { float y0 = titley + row * titleh, y1 = y0 + titleh; #ifdef USE_TITLE_VERTEX_ARRAY unsigned int color = (xs_RoundToInt(255*baralpha[row]) << 24) | 0x00505050; *colorptr++ = color; *colorptr++ = color; *colorptr++ = color; *colorptr++ = color; *vertexptr++ = Vector2(0, y0); *vertexptr++ = Vector2(640, y0); *vertexptr++ = Vector2(640, y1); *vertexptr++ = Vector2(0, y1); #else glColor4f(0.3f, 0.3f, 0.3f, baralpha[row]); glVertex2f(0, y0); glVertex2f(640, y0); glVertex2f(640, y1); glVertex2f(0, y1); #endif } // draw title body unsigned short *titlefillptr = titlefill; #if 1 #ifdef USE_TITLE_MIRROR_WATER_EFFECT // starting mirror properties float mirror_y0 = MirrorWaveY(titley - titleh); float mirror_d0 = MirrorWaveX(mirror_y0); float mirror_a0 = mirroralphastart + mirroralphadelta * mirror_y0; #endif for (int row = -1; row < (int)SDL_arraysize(titlemap) + 1; ++row) { float y = titley + row * titleh; #ifdef USE_TITLE_MIRROR_WATER_EFFECT // row mirror properties float mirror_y1 = MirrorWaveY(y + titleh); float mirror_yd = (mirror_y1 - mirror_y0) / titleh; float mirror_d1 = MirrorWaveX(mirror_y1); float mirror_dd = (mirror_d1 - mirror_d0) / titleh; float mirror_a1 = mirroralphastart + mirroralphadelta * mirror_y1; float mirror_ad = (mirror_a1 - mirror_a0) / titleh; #endif for (int col = -1; col < (int)SDL_arraysize(titlemap[0]); ++col) { float x = titlex + col * titlew; if (*titlefillptr != 0) { int phase = *titlefillptr >> 9; int fill = *titlefillptr & 0x1FF; // get block color float R, G, B; float h = BlockHue(col, row); bool border = (fill & ~(1<<4)) != 0; HSV2RGB(h + phase * 0.5f + border * 0.5f, 1.0f, 1.0f - 0.25f * border, R, G, B); // for each block... for (int i = 0; i < 9; ++i) { // if the block is filled if (fill & (1 << i)) { // block borders float x0 = x + block[i][0][0]; float x1 = x + block[i][0][1]; float y0 = y + block[i][1][0]; float y1 = y + block[i][1][1]; // upright #ifdef USE_TITLE_VERTEX_ARRAY unsigned int color = 0xFF000000 | (xs_RoundToInt(B * 255) << 16) | (xs_RoundToInt(G * 255) << 8) | (xs_RoundToInt(R * 255) ); *colorptr++ = color; *colorptr++ = color; *colorptr++ = color; *colorptr++ = color; *vertexptr++ = Vector2(x0, y0); *vertexptr++ = Vector2(x1, y0); *vertexptr++ = Vector2(x1, y1); *vertexptr++ = Vector2(x0, y1); #else glColor4f(R, G, B, 1.0f); glVertex2f(x0, y0); glVertex2f(x1, y0); glVertex2f(x1, y1); glVertex2f(x0, y1); #endif #ifdef USE_TITLE_MIRROR_WATER_EFFECT if (mirror_a0 > 0.0f || mirror_a1 > 0.0f) { // mirrored float m0 = y0 - y; float m1 = y1 - y; float a0 = std::max(mirror_a0 + mirror_ad * m0, 0.0f); float a1 = std::max(mirror_a0 + mirror_ad * m1, 0.0f); float dx0 = mirror_d0 + mirror_dd * m0; float dx1 = mirror_d0 + mirror_dd * m1; float yy0 = mirror_y0 + mirror_yd * m0; float yy1 = mirror_y0 + mirror_yd * m1; #ifdef USE_TITLE_VERTEX_ARRAY color &= 0x00FFFFFF; color |= xs_RoundToInt(a1 * a1 * 255) << 24; *colorptr++ = color; *colorptr++ = color; *vertexptr++ = Vector2(x0 + dx1, yy1); *vertexptr++ = Vector2(x1 + dx1, yy1); color &= 0x00FFFFFF; color |= xs_RoundToInt(a0 * a0 * 255) << 24; *colorptr++ = color; *colorptr++ = color; *vertexptr++ = Vector2(x1 + dx0, yy0); *vertexptr++ = Vector2(x0 + dx0, yy0); #else glColor4f(R, G, B, a1 * a1); glVertex2f(x0 + dx1, yy1); glVertex2f(x1 + dx1, yy1); glColor4f(R, G, B, a0 * a0); glVertex2f(x1 + dx0, yy0); glVertex2f(x0 + dx0, yy0); #endif } #endif } } } ++titlefillptr; } #ifdef USE_TITLE_MIRROR_WATER_EFFECT // mirror shift row mirror_y0 = mirror_y1; mirror_d0 = mirror_d1; mirror_a0 = mirror_a1; #endif }
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; }