bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right) { const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac); bool flipTextureX = false; FTexture *tex = GetSpriteTexture(thing, flipTextureX); if (tex == nullptr) return false; DVector2 spriteScale = thing->Scale; double thingxscalemul = spriteScale.X / tex->Scale.X; double thingyscalemul = spriteScale.Y / tex->Scale.Y; double spriteWidth = thingxscalemul * tex->GetWidth(); double spriteHeight = thingyscalemul * tex->GetHeight(); double offsetX; if (flipTextureX) offsetX = (tex->GetWidth() - tex->GetLeftOffsetPo()) * thingxscalemul; else offsetX = tex->GetLeftOffsetPo() * thingxscalemul; left = DVector2(pos.X - viewpoint.Sin * offsetX, pos.Y + viewpoint.Cos * offsetX); right = DVector2(left.X + viewpoint.Sin * spriteWidth, left.Y - viewpoint.Cos * spriteWidth); return true; }
static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) { int trans; // Powered up weapons and inherited sister weapons are not displayed. if (weapon->WeaponFlags & WIF_POWERED_UP) return; if (weapon->SisterWeapon && weapon->IsKindOf(weapon->SisterWeapon->GetClass())) return; trans=0x6666; if (CPlayer->ReadyWeapon) { if (weapon==CPlayer->ReadyWeapon || weapon==CPlayer->ReadyWeapon->SisterWeapon) trans=0xd999; } FTextureID picnum = GetInventoryIcon(weapon, DI_ALTICONFIRST); if (picnum.isValid()) { FTexture * tex = TexMan[picnum]; int w = tex->GetWidth(); int h = tex->GetHeight(); int rh; if (w>h) rh=8; else rh=16,y-=8; // don't draw tall sprites too small! DrawImageToBox(tex, x-24, y, 20, rh, trans); y-=10; } }
void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, fixed_t x, fixed_t y, fixed_t z, F3DFloor * ffloor) { FTexture *tex; vertex_t *v1; fixed_t rorg, ldx, ldy; GetWallStuff (wall, v1, ldx, ldy); rorg = Length (x - v1->x, y - v1->y); tex = TexMan[PicNum]; int dwidth = tex->GetWidth (); DecalWidth = dwidth * ScaleX; DecalLeft = tex->LeftOffset * ScaleX; DecalRight = DecalWidth - DecalLeft; SpreadSource = this; SpreadTemplate = tpl; SpreadZ = z; // Try spreading left first SpreadLeft (rorg - DecalLeft, v1, wall, ffloor); SpreadStack.Clear (); // Then try spreading right SpreadRight (rorg + DecalRight, wall, Length (wall->linedef->dx, wall->linedef->dy), ffloor); SpreadStack.Clear (); }
void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, double x, double y, double z, F3DFloor * ffloor) { FTexture *tex; vertex_t *v1; double rorg, ldx, ldy; GetWallStuff (wall, v1, ldx, ldy); rorg = Length (x - v1->fX(), y - v1->fY()); if ((tex = TexMan[PicNum]) == NULL) { return; } int dwidth = tex->GetWidth (); DecalWidth = dwidth * ScaleX; DecalLeft = tex->LeftOffset * ScaleX; DecalRight = DecalWidth - DecalLeft; SpreadSource = this; SpreadTemplate = tpl; SpreadZ = z; // Try spreading left first SpreadLeft (rorg - DecalLeft, v1, wall, ffloor); SpreadStack.Clear (); // Then try spreading right SpreadRight (rorg + DecalRight, wall, Length (wall->linedef->Delta().X, wall->linedef->Delta().Y), ffloor); SpreadStack.Clear (); }
int WI_drawNum (int x, int y, int n, int digits, bool leadingzeros = true) { // if non-number, do not draw it if (n == 1994) return 0; int fontwidth = num[3]->GetWidth(); int xofs; char text[8]; char *text_p; if (leadingzeros) { sprintf (text, "%07d", n); } else { sprintf (text, "%7d", n); if (digits < 0) { text_p = strrchr (text, ' '); digits = (text_p == NULL) ? 7 : 6 - (int)(text_p - text); x -= digits * fontwidth; } } text_p = strchr (text, '-'); if (text_p == NULL || text_p - text > 7 - digits) { text_p = text + 7 - digits; } xofs = x; if (*text_p == '-') { x -= fontwidth; WI_DrawCharPatch (wiminus, x, y); } // draw the new number while (*text_p) { if (*text_p >= '0' && *text_p <= '9') { FTexture *p = num[*text_p - '0']; WI_DrawCharPatch (p, xofs + (fontwidth - p->GetWidth())/2, y); } text_p++; xofs += fontwidth; } return x; }
// Examines the lump contents to decide what type of texture to create, // and creates the texture. FTexture * FTexture::CreateTexture (int lumpnum, int usetype) { static TexCreateInfo CreateInfo[]={ { IMGZTexture_TryCreate, TEX_Any }, { PNGTexture_TryCreate, TEX_Any }, { JPEGTexture_TryCreate, TEX_Any }, { DDSTexture_TryCreate, TEX_Any }, { PCXTexture_TryCreate, TEX_Any }, { TGATexture_TryCreate, TEX_Any }, { RawPageTexture_TryCreate, TEX_MiscPatch }, { FlatTexture_TryCreate, TEX_Flat }, { PatchTexture_TryCreate, TEX_Any }, { EmptyTexture_TryCreate, TEX_Any }, { AutomapTexture_TryCreate, TEX_MiscPatch }, }; if (lumpnum == -1) return NULL; FWadLump data = Wads.OpenLumpNum (lumpnum); for(size_t i = 0; i < countof(CreateInfo); i++) { if ((CreateInfo[i].usetype == usetype || CreateInfo[i].usetype == TEX_Any)) { FTexture * tex = CreateInfo[i].TryCreate(data, lumpnum); if (tex != NULL) { tex->UseType = usetype; if (usetype == FTexture::TEX_Flat) { int w = tex->GetWidth(); int h = tex->GetHeight(); // Auto-scale flats with dimensions 128x128 and 256x256. // In hindsight, a bad idea, but RandomLag made it sound better than it really is. // Now we're stuck with this stupid behaviour. if (w==128 && h==128) { tex->xScale = tex->yScale = 2*FRACUNIT; tex->bWorldPanning = true; } else if (w==256 && h==256) { tex->xScale = tex->yScale = 4*FRACUNIT; tex->bWorldPanning = true; } } return tex; } } } return NULL; }
static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) { int trans; FTextureID picnum; // Powered up weapons and inherited sister weapons are not displayed. if (weapon->WeaponFlags & WIF_POWERED_UP) return; if (weapon->SisterWeapon && weapon->IsKindOf(RUNTIME_TYPE(weapon->SisterWeapon))) return; trans=0x6666; if (CPlayer->ReadyWeapon) { if (weapon==CPlayer->ReadyWeapon || weapon==CPlayer->ReadyWeapon->SisterWeapon) trans=0xd999; } FState * state=NULL, *ReadyState; FTextureID AltIcon = GetHUDIcon(weapon->GetClass()); picnum = !AltIcon.isNull()? AltIcon : weapon->Icon; if (picnum.isNull()) { if (weapon->SpawnState && weapon->SpawnState->sprite!=0) { state = weapon->SpawnState; } // no spawn state - now try the ready state else if ((ReadyState = weapon->FindState(NAME_Ready)) && ReadyState->sprite!=0) { state = ReadyState; } if (state && (unsigned)state->sprite < (unsigned)sprites.Size ()) { spritedef_t * sprdef = &sprites[state->sprite]; spriteframe_t * sprframe = &SpriteFrames[sprdef->spriteframes + state->GetFrame()]; picnum = sprframe->Texture[0]; } } if (picnum.isValid()) { FTexture * tex = TexMan[picnum]; int w = tex->GetWidth(); int h = tex->GetHeight(); int rh; if (w>h) rh=8; else rh=16,y-=8; // don't draw tall sprites too small! DrawImageToBox(tex, x-24, y, 20, rh, trans); y-=10; } }
void FSingleLumpFont::CreateFontFromPic (int picnum) { FTexture *pic = TexMan[picnum]; FontHeight = pic->GetHeight (); SpaceWidth = pic->GetWidth (); GlobalKerning = 0; FirstChar = LastChar = 'A'; Chars = new CharData[1]; Chars->Pic = pic; // Only one color range. Don't bother with the others. ActiveColors = 0; }
void DrawFullScreenStuff () { // Draw health DrINumberOuter (CPlayer->health, 4, -10, false, 7); screen->DrawTexture (Images[imgMEDI], 14, -17, DTA_HUDRules, HUD_Normal, DTA_CenterBottomOffset, true, TAG_DONE); // Draw armor ABasicArmor *armor = CPlayer->mo->FindInventory<ABasicArmor>(); if (armor != NULL && armor->Amount != 0) { DrINumberOuter (armor->Amount, 35, -10, false, 7); screen->DrawTexture (TexMan(armor->Icon), 45, -17, DTA_HUDRules, HUD_Normal, DTA_CenterBottomOffset, true, TAG_DONE); } // Draw ammo AAmmo *ammo1, *ammo2; int ammocount1, ammocount2; GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); if (ammo1 != NULL) { // Draw primary ammo in the bottom-right corner DrINumberOuter (ammo1->Amount, -23, -10, false, 7); screen->DrawTexture (TexMan(ammo1->Icon), -14, -17, DTA_HUDRules, HUD_Normal, DTA_CenterBottomOffset, true, TAG_DONE); if (ammo2 != NULL) { // Draw secondary ammo just above the primary ammo DrINumberOuter (ammo2->Amount, -23, -48, false, 7); screen->DrawTexture (TexMan(ammo2->Icon), -14, -55, DTA_HUDRules, HUD_Normal, DTA_CenterBottomOffset, true, TAG_DONE); } } if (deathmatch) { // Draw frags (in DM) DrBNumberOuterFont (CPlayer->fragcount, -44, 1); } // Draw inventory if (CPlayer->inventorytics == 0) { if (CPlayer->InvSel != 0) { if (ItemFlash > 0) { FTexture *cursor = Images[CursorImage]; screen->DrawTexture (cursor, -28, -15, DTA_HUDRules, HUD_Normal, DTA_LeftOffset, cursor->GetWidth(), DTA_TopOffset, cursor->GetHeight(), DTA_Alpha, ItemFlash, TAG_DONE); } DrINumberOuter (CPlayer->InvSel->Amount, -51, -10, false, 7); screen->DrawTexture (TexMan(CPlayer->InvSel->Icon), -42, -17, DTA_HUDRules, HUD_Normal, DTA_CenterBottomOffset, true, TAG_DONE); } } else { CPlayer->InvFirst = ValidateInvFirst (6); int i = 0; AInventory *item; if (CPlayer->InvFirst != NULL) { for (item = CPlayer->InvFirst; item != NULL && i < 6; item = item->NextInv(), ++i) { if (item == CPlayer->InvSel) { screen->DrawTexture (Images[CursorImage], -100+i*35, -21, DTA_HUDRules, HUD_HorizCenter, DTA_Alpha, TRANSLUC75, TAG_DONE); } if (item->Icon != 0) { screen->DrawTexture (TexMan(item->Icon), -94 + i*35, -19, DTA_HUDRules, HUD_HorizCenter, TAG_DONE); } DrINumberOuter (item->Amount, -89 + i*35, -10, true, 7); } } } // Draw pop screen (log, keys, and status) if (CurrentPop != POP_None && PopHeight < 0) { DrawPopScreen (screen->GetHeight()); } }
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 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--); }