void GL_RecalcLowerWall(seg_t *seg, sector_t *frontSector, gl_poly_t *poly) { FTexture *tex = TexMan(seg->sidedef->bottomtexture); float txScale, tyScale, yOffset, xOffset, dist, texHeight; float v1[5], v2[5], v3[5], v4[5]; float upperHeight, lowerHeight; texcoord_t ll, ul, lr, ur; sector_t *backSector, ts2; vertex_t *vert1, *vert2; fixed_t h1, h2; if (!poly->initialized) GL_InitPolygon(poly); poly->lastUpdate = frameStartMS; poly->initialized = true; vert1 = seg->v1; vert2 = seg->v2; dist = seg->length; backSector = R_FakeFlat(seg->backsector, &ts2, NULL, NULL, false); h1 = (backSector->floorplane.ZatPoint(vert1) - frontSector->floorplane.ZatPoint(vert1)); h2 = (backSector->floorplane.ZatPoint(vert2) - frontSector->floorplane.ZatPoint(vert2)); v1[0] = v3[0] = -vert1->x * MAP_SCALE; v1[2] = v3[2] = vert1->y * MAP_SCALE; v2[0] = v4[0] = -vert2->x * MAP_SCALE; v2[2] = v4[2] = vert2->y * MAP_SCALE; v1[1] = (float)frontSector->floorplane.ZatPoint(vert1); v2[1] = (float)frontSector->floorplane.ZatPoint(vert2); v3[1] = v1[1] + h1; v4[1] = v2[1] + h2; // texscale: 8 = 1.0, 16 = 2.0, 4 = 0.5 txScale = tex->ScaleX ? tex->ScaleX / 8.f : 1.f; tyScale = tex->ScaleY ? tex->ScaleY / 8.f : 1.f; xOffset = (seg->offset * txScale) * INV_FRACUNIT; ll.x = xOffset / tex->GetWidth(); ul.x = ll.x; lr.x = ll.x + (dist / tex->GetWidth() * txScale); ur.x = lr.x; ul.y = ur.y = 1.f; ll.y = lr.y = 0.f; if (tex) { texHeight = tex->GetHeight() / tyScale; lowerHeight = frontSector->floortexz * INV_FRACUNIT; upperHeight = backSector->floortexz * INV_FRACUNIT; if (seg->linedef->flags & ML_DONTPEGBOTTOM) { yOffset = (frontSector->ceilingtexz - backSector->floortexz) * INV_FRACUNIT; } else { yOffset = 0.f; } ul.y = ur.y = (yOffset + upperHeight - lowerHeight) / texHeight; ll.y = lr.y = yOffset / texHeight; // scale the coordinates //ul.y *= tyScale; //ur.y *= tyScale; //ll.y *= tyScale; //lr.y *= tyScale; // adjust for slopes ul.y -= ((v1[1] * INV_FRACUNIT) - lowerHeight) / texHeight; ur.y -= ((v2[1] * INV_FRACUNIT) - lowerHeight) / texHeight; ll.y += (upperHeight - (v3[1] * INV_FRACUNIT)) / texHeight; lr.y += (upperHeight - (v4[1] * INV_FRACUNIT)) / texHeight; } v1[1] *= MAP_SCALE; v2[1] *= MAP_SCALE; v3[1] *= MAP_SCALE; v4[1] *= MAP_SCALE; v1[3] = ul.x; v1[4] = ul.y; v2[3] = ur.x; v2[4] = ur.y; v3[3] = ll.x; v3[4] = ll.y; v4[3] = lr.x; v4[4] = lr.y; memcpy(poly->vertices + (0 * 3), v3, sizeof(float) * 3); memcpy(poly->vertices + (1 * 3), v1, sizeof(float) * 3); memcpy(poly->vertices + (2 * 3), v2, sizeof(float) * 3); memcpy(poly->vertices + (3 * 3), v4, sizeof(float) * 3); memcpy(poly->texCoords + (0 * 2), v3 + 3, sizeof(float) * 2); memcpy(poly->texCoords + (1 * 2), v1 + 3, sizeof(float) * 2); memcpy(poly->texCoords + (2 * 2), v2 + 3, sizeof(float) * 2); memcpy(poly->texCoords + (3 * 2), v4 + 3, sizeof(float) * 2); }
void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) { if (RenderPolySprite::IsThingCulled(thing)) return; const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac); pos.Z += thing->GetBobOffset(viewpoint.TicFrac); bool flipTextureX = false; FTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX); if (tex == nullptr || tex->UseType == FTexture::TEX_Null) return; DVector2 spriteScale = thing->Scale; double thingxscalemul = spriteScale.X / tex->Scale.X; double thingyscalemul = spriteScale.Y / tex->Scale.Y; double spriteHeight = thingyscalemul * tex->GetHeight(); DAngle ang = thing->Angles.Yaw + 90; double angcos = ang.Cos(); double angsin = ang.Sin(); // Determine left and right edges of sprite. The sprite's angle is its normal, // so the edges are 90 degrees each side of it. double x2 = tex->GetScaledWidth() * spriteScale.X; double x1 = tex->GetScaledLeftOffset() * spriteScale.X; DVector2 left, right; left.X = pos.X - x1 * angcos; left.Y = pos.Y - x1 * angsin; right.X = left.X + x2 * angcos; right.Y = left.Y + x2 * angsin; //int scaled_to = tex->GetScaledTopOffset(); //int scaled_bo = scaled_to - tex->GetScaledHeight(); //gzt = pos.Z + scale.Y * scaled_to; //gzb = pos.Z + scale.Y * scaled_bo; DVector2 points[2] = { left, right }; TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4); bool foggy = false; int actualextralight = foggy ? 0 : viewpoint.extralight << 4; std::pair<float, float> offsets[4] = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f }, }; for (int i = 0; i < 4; i++) { auto &p = (i == 0 || i == 3) ? points[0] : points[1]; vertices[i].x = (float)p.X; vertices[i].y = (float)p.Y; vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second); vertices[i].w = 1.0f; vertices[i].u = (float)(offsets[i].first * tex->Scale.X); vertices[i].v = (float)((1.0f - offsets[i].second) * tex->Scale.Y); if (flipTextureX) vertices[i].u = 1.0f - vertices[i].u; } bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight; PolyDrawArgs args; args.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite); args.SetTransform(&worldToClip); args.SetFaceCullCCW(true); args.SetStencilTestValue(stencilValue); args.SetTexture(tex); args.SetClipPlane(clipPlane); args.SetSubsectorDepthTest(true); args.SetWriteSubsectorDepth(false); args.SetWriteStencil(false); args.SetStyle(TriBlendMode::TextureMasked); args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan); }
void GL_RecalcMidWall(seg_t *seg, sector_t *frontSector, gl_poly_t *poly) { float height1, height2, v1[5], v2[5], v3[5], v4[5], txScale, tyScale; float yOffset1, yOffset2, yOffset, xOffset; float upperHeight, lowerHeight; float tmpOffset = seg->sidedef->rowoffset * INV_FRACUNIT; long offset = 0; int texHeight; FTexture *tex = NULL; texcoord_t ll, ul, lr, ur; sector_t *backSector, ts2; vertex_t *vert1, *vert2; if (!poly->initialized) GL_InitPolygon(poly); poly->lastUpdate = frameStartMS; poly->initialized = true; tex = TexMan(seg->sidedef->midtexture); vert1 = seg->v1; vert2 = seg->v2; backSector = R_FakeFlat(seg->backsector, &ts2, NULL, NULL, false); v1[0] = -vert1->x * MAP_SCALE; v1[2] = vert1->y * MAP_SCALE; v2[0] = -vert2->x * MAP_SCALE; v2[2] = vert2->y * MAP_SCALE; v1[1] = (float)frontSector->floorplane.ZatPoint(seg->v1); v2[1] = (float)frontSector->floorplane.ZatPoint(seg->v2); if ((seg->linedef->special == Line_Mirror && seg->backsector == NULL) || tex == NULL) { if (backSector) { height1 = (float)backSector->ceilingplane.ZatPoint(vert1); height2 = (float)backSector->ceilingplane.ZatPoint(vert2); } else { height1 = (float)frontSector->ceilingplane.ZatPoint(vert1); height2 = (float)frontSector->ceilingplane.ZatPoint(vert2); } } else { //yOffset = seg->sidedef->rowoffset * INV_FRACUNIT; yOffset = 0.f; tmpOffset = 0.f; offset = seg->sidedef->rowoffset; yOffset1 = yOffset2 = yOffset; // texscale: 8 = 1.0, 16 = 2.0, 4 = 0.5 txScale = tex->ScaleX ? tex->ScaleX / 8.f : 1.f; tyScale = tex->ScaleY ? tex->ScaleY / 8.f : 1.f; xOffset = (seg->offset * txScale) * INV_FRACUNIT; texHeight = (int)(tex->GetHeight() / tyScale); textureList.GetTexture(seg->sidedef->midtexture, true); ll.x = xOffset / tex->GetWidth(); ul.x = ll.x; lr.x = ll.x + (seg->length / tex->GetWidth() * txScale); ur.x = lr.x; if (backSector) { height1 = (float)MIN(frontSector->ceilingplane.ZatPoint(vert1), backSector->ceilingplane.ZatPoint(vert1)); height2 = (float)MIN(frontSector->ceilingplane.ZatPoint(vert2), backSector->ceilingplane.ZatPoint(vert2)); } else { height1 = (float)frontSector->ceilingplane.ZatPoint(vert1); height2 = (float)frontSector->ceilingplane.ZatPoint(vert2); } if (backSector && (textureList.IsTransparent() || seg->linedef->flags & ML_TWOSIDED)) { int h = texHeight; #if 0 if (seg->linedef->flags & ML_DONTPEGBOTTOM) { if (backSector) { v1[1] = MAX (frontSector->floortexz, backSector->floortexz) + offset; v2[1] = MAX (frontSector->floortexz, backSector->floortexz) + offset; } else { v1[1] = frontSector->floortexz + offset; v2[1] = frontSector->floortexz + offset; } } else { if (backSector) { v1[1] = MIN (frontSector->ceilingtexz, backSector->ceilingtexz) + offset - (h << FRACBITS); v2[1] = MIN (frontSector->ceilingtexz, backSector->ceilingtexz) + offset - (h << FRACBITS); } else { v1[1] = frontSector->ceilingtexz + offset - (h << FRACBITS); v2[1] = frontSector->ceilingtexz + offset - (h << FRACBITS); } } height1 = (h << FRACBITS) + v1[1]; height2 = (h << FRACBITS) + v2[1]; #else float rbceil = (float)backSector->ceilingtexz, rbfloor = (float)backSector->floortexz, rfceil = (float)frontSector->ceilingtexz, rffloor = (float)frontSector->floortexz; float gaptop, gapbottom; yOffset = (float)seg->sidedef->rowoffset; height1 = gaptop = MIN(rbceil, rfceil); v1[1] = gapbottom = MAX(rbfloor, rffloor); if (seg->linedef->flags & ML_DONTPEGBOTTOM) { v1[1] += yOffset; height1 = v1[1] + (tex->GetHeight() * FRACUNIT); } else { height1 += yOffset; v1[1] = height1 - (tex->GetHeight() * FRACUNIT); } height2 = height1; v2[1] = v1[1]; #endif } } // make sure to clip the geometry to the back sector... if (backSector) { if (seg->sidedef->bottomtexture) { v1[1] = MAX(v1[1], backSector->floorplane.ZatPoint(seg->v1)); v2[1] = MAX(v2[1], backSector->floorplane.ZatPoint(seg->v2)); } if (seg->sidedef->toptexture) { height1 = MIN(height1, backSector->ceilingplane.ZatPoint(seg->v1)); height2 = MIN(height2, backSector->ceilingplane.ZatPoint(seg->v2)); } } memcpy(v3, v1, sizeof(float) * 3); memcpy(v4, v2, sizeof(float) * 3); ul.y = ur.y = 1.f; ll.y = lr.y = 0.f; if (tex) { yOffset = 0.f; // code borrowed from Legacy ;) // damn pegged/unpegged/two sided lines! if (backSector) { float worldHigh = backSector->ceilingtexz * INV_FRACUNIT; float worldLow = backSector->floortexz * INV_FRACUNIT; float polyBottom, polyTop; lowerHeight = frontSector->floortexz * INV_FRACUNIT; upperHeight = frontSector->ceilingtexz * INV_FRACUNIT; float openTop = upperHeight < worldHigh ? upperHeight : worldHigh; float openBottom = lowerHeight > worldLow ? lowerHeight : worldLow; if (seg->linedef->flags & ML_DONTPEGBOTTOM) { polyBottom = openBottom + seg->sidedef->rowoffset * INV_FRACUNIT; polyTop = polyBottom + texHeight; upperHeight = MIN(openTop, polyTop); lowerHeight = MAX(openBottom, polyBottom); yOffset = lowerHeight + texHeight - upperHeight + polyBottom - lowerHeight; } else { polyTop = openTop + seg->sidedef->rowoffset * INV_FRACUNIT; polyBottom = polyTop - texHeight; yOffset = polyTop - upperHeight; } } else { lowerHeight = frontSector->floortexz * INV_FRACUNIT; upperHeight = frontSector->ceilingtexz * INV_FRACUNIT; yOffset = 0.f; if (seg->linedef->flags & ML_DONTPEGBOTTOM) { yOffset += lowerHeight + texHeight - upperHeight; } } ll.y = lr.y = yOffset / texHeight; ul.y = ur.y = ll.y + ((upperHeight - lowerHeight) / texHeight); // scale the coordinates //ul.y *= tyScale; //ur.y *= tyScale; //ll.y *= tyScale; //lr.y *= tyScale; // clip to slopes ul.y -= ((v1[1] * INV_FRACUNIT) - lowerHeight) / texHeight; ur.y -= ((v2[1] * INV_FRACUNIT) - lowerHeight) / texHeight; ll.y += (upperHeight - (height1 * INV_FRACUNIT)) / texHeight; lr.y += (upperHeight - (height2 * INV_FRACUNIT)) / texHeight; } v1[1] *= MAP_SCALE; v2[1] *= MAP_SCALE; v3[1] = height1 * MAP_SCALE; v4[1] = height2 * MAP_SCALE; v1[3] = ul.x; v1[4] = ul.y; v2[3] = ur.x; v2[4] = ur.y; v3[3] = ll.x; v3[4] = ll.y; v4[3] = lr.x; v4[4] = lr.y; memcpy(poly->vertices + (0 * 3), v3, sizeof(float) * 3); memcpy(poly->vertices + (1 * 3), v1, sizeof(float) * 3); memcpy(poly->vertices + (2 * 3), v2, sizeof(float) * 3); memcpy(poly->vertices + (3 * 3), v4, sizeof(float) * 3); memcpy(poly->texCoords + (0 * 2), v3 + 3, sizeof(float) * 2); memcpy(poly->texCoords + (1 * 2), v1 + 3, sizeof(float) * 2); memcpy(poly->texCoords + (2 * 2), v2 + 3, sizeof(float) * 2); memcpy(poly->texCoords + (3 * 2), v4 + 3, sizeof(float) * 2); }
void GL_DrawSky() { float angle; FTexture *tex; bool drawBoth = false; int sky1tex, sky2tex; int s1p, s2p; drawBoth = !((level.flags & LEVEL_SWAPSKIES) || (sky2texture == sky1texture)); if ((level.flags & LEVEL_SWAPSKIES) || (sky2texture == sky1texture)) { sky1tex = sky2texture; s1p = sky2pos; sky2tex = sky1texture; s2p = sky1pos; } else { sky1tex = sky1texture; s1p = sky1pos; sky2tex = sky2texture; s2p = sky2pos; } glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glDisable(GL_FOG); glDisable(GL_ALPHA_TEST); glPushMatrix(); angle = s2p * 1.f / (FRACUNIT * 2.f); glRotatef(-angle, 0.f, 1.f, 0.f); textureList.BindTexture(sky2tex, true); tex = TexMan(sky2tex); texw = tex->GetWidth(); texh = tex->GetHeight(); tx = ty = 1.f; yMult = 1.f; GL_RenderSkyHemisphere(SKYHEMI_UPPER); GL_RenderSkyHemisphere(SKYHEMI_LOWER); if (drawBoth) { angle = (s1p * 1.f / (FRACUNIT * 2.f)) - angle; glRotatef(-angle, 0.f, 1.f, 0.f); tex = TexMan(sky1tex); textureList.BindTexture(sky1tex, true); texw = tex->GetWidth(); texh = tex->GetHeight(); if (level.flags & LEVEL_DOUBLESKY && texh <= 128) { yMult = 2.f; } tx = ty = 1.f; GL_RenderSkyHemisphere(SKYHEMI_UPPER); GL_RenderSkyHemisphere(SKYHEMI_LOWER); } glPopMatrix(); glEnable(GL_DEPTH_TEST); glEnable(GL_ALPHA_TEST); glFogf(GL_FOG_MODE, GL_EXP); glDepthMask(GL_TRUE); if (gl_depthfog && !Player->fixedcolormap) { glEnable(GL_FOG); } }
void RenderDecal::Render(RenderThread *thread, side_t *wall, DBaseDecal *decal, DrawSegment *clipper, int wallshade, float lightleft, float lightstep, seg_t *curline, const FWallCoords &savecoord, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass) { DVector2 decal_left, decal_right, decal_pos; int x1, x2; double yscale; uint8_t flipx; double zpos; int needrepeat = 0; sector_t *back; bool calclighting; bool rereadcolormap; FDynamicColormap *usecolormap; float light = 0; const short *mfloorclip; const short *mceilingclip; if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid()) return; // Determine actor z zpos = decal->Z; back = (curline->backsector != NULL) ? curline->backsector : curline->frontsector; // for 3d-floor segments use the model sector as reference sector_t *front; if ((decal->RenderFlags&RF_CLIPMASK) == RF_CLIPMID) front = decal->Sector; else front = curline->frontsector; switch (decal->RenderFlags & RF_RELMASK) { default: zpos = decal->Z; break; case RF_RELUPPER: if (curline->linedef->flags & ML_DONTPEGTOP) { zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); } else { zpos = decal->Z + back->GetPlaneTexZ(sector_t::ceiling); } break; case RF_RELLOWER: if (curline->linedef->flags & ML_DONTPEGBOTTOM) { zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); } else { zpos = decal->Z + back->GetPlaneTexZ(sector_t::floor); } break; case RF_RELMID: if (curline->linedef->flags & ML_DONTPEGBOTTOM) { zpos = decal->Z + front->GetPlaneTexZ(sector_t::floor); } else { zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); } } FTexture *WallSpriteTile = TexMan(decal->PicNum, true); flipx = (uint8_t)(decal->RenderFlags & RF_XFLIP); if (WallSpriteTile == NULL || WallSpriteTile->UseType == ETextureType::Null) { return; } // Determine left and right edges of sprite. Since this sprite is bound // to a wall, we use the wall's angle instead of the decal's. This is // pretty much the same as what R_AddLine() does. double edge_right = WallSpriteTile->GetWidth(); double edge_left = WallSpriteTile->GetLeftOffset(0); // decals should not use renderer-specific offsets. edge_right = (edge_right - edge_left) * decal->ScaleX; edge_left *= decal->ScaleX; double dcx, dcy; decal->GetXY(wall, dcx, dcy); decal_pos = { dcx, dcy }; DVector2 angvec = (curline->v2->fPos() - curline->v1->fPos()).Unit(); float maskedScaleY; decal_left = decal_pos - edge_left * angvec - thread->Viewport->viewpoint.Pos; decal_right = decal_pos + edge_right * angvec - thread->Viewport->viewpoint.Pos; CameraLight *cameraLight; double texturemid; FWallCoords WallC; if (WallC.Init(thread, decal_left, decal_right, TOO_CLOSE_Z)) return; x1 = WallC.sx1; x2 = WallC.sx2; if (x1 >= clipper->x2 || x2 <= clipper->x1) return; FWallTmapVals WallT; WallT.InitFromWallCoords(thread, &WallC); if (drawsegPass) { uint32_t clipMode = decal->RenderFlags & RF_CLIPMASK; if (clipMode != RF_CLIPMID && clipMode != RF_CLIPFULL) return; // Clip decal to stay within the draw segment wall mceilingclip = walltop; mfloorclip = wallbottom; // Rumor has it that if RT_CLIPMASK is specified then the decal should be clipped according // to the full drawsegment visibility, as implemented in the remarked section below. // // This is problematic because not all 3d floors may have been drawn yet at this point. The // code below might work ok for cases where there is only one 3d floor. /*if (clipMode == RF_CLIPFULL) { mceilingclip = clipper->sprtopclip - clipper->x1; mfloorclip = clipper->sprbottomclip - clipper->x1; }*/ } else { // Get the top and bottom clipping arrays switch (decal->RenderFlags & RF_CLIPMASK) { default: // keep GCC quiet. return; case RF_CLIPFULL: if (curline->backsector == NULL) { mceilingclip = walltop; mfloorclip = wallbottom; } else { mceilingclip = walltop; mfloorclip = thread->OpaquePass->ceilingclip; needrepeat = 1; } break; case RF_CLIPUPPER: mceilingclip = walltop; mfloorclip = thread->OpaquePass->ceilingclip; break; case RF_CLIPMID: return; case RF_CLIPLOWER: mceilingclip = thread->OpaquePass->floorclip; mfloorclip = wallbottom; break; } } yscale = decal->ScaleY; texturemid = WallSpriteTile->GetTopOffset(0) + (zpos - thread->Viewport->viewpoint.Pos.Z) / yscale; // Clip sprite to drawseg x1 = MAX<int>(clipper->x1, x1); x2 = MIN<int>(clipper->x2, x2); if (x1 >= x2) { return; } ProjectedWallTexcoords walltexcoords; walltexcoords.Project(thread->Viewport.get(), WallSpriteTile->GetWidth(), x1, x2, WallT); if (flipx) { int i; int right = (WallSpriteTile->GetWidth() << FRACBITS) - 1; for (i = x1; i < x2; i++) { walltexcoords.UPos[i] = right - walltexcoords.UPos[i]; } } // Prepare lighting calclighting = false; usecolormap = basecolormap; rereadcolormap = true; // Decals that are added to the scene must fade to black. if (decal->RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0) { usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate); rereadcolormap = false; } light = lightleft + (x1 - savecoord.sx1) * lightstep; cameraLight = CameraLight::Instance(); // Draw it bool sprflipvert; if (decal->RenderFlags & RF_YFLIP) { sprflipvert = true; yscale = -yscale; texturemid -= WallSpriteTile->GetHeight(); } else { sprflipvert = false; } maskedScaleY = float(1 / yscale); do { int x = x1; SpriteDrawerArgs drawerargs; if (cameraLight->FixedLightLevel() >= 0) drawerargs.SetLight((r_fullbrightignoresectorcolor) ? &FullNormalLight : usecolormap, 0, cameraLight->FixedLightLevelShade()); else if (cameraLight->FixedColormap() != NULL) drawerargs.SetLight(cameraLight->FixedColormap(), 0, 0); else if (!foggy && (decal->RenderFlags & RF_FULLBRIGHT)) drawerargs.SetLight((r_fullbrightignoresectorcolor) ? &FullNormalLight : usecolormap, 0, 0); else calclighting = true; bool visible = drawerargs.SetStyle(thread->Viewport.get(), decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor, basecolormap); // R_SetPatchStyle can modify basecolormap. if (rereadcolormap) { usecolormap = basecolormap; } if (visible) { thread->PrepareTexture(WallSpriteTile, decal->RenderStyle); while (x < x2) { if (calclighting) { // calculate lighting drawerargs.SetLight(usecolormap, light, wallshade); } DrawColumn(thread, drawerargs, x, WallSpriteTile, walltexcoords, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip, decal->RenderStyle); light += lightstep; x++; } } // If this sprite is RF_CLIPFULL on a two-sided line, needrepeat will // be set 1 if we need to draw on the lower wall. In all other cases, // needrepeat will be 0, and the while will fail. mceilingclip = thread->OpaquePass->floorclip; mfloorclip = wallbottom; } while (needrepeat--); }
void RenderPolySprite::Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2) { if (r_modelscene) { const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; int spritenum = thing->sprite; bool isPicnumOverride = thing->picnum.isValid(); FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); if (modelframe && (thing->Pos() - viewpoint.Pos).LengthSquared() < model_distance_cull) { DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac); PolyRenderModel(thread, PolyRenderer::Instance()->Scene.CurrentViewpoint->WorldToClip, stencilValue, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing); return; } } DVector2 line[2]; if (!GetLine(thing, line[0], line[1])) return; const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; DVector3 thingpos = thing->InterpolatedPosition(viewpoint.TicFrac); double posZ = thingpos.Z; uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK); if (spritetype == RF_FACESPRITE) posZ -= thing->Floorclip; if (thing->flags2 & MF2_FLOATBOB) posZ += thing->GetBobOffset(viewpoint.TicFrac); bool flipTextureX = false; FTexture *tex = GetSpriteTexture(thing, flipTextureX); if (tex == nullptr || tex->UseType == ETextureType::Null) return; double thingyscalemul = thing->Scale.Y / tex->Scale.Y; double spriteHeight = thingyscalemul * tex->GetHeight(); posZ -= (tex->GetHeight() - tex->GetTopOffsetPo()) * thingyscalemul; posZ = PerformSpriteClipAdjustment(thing, thingpos, spriteHeight, posZ); //double depth = 1.0; //visstyle_t visstyle = GetSpriteVisStyle(thing, depth); // Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here.. //R_SetColorMapLight(visstyle.BaseColormap, 0, visstyle.ColormapNum << FRACBITS); TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4); bool foggy = false; int actualextralight = foggy ? 0 : viewpoint.extralight << 4; std::pair<float, float> offsets[4] = { { t1, 1.0f }, { t2, 1.0f }, { t2, 0.0f }, { t1, 0.0f }, }; DVector2 points[2] = { line[0] * (1.0 - t1) + line[1] * t1, line[0] * (1.0 - t2) + line[1] * t2 }; for (int i = 0; i < 4; i++) { auto &p = (i == 0 || i == 3) ? points[0] : points[1]; vertices[i].x = (float)p.X; vertices[i].y = (float)p.Y; vertices[i].z = (float)(posZ + spriteHeight * offsets[i].second); vertices[i].w = 1.0f; vertices[i].u = (float)(offsets[i].first * tex->Scale.X); vertices[i].v = (float)((1.0f - offsets[i].second) * tex->Scale.Y); if (flipTextureX) vertices[i].u = 1.0f - vertices[i].u; } bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight; PolyDrawArgs args; SetDynlight(thing, args); args.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite); args.SetStencilTestValue(stencilValue); if ((thing->renderflags & RF_ZDOOMTRANS) && r_UseVanillaTransparency) args.SetStyle(LegacyRenderStyles[STYLE_Normal], 1.0f, thing->fillcolor, thing->Translation, tex, fullbrightSprite); else args.SetStyle(thing->RenderStyle, thing->Alpha, thing->fillcolor, thing->Translation, tex, fullbrightSprite); args.SetDepthTest(true); args.SetWriteDepth(false); args.SetWriteStencil(false); PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan); }
void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, AActor *thing, subsector_t *sub, uint32_t subsectorDepth) { if (RenderPolySprite::IsThingCulled(thing)) return; DVector3 pos = thing->InterpolatedPosition(r_TicFracF); pos.Z += thing->GetBobOffset(r_TicFracF); bool flipTextureX = false; FTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX); if (tex == nullptr) return; DVector2 spriteScale = thing->Scale; double thingxscalemul = spriteScale.X / tex->Scale.X; double thingyscalemul = spriteScale.Y / tex->Scale.Y; double spriteHeight = thingyscalemul * tex->GetHeight(); DAngle ang = thing->Angles.Yaw + 90; double angcos = ang.Cos(); double angsin = ang.Sin(); // Determine left and right edges of sprite. The sprite's angle is its normal, // so the edges are 90 degrees each side of it. double x2 = tex->GetScaledWidth() * spriteScale.X; double x1 = tex->GetScaledLeftOffset() * spriteScale.X; DVector2 left, right; left.X = pos.X - x1 * angcos; left.Y = pos.Y - x1 * angsin; right.X = left.X + x2 * angcos; right.Y = right.Y + x2 * angsin; //int scaled_to = tex->GetScaledTopOffset(); //int scaled_bo = scaled_to - tex->GetScaledHeight(); //gzt = pos.Z + scale.Y * scaled_to; //gzb = pos.Z + scale.Y * scaled_bo; DVector2 points[2] = { left, right }; TriVertex *vertices = PolyVertexBuffer::GetVertices(4); if (!vertices) return; bool foggy = false; int actualextralight = foggy ? 0 : extralight << 4; std::pair<float, float> offsets[4] = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f }, }; for (int i = 0; i < 4; i++) { auto &p = (i == 0 || i == 3) ? points[0] : points[1]; vertices[i].x = (float)p.X; vertices[i].y = (float)p.Y; vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second); vertices[i].w = 1.0f; vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X); vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y); if (flipTextureX) vertices[i].varying[0] = 1.0f - vertices[i].varying[0]; } bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); TriUniforms uniforms; if (fullbrightSprite || fixedlightlev >= 0 || fixedcolormap) { uniforms.light = 256; uniforms.flags = TriUniforms::fixed_light; } else { uniforms.light = (uint32_t)((thing->Sector->lightlevel + actualextralight) / 255.0f * 256.0f); uniforms.flags = 0; } uniforms.subsectorDepth = subsectorDepth; PolyDrawArgs args; args.uniforms = uniforms; args.objectToClip = &worldToClip; args.vinput = vertices; args.vcount = 4; args.mode = TriangleDrawMode::Fan; args.ccw = true; args.stenciltestvalue = 0; args.stencilwritevalue = 1; args.SetTexture(tex); args.SetColormap(sub->sector->ColorMap); PolyTriangleDrawer::draw(args, TriDrawVariant::DrawSubsector, TriBlendMode::AlphaBlend); }