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 gl_RenderHUDModel(DPSprite *psp, float ofsX, float ofsY) { AActor * playermo=players[consoleplayer].camera; FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false); // [BB] No model found for this sprite, so we can't render anything. if ( smf == nullptr ) return; glDepthFunc(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] )) { glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); } // [BB] The model has to be drawn independently from the position of the player, // so we have to reset the view matrix. gl_RenderState.mViewMatrix.loadIdentity(); // Scaling model (y scale for a sprite means height, i.e. z in the world!). gl_RenderState.mViewMatrix.scale(smf->xscale, smf->zscale, smf->yscale); // Aplying model offsets (model offsets do not depend on model scalings). gl_RenderState.mViewMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale); // [BB] Weapon bob, very similar to the normal Doom weapon bob. gl_RenderState.mViewMatrix.rotate(ofsX/4, 0, 1, 0); gl_RenderState.mViewMatrix.rotate((ofsY-WEAPONTOP)/-4., 1, 0, 0); // [BB] For some reason the jDoom models need to be rotated. gl_RenderState.mViewMatrix.rotate(90.f, 0, 1, 0); // Applying angleoffset, pitchoffset, rolloffset. gl_RenderState.mViewMatrix.rotate(-smf->angleoffset, 0, 1, 0); gl_RenderState.mViewMatrix.rotate(smf->pitchoffset, 0, 0, 1); gl_RenderState.mViewMatrix.rotate(-smf->rolloffset, 1, 0, 0); gl_RenderState.ApplyMatrices(); gl_RenderFrameModels( smf, psp->GetState(), psp->GetTics(), playermo->player->ReadyWeapon->GetClass(), nullptr, 0 ); glDepthFunc(GL_LESS); if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) glDisable(GL_CULL_FACE); }
void gl_RenderModel(GLSprite * spr) { FSpriteModelFrame * smf = spr->modelframe; // Setup transformation. glDepthFunc(GL_LEQUAL); gl_RenderState.EnableTexture(true); // [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] )) { glEnable(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 = spr->actor->Scale.X * smf->xscale; float scaleFactorY = spr->actor->Scale.X * smf->yscale; float scaleFactorZ = spr->actor->Scale.Y * smf->zscale; float pitch = 0; float roll = 0; float rotateOffset = 0; float angle = spr->actor->Angles.Yaw.Degrees; // [BB] Workaround for the missing pitch information. if ( (smf->flags & MDL_PITCHFROMMOMENTUM) ) { const double x = spr->actor->Vel.X; const double y = spr->actor->Vel.Y; const double z = spr->actor->Vel.Z; if (spr->actor->Vel.LengthSquared() > EQUAL_EPSILON) { // [BB] Calculate the pitch using spherical coordinates. if (z || x || y) pitch = float(atan(z / sqrt(x*x + y*y)) / M_PI * 180); // Correcting pitch if model is moving backwards if (fabs(x) > EQUAL_EPSILON || fabs(y) > EQUAL_EPSILON) { if ((x * cos(angle * M_PI / 180) + y * sin(angle * M_PI / 180)) / sqrt(x * x + y * y) < 0) pitch *= -1; } else pitch = fabs(pitch); } } if( smf->flags & MDL_ROTATING ) { const float time = smf->rotationSpeed*GetTimeFloat()/200.f; rotateOffset = float((time - xs_FloorToInt(time)) *360.f ); } // Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing. // If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the momentum vector pitch. if (smf->flags & MDL_USEACTORPITCH) { double d = spr->actor->Angles.Pitch.Degrees; if (smf->flags & MDL_BADROTATION) pitch -= d; else pitch += d; } if(smf->flags & MDL_USEACTORROLL) roll += spr->actor->Angles.Roll.Degrees; gl_RenderState.mModelMatrix.loadIdentity(); // Model space => World space gl_RenderState.mModelMatrix.translate(spr->x, spr->z, spr->y ); // Applying model transformations: // 1) Applying actor angle, pitch and roll to the model gl_RenderState.mModelMatrix.rotate(-angle, 0, 1, 0); gl_RenderState.mModelMatrix.rotate(pitch, 0, 0, 1); gl_RenderState.mModelMatrix.rotate(-roll, 1, 0, 0); // 2) Applying Doomsday like rotation of the weapon pickup models // The rotation angle is based on the elapsed time. if( smf->flags & MDL_ROTATING ) { gl_RenderState.mModelMatrix.translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ); gl_RenderState.mModelMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate); gl_RenderState.mModelMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ); } // 3) Scaling model. gl_RenderState.mModelMatrix.scale(scaleFactorX, scaleFactorZ, scaleFactorY); // 4) Aplying model offsets (model offsets do not depend on model scalings). gl_RenderState.mModelMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale); // 5) Applying model rotations. gl_RenderState.mModelMatrix.rotate(-smf->angleoffset, 0, 1, 0); gl_RenderState.mModelMatrix.rotate(smf->pitchoffset, 0, 0, 1); gl_RenderState.mModelMatrix.rotate(-smf->rolloffset, 1, 0, 0); // consider the pixel stretching. For non-voxels this must be factored out here float stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor() : 1.f) / glset.pixelstretch; gl_RenderState.mModelMatrix.scale(1, stretch, 1); gl_RenderState.EnableModelMatrix(true); gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, spr->actor->GetClass(), nullptr, translation ); gl_RenderState.EnableModelMatrix(false); glDepthFunc(GL_LESS); if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) glDisable(GL_CULL_FACE); }
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); }