// [BB] Small helper function for MDL_ROLLAGAINSTANGLE. float gl_RollAgainstAngleHelper ( const AActor *actor ) { float angleDiff = ANGLE_TO_FLOAT ( R_PointToAngle ( actor->x, actor->y ) ) - ANGLE_TO_FLOAT ( actor->angle ); if ( angleDiff > 180 ) angleDiff -= 360; else if ( angleDiff < -180 ) angleDiff += 360; if ( actor->z > viewz ) angleDiff *= -1; if ( ( angleDiff < 90 ) && ( angleDiff > - 90 ) ) angleDiff *= -1; return angleDiff; }
// 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 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); } }
//========================================================================== // // // //========================================================================== void ADynamicLight::Activate(AActor *activator) { //Super::Activate(activator); flags2&=~MF2_DORMANT; m_currentIntensity = float(m_intensity[0]); m_tickCount = 0; if (lighttype == PulseLight) { float pulseTime = ANGLE_TO_FLOAT(this->angle) / TICRATE; m_lastUpdate = level.maptime; m_cycler.SetParams(float(m_intensity[1]), float(m_intensity[0]), pulseTime); m_cycler.ShouldCycle(true); m_cycler.SetCycleType(CYCLE_Sin); m_currentIntensity = (BYTE)m_cycler.GetVal(); } }
//========================================================================== // // // //========================================================================== void ADynamicLight::Tick() { if (vid_renderer == 0) { return; } if (IsOwned()) { if (!target || !target->state) { this->Destroy(); return; } if (target->flags & MF_UNMORPHED) return; } // Don't bother if the light won't be shown if (!IsActive()) return; // I am doing this with a type field so that I can dynamically alter the type of light // without having to create or maintain multiple objects. switch(lighttype) { case PulseLight: { float diff = (level.maptime - m_lastUpdate) / (float)TICRATE; m_lastUpdate = level.maptime; m_cycler.Update(diff); m_currentIntensity = m_cycler.GetVal(); break; } case FlickerLight: { BYTE rnd = randLight(); float pct = ANGLE_TO_FLOAT(angle)/360.f; m_currentIntensity = float(m_intensity[rnd >= pct * 255]); break; } case RandomFlickerLight: { int flickerRange = m_intensity[1] - m_intensity[0]; float amt = randLight() / 255.f; m_tickCount++; if (m_tickCount > ANGLE_TO_FLOAT(angle)) { m_currentIntensity = float(m_intensity[0] + (amt * flickerRange)); m_tickCount = 0; } break; } #if 0 // These need some more work elsewhere case ColorFlickerLight: { BYTE rnd = randLight(); float pct = ANGLE_TO_FLOAT(angle)/360.f; m_currentIntensity = m_intensity[rnd >= pct * 255]; break; } case RandomColorFlickerLight: { int flickerRange = m_intensity[1] - m_intensity[0]; float amt = randLight() / 255.f; m_tickCount++; if (m_tickCount > ANGLE_TO_FLOAT(angle)) { m_currentIntensity = m_intensity[0] + (amt * flickerRange); m_tickCount = 0; } break; } #endif case SectorLight: { float intensity; float scale = args[LIGHT_SCALE] / 8.f; if (scale == 0.f) scale = 1.f; intensity = Sector->lightlevel * scale; intensity = clamp<float>(intensity, 0.f, 255.f); m_currentIntensity = intensity; break; } case PointLight: m_currentIntensity = float(m_intensity[0]); break; } UpdateLocation(); }
//========================================================================== // // 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); }
//========================================================================== // // 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); }
void gl_RenderModel(GLSprite * spr, int cm) { // [BB/EP] Take care of gl_fogmode and ZADF_FORCE_GL_DEFAULTS. OVERRIDE_FOGMODE_IF_NECESSARY FSpriteModelFrame * smf = spr->modelframe; // Setup transformation. gl.MatrixMode(GL_MODELVIEW); gl.PushMatrix(); 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 (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) { gl.Enable(GL_CULL_FACE); glFrontFace(GL_CW); } int translation = 0; if ( !(smf->flags & MDL_IGNORETRANSLATION) ) translation = spr->actor->Translation; // y scale for a sprite means height, i.e. z in the world! float scaleFactorX = FIXED2FLOAT(spr->actor->scaleX) * smf->xscale; float scaleFactorY = FIXED2FLOAT(spr->actor->scaleX) * smf->yscale; float scaleFactorZ = FIXED2FLOAT(spr->actor->scaleY) * smf->zscale; float pitch = 0; float rotateOffset = 0; float angle = ANGLE_TO_FLOAT(spr->actor->angle); // [BB] Workaround for the missing pitch information. if ( (smf->flags & MDL_PITCHFROMMOMENTUM) ) { const double x = static_cast<double>(spr->actor->velx); const double y = static_cast<double>(spr->actor->vely); const double z = static_cast<double>(spr->actor->velz); // [BB] Calculate the pitch using spherical coordinates. pitch = float(atan( z/sqrt(x*x+y*y) ) / M_PI * 180); } if( smf->flags & MDL_ROTATING ) { const float time = smf->rotationSpeed*GetTimeFloat()/200.f; rotateOffset = float((time - xs_FloorToInt(time)) *360.f ); } if (gl_fogmode != 2 && (GLRenderer->mLightCount == 0 || !gl_light_models)) { // Model space => World space gl.Translatef(spr->x, spr->z, spr->y ); if ( !(smf->flags & MDL_ALIGNANGLE) ) gl.Rotatef(-angle, 0, 1, 0); // [BB] Change the angle so that the object is exactly facing the camera in the x/y plane. else gl.Rotatef( -ANGLE_TO_FLOAT ( R_PointToAngle ( spr->actor->x, spr->actor->y ) ), 0, 1, 0); // [BB] Change the pitch so that the object is vertically facing the camera (only makes sense combined with MDL_ALIGNANGLE). if ( (smf->flags & MDL_ALIGNPITCH) ) { const fixed_t distance = R_PointToDist2( spr->actor->x - viewx, spr->actor->y - viewy ); const float pitch = RAD2DEG ( atan2( FIXED2FLOAT ( spr->actor->z - viewz ), FIXED2FLOAT ( distance ) ) ); gl.Rotatef(pitch, 0, 0, 1); } // [BB] Workaround for the missing pitch information. if (pitch != 0) gl.Rotatef(pitch, 0, 0, 1); // [BB] Special flag for flat, beam like models. if ( (smf->flags & MDL_ROLLAGAINSTANGLE) ) gl.Rotatef( gl_RollAgainstAngleHelper ( spr->actor ), 1, 0, 0); // Model rotation. // [BB] Added Doomsday like rotation of the weapon pickup models. // The rotation angle is based on the elapsed time. if( smf->flags & MDL_ROTATING ) { gl.Translatef(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ); gl.Rotatef(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate); gl.Translatef(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ); } // Scaling and model space offset. gl.Scalef(scaleFactorX, scaleFactorZ, scaleFactorY); // [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.); gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, NULL, NULL, translation ); } else { Matrix3x4 ModelToWorld; Matrix3x4 NormalTransform; // For radial fog we need to pass coordinates in world space in order to calculate distances. // That means that the local transformations cannot be part of the modelview matrix ModelToWorld.MakeIdentity(); // Model space => World space ModelToWorld.Translate(spr->x, spr->z, spr->y); if ( !(smf->flags & MDL_ALIGNANGLE) ) ModelToWorld.Rotate(0,1,0, -angle); // [BB] Change the angle so that the object is exactly facing the camera in the x/y plane. else ModelToWorld.Rotate(0,1,0, -ANGLE_TO_FLOAT ( R_PointToAngle ( spr->actor->x, spr->actor->y ) ) ); // [BB] Change the pitch so that the object is vertically facing the camera (only makes sense combined with MDL_ALIGNANGLE). if ( (smf->flags & MDL_ALIGNPITCH) ) { const fixed_t distance = R_PointToDist2( spr->actor->x - viewx, spr->actor->y - viewy ); const float pitch = RAD2DEG ( atan2( FIXED2FLOAT ( spr->actor->z - viewz ), FIXED2FLOAT ( distance ) ) ); ModelToWorld.Rotate(0,0,1,pitch); } // [BB] Workaround for the missing pitch information. if (pitch != 0) ModelToWorld.Rotate(0,0,1,pitch); // [BB] Special flag for flat, beam like models. if ( (smf->flags & MDL_ROLLAGAINSTANGLE) ) ModelToWorld.Rotate(1, 0, 0, gl_RollAgainstAngleHelper ( spr->actor )); // Model rotation. // [BB] Added Doomsday like rotation of the weapon pickup models. // The rotation angle is based on the elapsed time. if( smf->flags & MDL_ROTATING ) { ModelToWorld.Translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ); ModelToWorld.Rotate(smf->xrotate, smf->yrotate, smf->zrotate, rotateOffset); ModelToWorld.Translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ); } ModelToWorld.Scale(scaleFactorX, scaleFactorZ, scaleFactorY); // [BB] Apply zoffset here, needs to be scaled by 1 / smf->zscale, so that zoffset doesn't depend on the z-scaling. ModelToWorld.Translate(0., smf->zoffset / smf->zscale, 0.); if (!gl_light_models) { gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, &ModelToWorld, NULL, translation ); } else { // The normal transform matrix only contains the inverse rotations and scalings but not the translations NormalTransform.MakeIdentity(); NormalTransform.Scale(1.f/scaleFactorX, 1.f/scaleFactorZ, 1.f/scaleFactorY); if( smf->flags & MDL_ROTATING ) NormalTransform.Rotate(smf->xrotate, smf->yrotate, smf->zrotate, -rotateOffset); if (pitch != 0) NormalTransform.Rotate(0,0,1,-pitch); if (angle != 0) NormalTransform.Rotate(0,1,0, angle); gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, &ModelToWorld, &NormalTransform, translation ); } } gl.MatrixMode(GL_MODELVIEW); gl.PopMatrix(); gl.DepthFunc(GL_LESS); if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) gl.Disable(GL_CULL_FACE); }