void gl_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * gltexture) { // only manipulate the texture matrix if needed. if (secplane->xoffs != 0 || secplane->yoffs != 0 || secplane->xscale != FRACUNIT || secplane->yscale != FRACUNIT || secplane->angle != 0 || gltexture->TextureWidth() != 64 || gltexture->TextureHeight() != 64) { float uoffs = FIXED2FLOAT(secplane->xoffs) / gltexture->TextureWidth(); float voffs = FIXED2FLOAT(secplane->yoffs) / gltexture->TextureHeight(); float xscale1=FIXED2FLOAT(secplane->xscale); float yscale1=FIXED2FLOAT(secplane->yscale); if (gltexture->tex->bHasCanvas) { yscale1 = 0 - yscale1; } float angle=-ANGLE_TO_FLOAT(secplane->angle); float xscale2=64.f/gltexture->TextureWidth(); float yscale2=64.f/gltexture->TextureHeight(); gl_RenderState.mTextureMatrix.loadIdentity(); gl_RenderState.mTextureMatrix.scale(xscale1 ,yscale1,1.0f); gl_RenderState.mTextureMatrix.translate(uoffs,voffs,0.0f); gl_RenderState.mTextureMatrix.scale(xscale2 ,yscale2,1.0f); gl_RenderState.mTextureMatrix.rotate(angle,0.0f,0.0f,1.0f); gl_RenderState.EnableTextureMatrix(true); } }
// construct a new ViewShifter, to temporarily shift camera viewpoint ViewShifter(EyeView eyeView, player_t * player, FGLRenderer& renderer_param) { renderer = &renderer_param; saved_viewx = viewx; saved_viewy = viewy; float xf = FIXED2FLOAT(viewx); float yf = FIXED2FLOAT(viewy); float yaw = DEG2RAD( ANGLE_TO_FLOAT(viewangle) ); float eyeShift = vr_ipd / 2.0; if (eyeView == EYE_VIEW_LEFT) eyeShift = -eyeShift; float vh = 41.0; if (player != NULL) vh = FIXED2FLOAT(player->mo->ViewHeight); float mapunits_per_meter = vh/(0.95 * vr_player_height_meters); float eyeShift_mapunits = eyeShift * mapunits_per_meter; xf += sin(yaw) * eyeShift_mapunits; yf -= cos(yaw) * eyeShift_mapunits; // Printf("eyeShift_mapunits (ViewShifter) = %.1f\n", eyeShift_mapunits); viewx = FLOAT2FIXED(xf); viewy = FLOAT2FIXED(yf); renderer->SetCameraPos(viewx, viewy, viewz, viewangle); renderer->SetViewMatrix(false, false); }
void Plane::Set(secplane_t &plane) { float a, b, c, d; a = FIXED2FLOAT(plane.a); b = FIXED2FLOAT(plane.b); c = FIXED2FLOAT(plane.c); d = FIXED2FLOAT(plane.d); m_normal.Set(a, c, b); //m_normal.Normalize(); the vector is already normalized m_d = d; }
void gl_RenderHUDModel(pspdef_t *psp, fixed_t ofsx, fixed_t ofsy, int cm) { AActor * playermo=players[consoleplayer].camera; FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->state->sprite, psp->state->GetFrame()); // [BB] No model found for this sprite, so we can't render anything. if ( smf == NULL ) return; // [BB] The model has to be drawn independtly from the position of the player, // so we have to reset the GL_MODELVIEW matrix. gl.MatrixMode(GL_MODELVIEW); gl.PushMatrix(); gl.LoadIdentity(); gl.DepthFunc(GL_LEQUAL); // [BB] In case the model should be rendered translucent, do back face culling. // This solves a few of the problems caused by the lack of depth sorting. // TO-DO: Implement proper depth sorting. if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) { gl.Enable(GL_CULL_FACE); glFrontFace(GL_CCW); } // Scaling and model space offset. gl.Scalef( smf->xscale, smf->zscale, // y scale for a sprite means height, i.e. z in the world! smf->yscale); // [BB] Apply zoffset here, needs to be scaled by 1 / smf->zscale, so that zoffset doesn't depend on the z-scaling. gl.Translatef(0., smf->zoffset / smf->zscale, 0.); // [BB] Weapon bob, very similar to the normal Doom weapon bob. gl.Rotatef(FIXED2FLOAT(ofsx)/4, 0, 1, 0); gl.Rotatef(-FIXED2FLOAT(ofsy-WEAPONTOP)/4, 1, 0, 0); // [BB] For some reason the jDoom models need to be rotated. gl.Rotatef(90., 0, 1, 0); gl_RenderFrameModels( smf, psp->state, psp->tics, playermo->player->ReadyWeapon->GetClass(), cm, NULL, NULL, 0 ); gl.MatrixMode(GL_MODELVIEW); gl.PopMatrix(); gl.DepthFunc(GL_LESS); if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) gl.Disable(GL_CULL_FACE); }
void GLPlaneMirrorPortal::DrawContents() { if (renderdepth>r_mirror_recursions) { ClearScreen(); return; } int old_pm=PlaneMirrorMode; fixed_t planez = origin->ZatPoint(viewx, viewy); viewz = 2*planez - viewz; GLRenderer->mViewActor = NULL; PlaneMirrorMode = ksgn(origin->c); validcount++; PlaneMirrorFlag++; GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); ClearClipper(); glEnable(GL_CLIP_PLANE0+renderdepth); // This only works properly for non-sloped planes so don't bother with the math. //double d[4]={origin->a/65536., origin->c/65536., origin->b/65536., FIXED2FLOAT(origin->d)}; double d[4]={0, static_cast<double>(PlaneMirrorMode), 0, FIXED2FLOAT(origin->d)}; glClipPlane(GL_CLIP_PLANE0+renderdepth, d); GLRenderer->DrawScene(); glDisable(GL_CLIP_PLANE0+renderdepth); PlaneMirrorFlag--; PlaneMirrorMode=old_pm; }
void GLFlat::DrawSubsector(subsector_t * sub) { FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); if (plane.plane.a | plane.plane.b) { for (unsigned int k = 0; k < sub->numlines; k++) { vertex_t *vt = sub->firstline[k].v1; ptr->x = vt->fx; ptr->y = vt->fy; ptr->z = plane.plane.ZatPoint(vt->fx, vt->fy) + dz; ptr->u = vt->fx / 64.f; ptr->v = -vt->fy / 64.f; ptr++; } } else { float zc = FIXED2FLOAT(plane.plane.Zat0()) + dz; for (unsigned int k = 0; k < sub->numlines; k++) { vertex_t *vt = sub->firstline[k].v1; ptr->x = vt->fx; ptr->y = vt->fy; ptr->z = zc; ptr->u = vt->fx / 64.f; ptr->v = -vt->fy / 64.f; ptr++; } } GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); flatvertices += sub->numlines; flatprimitives++; }
static boolean RB_GenerateDecal(vtxlist_t *vl, int *drawcount) { vtx_t *v; rbDecal_t *decal; float offset; int count; int i; v = &drawVertex[*drawcount]; decal = (rbDecal_t*)vl->data; count = *drawcount; for(i = 0; i < decal->numpoints - 2; ++i) { RB_AddTriangle(count, count + 1 + i, count + 2 + i); } offset = 0; if(decal->type == DCT_UPPERWALL || decal->type == DCT_CEILING) { offset = FIXED2FLOAT(decal->initialStickZ - decal->stickSector->ceilingheight); } else if(decal->type == DCT_LOWERWALL || decal->type == DCT_FLOOR) { offset = FIXED2FLOAT(decal->initialStickZ - decal->stickSector->floorheight); } for(i = 0; i < decal->numpoints; ++i) { v[i].x = decal->points[i].x; v[i].y = decal->points[i].y; v[i].z = decal->points[i].z - offset; v[i].tu = decal->points[i].tu; v[i].tv = decal->points[i].tv; v[i].r = v[i].g = v[i].b = v[i].a = (byte)(decal->alpha * 255.0f); } *drawcount += decal->numpoints; return 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) ; v = (r / (float)rows) + yAdd; } else { u = (-timesRepeat * c / (float)columns) ; v = 1.0f + ((rows-r)/(float)rows) + yAdd; } glTexCoord2f(skymirror? -u:u, v); } if (r != 4) y+=FRACUNIT*300; // And finally the vertex. fx =-FIXED2FLOAT(x); // Doom mirrors the sky vertically! fy = FIXED2FLOAT(y); fz = FIXED2FLOAT(z); glVertex3f(fx, fy - 1.f, fz); }
void ADynamicLight::LinkLight() { // mark the old light nodes FLightNode * node; node = touching_sides; while (node) { node->lightsource = NULL; node = node->nextTarget; } node = touching_subsectors; while (node) { node->lightsource = NULL; node = node->nextTarget; } if (radius>0) { // passing in radius*radius allows us to do a distance check without any calls to sqrtf ::validcount++; subsector_t * subSec = R_PointInSubsector(x, y); if (subSec) { float fradius = FIXED2FLOAT(radius); CollectWithinRadius(subSec, fradius*fradius); } } // Now delete any nodes that won't be used. These are the ones where // m_thing is still NULL. node = touching_sides; while (node) { if (node->lightsource == NULL) { node = DeleteLightNode(node); } else node = node->nextTarget; } node = touching_subsectors; while (node) { if (node->lightsource == NULL) { node = DeleteLightNode(node); } else node = node->nextTarget; } }
//========================================================================== // // // //========================================================================== 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 > FIXED2FLOAT(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 FSkyVertexBuffer::SkyVertex(int r, int c, bool yflip) { static const angle_t maxSideAngle = ANGLE_180 / 3; static const fixed_t scale = 10000 << FRACBITS; angle_t topAngle= (angle_t)(c / (float)mColumns * ANGLE_MAX); angle_t sideAngle = maxSideAngle * (mRows - r) / mRows; 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]); FSkyVertex vert; vert.color = r == 0 ? 0xffffff : 0xffffffff; // And the texture coordinates. if(!yflip) // Flipped Y is for the lower hemisphere. { vert.u = (-c / (float)mColumns) ; vert.v = (r / (float)mRows); } else { vert.u = (-c / (float)mColumns); vert.v = 1.0f + ((mRows - r) / (float)mRows); } if (r != 4) y+=FRACUNIT*300; // And finally the vertex. vert.x =-FIXED2FLOAT(x); // Doom mirrors the sky vertically! vert.y = FIXED2FLOAT(y) - 1.f; vert.z = FIXED2FLOAT(z); mVertices.Push(vert); }
//========================================================================== // // // //========================================================================== void GLSprite::SplitSprite(sector_t * frontsector, bool translucent) { GLSprite copySprite; fixed_t lightbottom; float maplightbottom; unsigned int i; bool put=false; TArray<lightlist_t> & lightlist=frontsector->e->XFloor.lightlist; //y1+=y; //y2+=y; //y=0; for(i=0; i<lightlist.Size(); i++) { // Particles don't go through here so we can safely assume that actor is not NULL if (i<lightlist.Size()-1) lightbottom=lightlist[i+1].plane.ZatPoint(actor->x,actor->y); else lightbottom=frontsector->floorplane.ZatPoint(actor->x,actor->y); //maplighttop=FIXED2FLOAT(lightlist[i].height); maplightbottom=FIXED2FLOAT(lightbottom); if (maplightbottom<z2) maplightbottom=z2; if (maplightbottom<z1) { copySprite=*this; copySprite.lightlevel=*lightlist[i].p_lightlevel; copySprite.Colormap.CopyLightColor(*lightlist[i].p_extra_colormap); if (glset.nocoloredspritelighting) { int v = (copySprite.Colormap.LightColor.r + copySprite.Colormap.LightColor.g + copySprite.Colormap.LightColor.b )/3; copySprite.Colormap.LightColor.r= copySprite.Colormap.LightColor.g= copySprite.Colormap.LightColor.b=(255+v+v)/3; } if (!gl_isWhite(ThingColor)) { copySprite.Colormap.LightColor.r=(copySprite.Colormap.LightColor.r*ThingColor.r)>>8; copySprite.Colormap.LightColor.g=(copySprite.Colormap.LightColor.g*ThingColor.g)>>8; copySprite.Colormap.LightColor.b=(copySprite.Colormap.LightColor.b*ThingColor.b)>>8; } z1=copySprite.z2=maplightbottom; vt=copySprite.vb=copySprite.vt+ (maplightbottom-copySprite.z1)*(copySprite.vb-copySprite.vt)/(z2-copySprite.z1); copySprite.PutSprite(translucent); put=true; }
//========================================================================== // // // //========================================================================== 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 > FIXED2FLOAT(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); } }
float ADynamicLight::DistToSeg(seg_t *seg) { float u, px, py; float seg_dx = FIXED2FLOAT(seg->v2->x - seg->v1->x); float seg_dy = FIXED2FLOAT(seg->v2->y - seg->v1->y); float seg_length_sq = seg_dx * seg_dx + seg_dy * seg_dy; u = ( FIXED2FLOAT(x - seg->v1->x) * seg_dx + FIXED2FLOAT(y - seg->v1->y) * seg_dy) / seg_length_sq; if (u < 0.f) u = 0.f; // clamp the test point to the line segment if (u > 1.f) u = 1.f; px = FIXED2FLOAT(seg->v1->x) + (u * seg_dx); py = FIXED2FLOAT(seg->v1->y) + (u * seg_dy); px -= FIXED2FLOAT(x); py -= FIXED2FLOAT(y); return (px*px) + (py*py); }
void RenderAutomap() { size_t i; glDisable(GL_TEXTURE_2D); glColor4f(0.2,0.2,0,1); DrawQuad(0,0,1,1); glColor4f(1,1,1,1); glPushMatrix(); glTranslatef(0.5, 0.5, 0); glScalef(-0.001, 0.001, 0.001); AActor *mo = consoleplayer().mo; if(mo) glTranslatef(FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), 0); glRotatef(180, 0, 0, 1); glBegin(GL_LINES); // grid // walls for(i = 0; i < numlines; i++) { if (!(lines[i].flags & ML_MAPPED)) continue; glVertex2f(FIXED2FLOAT(lines[i].v1->x), FIXED2FLOAT(lines[i].v1->y)); glVertex2f(FIXED2FLOAT(lines[i].v2->x), FIXED2FLOAT(lines[i].v2->y)); } // players for (i = 0; i < players.size(); i++) { } // things glEnd(); glPopMatrix(); }
void FDrawInfo::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 == seg->linedef->sidedef[0]) { v1=seg->linedef->v1; v2=seg->linedef->v2; } else { v1=seg->linedef->v2; v2=seg->linedef->v1; } ws.x1= FIXED2FLOAT(v1->x); ws.y1= FIXED2FLOAT(v1->y); ws.x2= FIXED2FLOAT(v2->x); ws.y2= FIXED2FLOAT(v2->y); ws.z2= FIXED2FLOAT(frontz); ws.z1= FIXED2FLOAT(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 FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) { GLSectorPlane plane; int lightlevel; FColormap Colormap; FMaterial * gltexture; plane.GetFromSector(sec, ceiling); gltexture=FMaterial::ValidateTexture(plane.texture, true); if (!gltexture) return; if (gl_fixedcolormap) { Colormap.Clear(); 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? sec->GetCeilingLight() : sec->GetFloorLight()); } int rel = getExtraLight(); gl_SetColor(lightlevel, rel, Colormap, 1.0f); gl_SetFog(lightlevel, rel, &Colormap, false); gltexture->Bind(); float fviewx = FIXED2FLOAT(viewx); float fviewy = FIXED2FLOAT(viewy); float fviewz = FIXED2FLOAT(viewz); gl_SetPlaneTextureRotation(&plane, gltexture); gl_RenderState.Apply(); 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); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(px1, planez, py1, px1 / 64, -py1 / 64); ptr++; ptr->Set(px2, planez, py2, px2 / 64, -py2 / 64); ptr++; ptr->Set(px3, planez, py3, px3 / 64, -py3 / 64); ptr++; ptr->Set(px4, planez, py4, px4 / 64, -py4 / 64); ptr++; GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); gl_RenderState.EnableTextureMatrix(false); }
void GLWall::SetupLights() { float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Init(vtx,4); if (!p.ValidNormal()) { return; } for(int i=0;i<2;i++) { FLightNode *node; if (!seg->bPolySeg) { // Iterate through all dynamic lights which touch this wall and render them if (seg->sidedef) { node = seg->sidedef->lighthead[i]; } else node = NULL; } else if (sub) { // To avoid constant rechecking for polyobjects use the subsector's lightlist instead node = sub->lighthead[i]; } else node = NULL; while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; Vector fn, pos; float x = FIXED2FLOAT(node->lightsource->x); float y = FIXED2FLOAT(node->lightsource->y); float z = FIXED2FLOAT(node->lightsource->z); float dist = fabsf(p.DistToPoint(x, z, y)); float radius = (node->lightsource->GetRadius() * gl_lights_size); float scale = 1.0f / ((2.f * radius) - dist); if (radius > 0.f && dist < radius) { Vector nearPt, up, right; pos.Set(x,z,y); fn=p.Normal(); fn.GetRightUp(right, up); Vector tmpVec = fn * dist; nearPt = pos + tmpVec; Vector t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1.Set(&vtx[i*3]); Vector nearToVert = t1 - nearPt; tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f; tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(p, node->lightsource, Colormap.colormap, true, false, lightdata); } } } node = node->nextLight; } } int numlights[3]; lightdata.Combine(numlights, gl.MaxLights()); if (numlights[2] > 0) { draw_dlight+=numlights[2]/2; gl_RenderState.EnableLight(true); gl_RenderState.SetLights(numlights, &lightdata.arrays[0][0]); } }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // // Horizon Portal // // This simply draws the area in medium sized squares. Drawing it as a whole // polygon creates visible inaccuracies. // // Originally I tried to minimize the amount of data to be drawn but there // are 2 problems with it: // // 1. Setting this up completely negates any performance gains. // 2. It doesn't work with a 360° field of view (as when you are looking up.) // // // So the brute force mechanism is just as good. // // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // GLHorizonPortal::DrawContents // //----------------------------------------------------------------------------- void GLHorizonPortal::DrawContents() { PortalAll.Clock(); GLSectorPlane * sp=&origin->plane; FMaterial * gltexture; PalEntry color; float z; player_t * player=&players[consoleplayer]; gltexture=FMaterial::ValidateTexture(sp->texture, true); if (!gltexture) { ClearScreen(); PortalAll.Unclock(); return; } z=FIXED2FLOAT(sp->texheight); if (gltexture && gltexture->tex->isFullbright()) { // glowing textures are always drawn full bright without color gl_SetColor(255, 0, NULL, 1.f); gl_SetFog(255, 0, &origin->colormap, false); } else { int rel = getExtraLight(); gl_SetColor(origin->lightlevel, rel, &origin->colormap, 1.0f); gl_SetFog(origin->lightlevel, rel, &origin->colormap, false); } gltexture->Bind(origin->colormap.colormap); gl_RenderState.EnableAlphaTest(false); gl_RenderState.BlendFunc(GL_ONE,GL_ZERO); gl_RenderState.Apply(); bool pushed = gl_SetPlaneTextureRotation(sp, gltexture); float vx=FIXED2FLOAT(viewx); float vy=FIXED2FLOAT(viewy); // Draw to some far away boundary for(float x=-32768+vx; x<32768+vx; x+=4096) { for(float y=-32768+vy; y<32768+vy;y+=4096) { glBegin(GL_TRIANGLE_FAN); glTexCoord2f(x/64, -y/64); glVertex3f(x, z, y); glTexCoord2f(x/64 + 64, -y/64); glVertex3f(x + 4096, z, y); glTexCoord2f(x/64 + 64, -y/64 - 64); glVertex3f(x + 4096, z, y + 4096); glTexCoord2f(x/64, -y/64 - 64); glVertex3f(x, z, y + 4096); glEnd(); } } float vz=FIXED2FLOAT(viewz); float tz=(z-vz);///64.0f; // fill the gap between the polygon and the true horizon // Since I can't draw into infinity there can always be a // small gap glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(512.f, 0); glVertex3f(-32768+vx, z, -32768+vy); glTexCoord2f(512.f, tz); glVertex3f(-32768+vx, vz, -32768+vy); glTexCoord2f(-512.f, 0); glVertex3f(-32768+vx, z, 32768+vy); glTexCoord2f(-512.f, tz); glVertex3f(-32768+vx, vz, 32768+vy); glTexCoord2f(512.f, 0); glVertex3f( 32768+vx, z, 32768+vy); glTexCoord2f(512.f, tz); glVertex3f( 32768+vx, vz, 32768+vy); glTexCoord2f(-512.f, 0); glVertex3f( 32768+vx, z, -32768+vy); glTexCoord2f(-512.f, tz); glVertex3f( 32768+vx, vz, -32768+vy); glTexCoord2f(512.f, 0); glVertex3f(-32768+vx, z, -32768+vy); glTexCoord2f(512.f, tz); glVertex3f(-32768+vx, vz, -32768+vy); glEnd(); if (pushed) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); } PortalAll.Unclock(); }
void FNodeBuilder::ExtractMini (FMiniBSP *bsp) { unsigned int i; bsp->bDirty = false; bsp->Verts.Resize(Vertices.Size()); for (i = 0; i < Vertices.Size(); ++i) { bsp->Verts[i].set(Vertices[i].x, Vertices[i].y); } bsp->Subsectors.Resize(Subsectors.Size()); memset(&bsp->Subsectors[0], 0, Subsectors.Size() * sizeof(subsector_t)); bsp->Nodes.Resize(Nodes.Size()); memcpy(&bsp->Nodes[0], &Nodes[0], Nodes.Size()*sizeof(node_t)); for (i = 0; i < Nodes.Size(); ++i) { D(Printf(PRINT_LOG, "Node %d:\n", i)); // Go backwards because on 64-bit systems, both of the intchildren are // inside the first in-game child. for (int j = 1; j >= 0; --j) { if (bsp->Nodes[i].intchildren[j] & 0x80000000) { D(Printf(PRINT_LOG, " subsector %d\n", bsp->Nodes[i].intchildren[j] & 0x7FFFFFFF)); bsp->Nodes[i].children[j] = (uint8_t *)&bsp->Subsectors[bsp->Nodes[i].intchildren[j] & 0x7fffffff] + 1; } else { D(Printf(PRINT_LOG, " node %d\n", bsp->Nodes[i].intchildren[j])); bsp->Nodes[i].children[j] = &bsp->Nodes[bsp->Nodes[i].intchildren[j]]; } } for (int j = 0; j < 2; ++j) { for (int k = 0; k < 4; ++k) { bsp->Nodes[i].bbox[j][k] = FIXED2FLOAT(bsp->Nodes[i].nb_bbox[j][k]); } } } if (GLNodes) { TArray<glseg_t> glsegs; for (i = 0; i < Subsectors.Size(); ++i) { uint32_t numsegs = CloseSubsector (glsegs, i, &bsp->Verts[0]); bsp->Subsectors[i].numlines = numsegs; bsp->Subsectors[i].firstline = &bsp->Segs[bsp->Segs.Size() - numsegs]; } bsp->Segs.Resize(glsegs.Size()); for (i = 0; i < glsegs.Size(); ++i) { bsp->Segs[i] = *(seg_t *)&glsegs[i]; } } else { memcpy(&bsp->Subsectors[0], &Subsectors[0], Subsectors.Size()*sizeof(subsector_t)); bsp->Segs.Resize(Segs.Size()); for (i = 0; i < Segs.Size(); ++i) { const FPrivSeg *org = &Segs[SegList[i].SegNum]; seg_t *out = &bsp->Segs[i]; D(Printf(PRINT_LOG, "Seg %d: v1(%d) -> v2(%d)\n", i, org->v1, org->v2)); out->v1 = &bsp->Verts[org->v1]; out->v2 = &bsp->Verts[org->v2]; out->backsector = org->backsector; out->frontsector = org->frontsector; if (org->sidedef != int(NO_SIDE)) { out->linedef = Level.Lines + org->linedef; out->sidedef = Level.Sides + org->sidedef; } else // part of a miniseg { out->linedef = NULL; out->sidedef = NULL; } } for (i = 0; i < bsp->Subsectors.Size(); ++i) { bsp->Subsectors[i].firstline = &bsp->Segs[(size_t)bsp->Subsectors[i].firstline]; } } }
//========================================================================== // // // //========================================================================== 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); }
bool gl_GetSpriteLight(AActor *self, fixed_t x, fixed_t y, fixed_t z, subsector_t * subsec, int desaturation, float * out, line_t *line, int side) { ADynamicLight *light; float frac, lr, lg, lb; float radius; bool changed = false; out[0]=out[1]=out[2]=0; for(int j=0;j<2;j++) { // Go through both light lists FLightNode * node = subsec->lighthead[j]; while (node) { light=node->lightsource; //if (!light->owned || light->target == NULL || light->target->IsVisibleToPlayer()) { if (!(light->flags2&MF2_DORMANT) && (!(light->flags4&MF4_DONTLIGHTSELF) || light->target != self)) { float dist = FVector3(FIXED2FLOAT(x - light->x), FIXED2FLOAT(y - light->y), FIXED2FLOAT(z - light->z)).Length(); radius = light->GetRadius() * gl_lights_size; if (dist < radius) { frac = 1.0f - (dist / radius); if (frac > 0) { if (line != NULL) { if (P_PointOnLineSide(light->x, light->y, line) != side) { node = node->nextLight; continue; } } lr = light->GetRed() / 255.0f * gl_lights_intensity; lg = light->GetGreen() / 255.0f * gl_lights_intensity; lb = light->GetBlue() / 255.0f * gl_lights_intensity; if (light->IsSubtractive()) { float bright = FVector3(lr, lg, lb).Length(); FVector3 lightColor(lr, lg, lb); lr = (bright - lr) * -1; lg = (bright - lg) * -1; lb = (bright - lb) * -1; } out[0] += lr * frac; out[1] += lg * frac; out[2] += lb * frac; changed = true; } } } } node = node->nextLight; } } // Desaturate dynamic lighting if applicable if (desaturation>0 && desaturation<=CM_DESAT31) { float gray=(out[0]*77 + out[1]*143 + out[2]*37)/257; out[0]= (out[0]*(31-desaturation)+ gray*desaturation)/31; out[1]= (out[1]*(31-desaturation)+ gray*desaturation)/31; out[2]= (out[2]*(31-desaturation)+ gray*desaturation)/31; } return changed; }
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(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)) > FIXED2FLOAT(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]=FIXED2FLOAT(bs->floorplane.ZatPoint(v1)); ztop[1]=FIXED2FLOAT(bs->floorplane.ZatPoint(v2)); flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment! } } else { FPortal *pfront = fs->portals[sector_t::floor]; FPortal *pback = bs->portals[sector_t::floor]; float frontreflect = fs->GetReflect(sector_t::floor); if (frontreflect > 0) { float backreflect = bs->GetReflect(sector_t::floor); if (backreflect > 0 && bs->floorplane.d == fs->floorplane.d) { // Don't add intra-portal line to the portal. return; } } else if (pfront == NULL || pfront == pback) { return; } // stacked sectors fixed_t fsc1=fs->floorplane.ZatPoint(v1); fixed_t fsc2=fs->floorplane.ZatPoint(v2); zbottom[0]=zbottom[1]=-32768.0f; ztop[0]=FIXED2FLOAT(fsc1); ztop[1]=FIXED2FLOAT(fsc2); } SkyPlane(fs, sector_t::floor, true); }
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) { if (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; // very, very, very ugly special case (See Icarus MAP14) // It is VERY important that this is only done for a floor height difference of 1 // or it will cause glitches elsewhere. tex = TexMan(seg->sidedef->GetTexture(side_t::mid)); if (tex != NULL && !(seg->linedef->flags & ML_DONTPEGTOP) && seg->sidedef->GetTextureYOffset(side_t::mid) > 0) { ztop[0]=ztop[1]=32768.0f; zbottom[0]=zbottom[1]= FIXED2FLOAT(bs->ceilingplane.ZatPoint(v2) + seg->sidedef->GetTextureYOffset(side_t::mid)); SkyPlane(fs, sector_t::ceiling, false); return; } } } } ztop[0]=ztop[1]=32768.0f; FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::top)); if (bs->GetTexture(sector_t::ceiling) != skyflatnum) { zbottom[0]=zceil[0]; zbottom[1]=zceil[1]; } else { zbottom[0]=FIXED2FLOAT(bs->ceilingplane.ZatPoint(v1)); zbottom[1]=FIXED2FLOAT(bs->ceilingplane.ZatPoint(v2)); flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment! } } else { FPortal *pfront = fs->portals[sector_t::ceiling]; FPortal *pback = bs->portals[sector_t::ceiling]; float frontreflect = fs->GetReflect(sector_t::ceiling); if (frontreflect > 0) { float backreflect = bs->GetReflect(sector_t::ceiling); if (backreflect > 0 && bs->ceilingplane.d == fs->ceilingplane.d) { // Don't add intra-portal line to the portal. return; } } else if (pfront == NULL || pfront == pback) { return; } // stacked sectors fixed_t fsc1=fs->ceilingplane.ZatPoint(v1); fixed_t fsc2=fs->ceilingplane.ZatPoint(v2); ztop[0]=ztop[1]=32768.0f; zbottom[0]=FIXED2FLOAT(fsc1); zbottom[1]=FIXED2FLOAT(fsc2); } SkyPlane(fs, sector_t::ceiling, true); }
//----------------------------------------------------------------------------- // // R_EnterMirror // //----------------------------------------------------------------------------- void GLMirrorPortal::DrawContents() { if (renderdepth>r_mirror_recursions) { ClearScreen(); return; } GLRenderer->mCurrentPortal = this; angle_t startang = viewangle; fixed_t startx = viewx; fixed_t starty = viewy; vertex_t *v1 = linedef->v1; vertex_t *v2 = linedef->v2; // Reflect the current view behind the mirror. if (linedef->dx == 0) { // vertical mirror viewx = v1->x - startx + v1->x; // Compensation for reendering inaccuracies if (startx<v1->x) viewx -= FRACUNIT/2; else viewx += FRACUNIT/2; } else if (linedef->dy == 0) { // horizontal mirror viewy = v1->y - starty + v1->y; // Compensation for reendering inaccuracies if (starty<v1->y) viewy -= FRACUNIT/2; else viewy += FRACUNIT/2; } else { // any mirror--use floats to avoid integer overflow. // Use doubles to avoid losing precision which is very important here. double dx = FIXED2FLOAT(v2->x - v1->x); double dy = FIXED2FLOAT(v2->y - v1->y); double x1 = FIXED2FLOAT(v1->x); double y1 = FIXED2FLOAT(v1->y); double x = FIXED2FLOAT(startx); double y = FIXED2FLOAT(starty); // the above two cases catch len == 0 double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy); viewx = FLOAT2FIXED((x1 + r * dx)*2 - x); viewy = FLOAT2FIXED((y1 + r * dy)*2 - y); // Compensation for reendering inaccuracies FVector2 v(-dx, dy); v.MakeUnit(); viewx+= FLOAT2FIXED(v[1] * renderdepth / 2); viewy+= FLOAT2FIXED(v[0] * renderdepth / 2); } // we cannot afford any imprecisions caused by R_PointToAngle2 here. They'd be visible as seams around the mirror. viewangle = 2*R_PointToAnglePrecise (linedef->v1->x, linedef->v1->y, linedef->v2->x, linedef->v2->y) - startang; GLRenderer->mViewActor = NULL; validcount++; MirrorFlag++; GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); clipper.Clear(); angle_t af = GLRenderer->FrustumAngle(); if (af<ANGLE_180) clipper.SafeAddClipRangeRealAngles(viewangle+af, viewangle-af); angle_t a2 = linedef->v1->GetClipAngle(); angle_t a1 = linedef->v2->GetClipAngle(); clipper.SafeAddClipRange(a1,a2); GLRenderer->DrawScene(); MirrorFlag--; }
void FNodeBuilder::Extract (FLevelLocals &level) { int i; auto &outVerts = level.vertexes; int vertCount = Vertices.Size (); outVerts.Alloc(vertCount); for (i = 0; i < vertCount; ++i) { outVerts[i].set(Vertices[i].x, Vertices[i].y); } auto &outSubs = level.subsectors; auto subCount = Subsectors.Size(); outSubs.Alloc(subCount); memset(&outSubs[0], 0, subCount * sizeof(subsector_t)); auto &outNodes = level.nodes; auto nodeCount = Nodes.Size (); outNodes.Alloc(nodeCount); memcpy (&outNodes[0], &Nodes[0], nodeCount*sizeof(node_t)); for (unsigned i = 0; i < nodeCount; ++i) { D(Printf(PRINT_LOG, "Node %d: Splitter[%08x,%08x] [%08x,%08x]\n", i, outNodes[i].x, outNodes[i].y, outNodes[i].dx, outNodes[i].dy)); // Go backwards because on 64-bit systems, both of the intchildren are // inside the first in-game child. for (int j = 1; j >= 0; --j) { if (outNodes[i].intchildren[j] & 0x80000000) { D(Printf(PRINT_LOG, " subsector %d\n", outNodes[i].intchildren[j] & 0x7FFFFFFF)); outNodes[i].children[j] = (uint8_t *)(&outSubs[(outNodes[i].intchildren[j] & 0x7fffffff)]) + 1; } else { D(Printf(PRINT_LOG, " node %d\n", outNodes[i].intchildren[j])); outNodes[i].children[j] = &outNodes[outNodes[i].intchildren[j]]; } } for (int j = 0; j < 2; ++j) { for (int k = 0; k < 4; ++k) { outNodes[i].bbox[j][k] = FIXED2FLOAT(outNodes[i].nb_bbox[j][k]); } } } auto &outSegs = level.segs; if (GLNodes) { TArray<glseg_t> segs (Segs.Size()*5/4); for (unsigned i = 0; i < subCount; ++i) { uint32_t numsegs = CloseSubsector (segs, i, &outVerts[0]); outSubs[i].numlines = numsegs; outSubs[i].firstline = (seg_t *)(size_t)(segs.Size() - numsegs); } auto segCount = segs.Size (); outSegs.Alloc(segCount); for (unsigned i = 0; i < segCount; ++i) { outSegs[i] = *(seg_t *)&segs[i]; if (segs[i].Partner != DWORD_MAX) { const uint32_t storedseg = Segs[segs[i].Partner].storedseg; outSegs[i].PartnerSeg = DWORD_MAX == storedseg ? nullptr : &outSegs[storedseg]; } else { outSegs[i].PartnerSeg = nullptr; } } } else { memcpy (&outSubs[0], &Subsectors[0], subCount*sizeof(subsector_t)); auto segCount = Segs.Size (); outSegs.Alloc(segCount); for (unsigned i = 0; i < segCount; ++i) { const FPrivSeg *org = &Segs[SegList[i].SegNum]; seg_t *out = &outSegs[i]; D(Printf(PRINT_LOG, "Seg %d: v1(%d) -> v2(%d)\n", i, org->v1, org->v2)); out->v1 = &outVerts[org->v1]; out->v2 = &outVerts[org->v2]; out->backsector = org->backsector; out->frontsector = org->frontsector; out->linedef = Level.Lines + org->linedef; out->sidedef = Level.Sides + org->sidedef; out->PartnerSeg = nullptr; } } for (unsigned i = 0; i < subCount; ++i) { outSubs[i].firstline = &outSegs[(size_t)outSubs[i].firstline]; } D(Printf("%i segs, %i nodes, %i subsectors\n", segCount, nodeCount, subCount)); for (i = 0; i < Level.NumLines; ++i) { Level.Lines[i].v1 = &outVerts[(size_t)Level.Lines[i].v1]; Level.Lines[i].v2 = &outVerts[(size_t)Level.Lines[i].v2]; } }
//========================================================================== // // Draw the plane segment into the gap // //========================================================================== void FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) { GLSectorPlane plane; int lightlevel; FColormap Colormap; FMaterial * gltexture; plane.GetFromSector(sec, ceiling); gltexture=FMaterial::ValidateTexture(plane.texture, true); 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? sec->GetCeilingLight() : sec->GetFloorLight()); } int rel = getExtraLight(); gl_SetColor(lightlevel, rel, &Colormap, 1.0f); gl_SetFog(lightlevel, rel, &Colormap, false); gltexture->Bind(Colormap.colormap); float fviewx = FIXED2FLOAT(viewx); float fviewy = FIXED2FLOAT(viewy); float fviewz = FIXED2FLOAT(viewz); gl_RenderState.Apply(); bool pushed = gl_SetPlaneTextureRotation(&plane, gltexture); glBegin(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); glTexCoord2f(px1 / 64, -py1 / 64); glVertex3f(px1, planez, py1); glTexCoord2f(px2 / 64, -py2 / 64); glVertex3f(px2, planez, py2); glTexCoord2f(px3 / 64, -py3 / 64); glVertex3f(px3, planez, py3); glTexCoord2f(px4 / 64, -py4 / 64); glVertex3f(px4, planez, py4); glEnd(); if (pushed) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); } }
//========================================================================== // // Calculate sky texture // //========================================================================== void GLWall::SkyPlane(sector_t *sector, int plane, bool allowreflect) { FPortal *portal = sector->portals[plane]; if (portal != NULL) { if (GLPortal::instack[1-plane]) return; type=RENDERWALL_SECTORSTACK; this->portal = portal; } else if (sector->GetTexture(plane)==skyflatnum) { GLSkyInfo skyinfo; ASkyViewpoint * skyboxx = sector->GetSkyBox(plane); // JUSTHIT is used as an indicator that a skybox is in use. // This is to avoid recursion if (!gl_noskyboxes && skyboxx && GLRenderer->mViewActor!=skyboxx && !(skyboxx->flags&MF_JUSTHIT)) { type=RENDERWALL_SKYBOX; skybox=skyboxx; } else { int sky1 = sector->sky; memset(&skyinfo, 0, sizeof(skyinfo)); if ((sky1 & PL_SKYFLAT) && (sky1 & (PL_SKYFLAT-1))) { const line_t *l = &lines[(sky1&(PL_SKYFLAT-1))-1]; const side_t *s = l->sidedef[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] = FMaterial::ValidateTexture(texno, false, true); 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 = FIXED2FLOAT(s->GetTextureYOffset(pos)); skyinfo.mirrored = !l->args[2]; } else { normalsky: if (level.flags&LEVEL_DOUBLESKY) { skyinfo.texture[1]=FMaterial::ValidateTexture(sky1texture, false, true); skyinfo.x_offset[1] = GLRenderer->mSky1Pos; skyinfo.doublesky = true; } if ((level.flags&LEVEL_SWAPSKIES || (sky1==PL_SKYFLAT) || (level.flags&LEVEL_DOUBLESKY)) && sky2texture!=sky1texture) // If both skies are equal use the scroll offset of the first! { skyinfo.texture[0]=FMaterial::ValidateTexture(sky2texture, false, true); skyinfo.skytexno1=sky2texture; skyinfo.sky2 = true; skyinfo.x_offset[0] = GLRenderer->mSky2Pos; } else { skyinfo.texture[0]=FMaterial::ValidateTexture(sky1texture, false, true); skyinfo.skytexno1=sky1texture; skyinfo.x_offset[0] = GLRenderer->mSky1Pos; } } if (skyfog>0) { skyinfo.fadecolor=Colormap.FadeColor; skyinfo.fadecolor.a=0; } else skyinfo.fadecolor=0; type=RENDERWALL_SKY; sky=UniqueSkies.Get(&skyinfo); } } else if (allowreflect && sector->GetReflect(plane) > 0) { if ((plane == sector_t::ceiling && viewz > sector->ceilingplane.d) || (plane == sector_t::floor && viewz < -sector->floorplane.d)) return; type=RENDERWALL_PLANEMIRROR; planemirror = plane == sector_t::ceiling? §or->ceilingplane : §or->floorplane; } else return; PutWall(0); }
bool APathFollower::Interpolate () { fixed_t dx = 0, dy = 0, dz = 0; if ((args[2] & 8) && Time > 0.f) { dx = x; dy = y; dz = z; } if (CurrNode->Next==NULL) return false; UnlinkFromWorld (); if (args[2] & 1) { // linear x = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->x), FIXED2FLOAT(CurrNode->Next->x))); y = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->y), FIXED2FLOAT(CurrNode->Next->y))); z = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->z), FIXED2FLOAT(CurrNode->Next->z))); } else { // spline if (CurrNode->Next->Next==NULL) return false; x = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->x), FIXED2FLOAT(CurrNode->x), FIXED2FLOAT(CurrNode->Next->x), FIXED2FLOAT(CurrNode->Next->Next->x))); y = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->y), FIXED2FLOAT(CurrNode->y), FIXED2FLOAT(CurrNode->Next->y), FIXED2FLOAT(CurrNode->Next->Next->y))); z = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->z), FIXED2FLOAT(CurrNode->z), FIXED2FLOAT(CurrNode->Next->z), FIXED2FLOAT(CurrNode->Next->Next->z))); } LinkToWorld (); if (args[2] & 6) { if (args[2] & 8) { if (args[2] & 1) { // linear dx = CurrNode->Next->x - CurrNode->x; dy = CurrNode->Next->y - CurrNode->y; dz = CurrNode->Next->z - CurrNode->z; } else if (Time > 0.f) { // spline dx = x - dx; dy = y - dy; dz = z - dz; } else { int realarg = args[2]; args[2] &= ~(2|4|8); Time += 0.1f; dx = x; dy = y; dz = z; Interpolate (); Time -= 0.1f; args[2] = realarg; dx = x - dx; dy = y - dy; dz = z - dz; x -= dx; y -= dy; z -= dz; } if (args[2] & 2) { // adjust yaw angle = R_PointToAngle2 (0, 0, dx, dy); } if (args[2] & 4) { // adjust pitch; use floats for precision float fdx = FIXED2FLOAT(dx); float fdy = FIXED2FLOAT(dy); float fdz = FIXED2FLOAT(-dz); float dist = (float)sqrt (fdx*fdx + fdy*fdy); float ang = dist != 0.f ? (float)atan2 (fdz, dist) : 0; pitch = (angle_t)(ang * 2147483648.f / PI); } } else { if (args[2] & 2) { // interpolate angle float angle1 = (float)CurrNode->angle; float angle2 = (float)CurrNode->Next->angle; if (angle2 - angle1 <= -2147483648.f) { float lerped = Lerp (angle1, angle2 + 4294967296.f); if (lerped >= 4294967296.f) { angle = (angle_t)(lerped - 4294967296.f); } else { angle = (angle_t)lerped; } } else if (angle2 - angle1 >= 2147483648.f) { float lerped = Lerp (angle1, angle2 - 4294967296.f); if (lerped < 0.f) { angle = (angle_t)(lerped + 4294967296.f); } else { angle = (angle_t)lerped; } } else { angle = (angle_t)Lerp (angle1, angle2); } } if (args[2] & 1) { // linear if (args[2] & 4) { // interpolate pitch pitch = FLOAT2FIXED(Lerp (FIXED2FLOAT(CurrNode->pitch), FIXED2FLOAT(CurrNode->Next->pitch))); } } else { // spline if (args[2] & 4) { // interpolate pitch pitch = FLOAT2FIXED(Splerp (FIXED2FLOAT(PrevNode->pitch), FIXED2FLOAT(CurrNode->pitch), FIXED2FLOAT(CurrNode->Next->pitch), FIXED2FLOAT(CurrNode->Next->Next->pitch))); } } } } return true; }
void FGLRenderer::DrawTexture(FTexture *img, DCanvas::DrawParms &parms) { double xscale = parms.destwidth / parms.texwidth; double yscale = parms.destheight / parms.texheight; double x = parms.x - parms.left * xscale; double y = parms.y - parms.top * yscale; double w = parms.destwidth; double h = parms.destheight; float u1, v1, u2, v2, r, g, b; float light = 1.f; FMaterial * gltex = FMaterial::ValidateTexture(img); const PatchTextureInfo * pti; if (parms.colorOverlay) { // Right now there's only black. Should be implemented properly later light = 1.f - APART(parms.colorOverlay)/255.f; } if (!img->bHasCanvas) { if (!parms.alphaChannel) { int translation = 0; if (parms.remap != NULL && !parms.remap->Inactive) { GLTranslationPalette * pal = static_cast<GLTranslationPalette*>(parms.remap->GetNative()); if (pal) translation = -pal->GetIndex(); } pti = gltex->BindPatch(CM_DEFAULT, translation); } else { // This is an alpha texture pti = gltex->BindPatch(CM_SHADE, 0); } if (!pti) return; u1 = pti->GetUL(); v1 = pti->GetVT(); u2 = pti->GetUR(); v2 = pti->GetVB(); } else { gltex->Bind(CM_DEFAULT, 0, 0); u2=1.f; v2=-1.f; u1 = v1 = 0.f; gl_RenderState.SetTextureMode(TM_OPAQUE); } if (parms.flipX) { float temp = u1; u1 = u2; u2 = temp; } if (parms.windowleft > 0 || parms.windowright < parms.texwidth) { x += parms.windowleft * xscale; w -= (parms.texwidth - parms.windowright + parms.windowleft) * xscale; u1 = float(u1 + parms.windowleft / parms.texwidth); u2 = float(u2 - (parms.texwidth - parms.windowright) / parms.texwidth); } if (parms.style.Flags & STYLEF_ColorIsFixed) { r = RPART(parms.fillcolor)/255.0f; g = GPART(parms.fillcolor)/255.0f; b = BPART(parms.fillcolor)/255.0f; } else { r = g = b = light; } // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; btm = SCREENHEIGHT - btm; gl.Enable(GL_SCISSOR_TEST); int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2; gl.Scissor(parms.lclip, btm - parms.dclip + space, parms.rclip - parms.lclip, parms.dclip - parms.uclip); gl_SetRenderStyle(parms.style, !parms.masked, false); if (img->bHasCanvas) { gl_RenderState.SetTextureMode(TM_OPAQUE); } gl.Color4f(r, g, b, FIXED2FLOAT(parms.alpha)); gl_RenderState.EnableAlphaTest(false); gl_RenderState.Apply(); gl.Begin(GL_TRIANGLE_STRIP); gl.TexCoord2f(u1, v1); glVertex2d(x, y); gl.TexCoord2f(u1, v2); glVertex2d(x, y + h); gl.TexCoord2f(u2, v1); glVertex2d(x + w, y); gl.TexCoord2f(u2, v2); glVertex2d(x + w, y + h); gl.End(); gl_RenderState.EnableAlphaTest(true); gl.Scissor(0, 0, screen->GetWidth(), screen->GetHeight()); gl.Disable(GL_SCISSOR_TEST); gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.BlendEquation(GL_FUNC_ADD); }