//========================================================================== // // Lower Skies on two sided walls // //========================================================================== void GLWall::SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2) { if (fs->GetTexture(sector_t::floor)==skyflatnum) { if ((bs->special&0xff) == NoSkyDraw) return; FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::bottom)); // For lower skies the normal logic only applies to walls with no lower texture! if (tex->UseType==FTexture::TEX_Null) { if (bs->GetTexture(sector_t::floor)==skyflatnum) { // if the back sector is closed the sky must be drawn! if (bs->ceilingplane.ZatPoint(v1) > bs->floorplane.ZatPoint(v1) || bs->ceilingplane.ZatPoint(v2) > bs->floorplane.ZatPoint(v2)) return; } else { // Special hack for Vrack2b if (bs->floorplane.ZatPoint(viewx, viewy) > viewz) return; } } zbottom[0]=zbottom[1]=-32768.0f; if ((tex && tex->UseType!=FTexture::TEX_Null) || bs->GetTexture(sector_t::floor)!=skyflatnum) { ztop[0]=zfloor[0]; ztop[1]=zfloor[1]; } else { ztop[0]=TO_GL(bs->floorplane.ZatPoint(v1)); ztop[1]=TO_GL(bs->floorplane.ZatPoint(v2)); flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment! } SkyTexture(fs->sky,fs->FloorSkyBox, false); } else { bool floorsky = (fs->FloorSkyBox && fs->FloorSkyBox->bAlways && fs->FloorSkyBox!=bs->FloorSkyBox); if (floorsky || fs->floor_reflect) { // stacked sectors fixed_t fsc1=fs->floorplane.ZatPoint(v1); fixed_t fsc2=fs->floorplane.ZatPoint(v2); zbottom[0]=zbottom[1]=-32768.0f; ztop[0]=TO_GL(fsc1); ztop[1]=TO_GL(fsc2); if (floorsky) SkyTexture(fs->sky,fs->FloorSkyBox, false); else MirrorPlane(&fs->floorplane, false); } } }
//========================================================================== // // Upper Skies on two sided walls // //========================================================================== void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2) { if (fs->GetTexture(sector_t::ceiling)==skyflatnum) { if ((bs->special&0xff) == NoSkyDraw) return; if (bs->GetTexture(sector_t::ceiling)==skyflatnum) { // if the back sector is closed the sky must be drawn! if (bs->ceilingplane.ZatPoint(v1) > bs->floorplane.ZatPoint(v1) || bs->ceilingplane.ZatPoint(v2) > bs->floorplane.ZatPoint(v2) || bs->transdoor) return; // one more check for some ugly transparent door hacks if (bs->floorplane.a==0 && bs->floorplane.b==0 && fs->floorplane.a==0 && fs->floorplane.b==0 && bs->GetPlaneTexZ(sector_t::floor)==fs->GetPlaneTexZ(sector_t::floor)+FRACUNIT) { FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::bottom)); if (!tex || tex->UseType==FTexture::TEX_Null) return; } } ztop[0]=ztop[1]=32768.0f; FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::top)); if (/*tex && tex->UseType!=FTexture::TEX_Null &&*/ bs->GetTexture(sector_t::ceiling) != skyflatnum) { zbottom[0]=zceil[0]; zbottom[1]=zceil[1]; } else { zbottom[0]=TO_GL(bs->ceilingplane.ZatPoint(v1)); zbottom[1]=TO_GL(bs->ceilingplane.ZatPoint(v2)); flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment! } SkyTexture(fs->sky,fs->CeilingSkyBox, true); } else { bool ceilingsky = (fs->CeilingSkyBox && fs->CeilingSkyBox->bAlways && fs->CeilingSkyBox!=bs->CeilingSkyBox); if (ceilingsky || fs->ceiling_reflect) { // stacked sectors fixed_t fsc1=fs->ceilingplane.ZatPoint(v1); fixed_t fsc2=fs->ceilingplane.ZatPoint(v2); ztop[0]=ztop[1]=32768.0f; zbottom[0]=TO_GL(fsc1); zbottom[1]=TO_GL(fsc2); if (ceilingsky) SkyTexture(fs->sky,fs->CeilingSkyBox, true); else MirrorPlane(&fs->ceilingplane, true); } } }
static void SkyVertex(int r, int c) { angle_t topAngle= (angle_t)(c / (float)columns * ANGLE_MAX); angle_t sideAngle = maxSideAngle * (rows - r) / rows; fixed_t height = finesine[sideAngle>>ANGLETOFINESHIFT]; fixed_t realRadius = FixedMul(scale, finecosine[sideAngle>>ANGLETOFINESHIFT]); fixed_t x = FixedMul(realRadius, finecosine[topAngle>>ANGLETOFINESHIFT]); fixed_t y = (!yflip) ? FixedMul(scale, height) : FixedMul(scale, height) * -1; fixed_t z = FixedMul(realRadius, finesine[topAngle>>ANGLETOFINESHIFT]); float fx, fy, fz; float color = r * 1.f / rows; float u, v; float timesRepeat; timesRepeat = (short)(4 * (256.f / texw)); if (timesRepeat == 0.f) timesRepeat = 1.f; if (!foglayer) { gl_SetColor(255, 0, NULL, r==0? 0.0f : 1.0f); // And the texture coordinates. if(!yflip) // Flipped Y is for the lower hemisphere. { u = (-timesRepeat * c / (float)columns) ;//* yMult; v = (r / (float)rows) * 1.f * yMult + yAdd; } else { u = (-timesRepeat * c / (float)columns) ;//* yMult; v = ((rows-r)/(float)rows) * 1.f * yMult + yAdd; } gl.TexCoord2f(u, v); } // And finally the vertex. fx =-TO_GL(x); // Doom mirrors the sky vertically! fy = TO_GL(y); fz = TO_GL(z); gl.Vertex3f(fx, fy - 1.f, fz); }
//========================================================================== // // // //========================================================================== void GLDrawList::SortWallIntoPlane(SortNode * head,SortNode * sort) { GLFlat * fh=&flats[drawitems[head->itemindex].index]; GLWall * ws=&walls[drawitems[sort->itemindex].index]; GLWall * ws1; bool ceiling = fh->z > TO_GL(viewz); if (ws->ztop[0]>fh->z && ws->zbottom[0]<fh->z) { // We have to split this wall! // WARNING: NEVER EVER push a member of an array onto the array itself. // Bad things will happen if the memory must be reallocated! GLWall w=*ws; AddWall(&w); ws1=&walls[walls.Size()-1]; ws=&walls[drawitems[sort->itemindex].index]; // may have been reallocated! float newtexv = ws->uplft.v + ((ws->lolft.v - ws->uplft.v) / (ws->zbottom[0] - ws->ztop[0])) * (fh->z - ws->ztop[0]); // I make the very big assumption here that translucent walls in sloped sectors // and 3D-floors never coexist in the same level. If that were the case this // code would become extremely more complicated. if (!ceiling) { ws->ztop[1] = ws1->zbottom[1] = ws->ztop[0] = ws1->zbottom[0] = fh->z; ws->uprgt.v = ws1->lorgt.v = ws->uplft.v = ws1->lolft.v = newtexv; } else { ws1->ztop[1] = ws->zbottom[1] = ws1->ztop[0] = ws->zbottom[0] = fh->z; ws1->uplft.v = ws->lolft.v = ws1->uprgt.v = ws->lorgt.v=newtexv; } SortNode * sort2=SortNodes.GetNew(); memset(sort2,0,sizeof(SortNode)); sort2->itemindex=drawitems.Size()-1; head->AddToLeft(sort); head->AddToRight(sort2); } else if ((ws->zbottom[0]<fh->z && !ceiling) || (ws->ztop[0]>fh->z && ceiling)) // completely on the left side { head->AddToLeft(sort); } else { head->AddToRight(sort); } }
//========================================================================== // // // //========================================================================== void GLDrawList::SortSpriteIntoPlane(SortNode * head,SortNode * sort) { GLFlat * fh=&flats[drawitems[head->itemindex].index]; GLSprite * ss=&sprites[drawitems[sort->itemindex].index]; GLSprite * ss1; bool ceiling = fh->z > TO_GL(viewz); if (ss->z1>fh->z && ss->z2<fh->z) { // We have to split this sprite! GLSprite s=*ss; AddSprite(&s); ss1=&sprites[sprites.Size()-1]; ss=&sprites[drawitems[sort->itemindex].index]; // may have been reallocated! float newtexv=ss->vt + ((ss->vb-ss->vt)/(ss->z2-ss->z1))*(fh->z-ss->z1); if (!ceiling) { ss->z1=ss1->z2=fh->z; ss->vt=ss1->vb=newtexv; } else { ss1->z1=ss->z2=fh->z; ss1->vt=ss->vb=newtexv; } SortNode * sort2=SortNodes.GetNew(); memset(sort2,0,sizeof(SortNode)); sort2->itemindex=drawitems.Size()-1; head->AddToLeft(sort); head->AddToRight(sort2); } else if ((ss->z2<fh->z && !ceiling) || (ss->z1>fh->z && ceiling)) // completely on the left side { head->AddToLeft(sort); } else { head->AddToRight(sort); } }
void GLDrawInfo::FloodLowerGap(seg_t * seg) { wallseg ws; sector_t ffake, bfake; sector_t * fakefsector = gl_FakeFlat(seg->frontsector, &ffake, true); sector_t * fakebsector = gl_FakeFlat(seg->backsector, &bfake, false); vertex_t * v1, * v2; // Although the plane can be sloped this code will only be called // when the edge itself is not. fixed_t backz = fakebsector->floorplane.ZatPoint(seg->v1); fixed_t frontz = fakefsector->floorplane.ZatPoint(seg->v1); if (fakebsector->GetTexture(sector_t::floor) == skyflatnum) return; if (fakebsector->GetPlaneTexZ(sector_t::floor) > viewz) return; if (seg->sidedef == &sides[seg->linedef->sidenum[0]]) { v1=seg->linedef->v1; v2=seg->linedef->v2; } else { v1=seg->linedef->v2; v2=seg->linedef->v1; } ws.x1= TO_GL(v1->x); ws.y1= TO_GL(v1->y); ws.x2= TO_GL(v2->x); ws.y2= TO_GL(v2->y); ws.z2= TO_GL(frontz); ws.z1= TO_GL(backz); // Step1: Draw a stencil into the gap SetupFloodStencil(&ws); // Step2: Project the ceiling plane into the gap DrawFloodedPlane(&ws, ws.z1, fakebsector, false); // Step3: Delete the stencil ClearFloodStencil(&ws); }
//========================================================================== // // Draw the plane segment into the gap // //========================================================================== void GLDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) { GLSectorPlane plane; int lightlevel; FColormap Colormap; FGLTexture * gltexture; plane.GetFromSector(sec, ceiling); gltexture=FGLTexture::ValidateTexture(plane.texture); if (!gltexture) return; if (gl_fixedcolormap) { Colormap.GetFixedColormap(); lightlevel=255; } else { Colormap=sec->ColorMap; if (gltexture->tex->isFullbright()) { Colormap.LightColor.r = Colormap.LightColor.g = Colormap.LightColor.b = 0xff; lightlevel=255; } else lightlevel=abs(ceiling? GetCeilingLight(sec) : GetFloorLight(sec)); } int rel = extralight * gl_weaponlight; gl_SetColor(lightlevel, rel, &Colormap, 1.0f); gl_SetFog(lightlevel, rel, &Colormap, false); gltexture->Bind(Colormap.LightColor.a); gl_SetPlaneTextureRotation(&plane, gltexture); float fviewx = TO_GL(viewx); float fviewy = TO_GL(viewy); float fviewz = TO_GL(viewz); gl_ApplyShader(); gl.Begin(GL_TRIANGLE_FAN); float prj_fac1 = (planez-fviewz)/(ws->z1-fviewz); float prj_fac2 = (planez-fviewz)/(ws->z2-fviewz); float px1 = fviewx + prj_fac1 * (ws->x1-fviewx); float py1 = fviewy + prj_fac1 * (ws->y1-fviewy); float px2 = fviewx + prj_fac2 * (ws->x1-fviewx); float py2 = fviewy + prj_fac2 * (ws->y1-fviewy); float px3 = fviewx + prj_fac2 * (ws->x2-fviewx); float py3 = fviewy + prj_fac2 * (ws->y2-fviewy); float px4 = fviewx + prj_fac1 * (ws->x2-fviewx); float py4 = fviewy + prj_fac1 * (ws->y2-fviewy); gl.TexCoord2f(px1 / 64, -py1 / 64); gl.Vertex3f(px1, planez, py1); gl.TexCoord2f(px2 / 64, -py2 / 64); gl.Vertex3f(px2, planez, py2); gl.TexCoord2f(px3 / 64, -py3 / 64); gl.Vertex3f(px3, planez, py3); gl.TexCoord2f(px4 / 64, -py4 / 64); gl.Vertex3f(px4, planez, py4); gl.End(); gl.MatrixMode(GL_TEXTURE); gl.PopMatrix(); gl.MatrixMode(GL_MODELVIEW); }
//========================================================================== // // Calculate sky texture // //========================================================================== void GLWall::SkyTexture(int sky1,ASkyViewpoint * skyboxx, bool ceiling) { // JUSTHIT is used as an indicator that a skybox is in use. // This is to avoid recursion if (!gl_noskyboxes && !(gl.flags&RFL_NOSTENCIL) && skyboxx && viewactor!=skyboxx && !(skyboxx->flags&MF_JUSTHIT)) { if (!skyboxx->Mate) { type=RENDERWALL_SKYBOX; skybox=skyboxx; } else { static GLSectorStackInfo stackinfo; if (ceiling && GLPortal::inlowerstack) return; if (!ceiling && GLPortal::inupperstack) return; type=RENDERWALL_SECTORSTACK; stackinfo.deltax = skyboxx->Mate->x - skyboxx->x; stackinfo.deltay = skyboxx->Mate->y - skyboxx->y; stackinfo.deltaz = 0; stackinfo.isupper= ceiling; stack=&stackinfo; } } else { if (skyboxx && skyboxx->Mate) return; // VC's optimizer totally screws up if this is made local... static GLSkyInfo skyinfo; memset(&skyinfo, 0, sizeof(skyinfo)); if ((sky1 & PL_SKYFLAT) && (sky1 & (PL_SKYFLAT-1)) && !(gl.flags&RFL_NOSTENCIL)) { const line_t *l = &lines[(sky1&(PL_SKYFLAT-1))-1]; const side_t *s = &sides[l->sidenum[0]]; int pos; if (level.flags & LEVEL_SWAPSKIES && s->GetTexture(side_t::bottom).isValid()) { pos = side_t::bottom; } else { pos = side_t::top; } FTextureID texno = s->GetTexture(pos); skyinfo.texture[0] = FGLTexture::ValidateTexture(texno); if (!skyinfo.texture[0] || skyinfo.texture[0]->tex->UseType == FTexture::TEX_Null) goto normalsky; skyinfo.skytexno1 = texno; skyinfo.x_offset[0] = ANGLE_TO_FLOAT(s->GetTextureXOffset(pos)); skyinfo.y_offset = TO_GL(s->GetTextureYOffset(pos)); skyinfo.mirrored = !l->args[2]; } else { normalsky: if (level.flags&LEVEL_DOUBLESKY) { skyinfo.texture[1]=FGLTexture::ValidateTexture(sky1texture); if (!skyinfo.texture[1]) return; skyinfo.x_offset[1] = gl_sky1pos; skyinfo.doublesky = true; } if ((level.flags&LEVEL_SWAPSKIES || (sky1==PL_SKYFLAT && !(gl.flags&RFL_NOSTENCIL)) || (level.flags&LEVEL_DOUBLESKY)) && sky2texture!=sky1texture) // If both skies are equal use the scroll offset of the first! { skyinfo.texture[0]=FGLTexture::ValidateTexture(sky2texture); skyinfo.skytexno1=sky2texture; skyinfo.x_offset[0] = gl_sky2pos; } else { skyinfo.texture[0]=FGLTexture::ValidateTexture(sky1texture); skyinfo.skytexno1=sky1texture; skyinfo.x_offset[0] = gl_sky1pos; } if (!skyinfo.texture[0]) return; } if (skyfog>0) { skyinfo.fadecolor=Colormap.FadeColor; skyinfo.fadecolor.a=0; } else skyinfo.fadecolor=0; type=RENDERWALL_SKY; sky = &skyinfo; } PutWall(0); }