openspades/Sources/Client/Client_Scene.cpp

793 lines
26 KiB
C++
Raw Normal View History

2014-03-09 21:43:38 +09:00
/*
Copyright (c) 2013 yvt
based on code of pysnip (c) Mathias Kaerlev 2011-2012.
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
This file is part of OpenSpades.
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
*/
#include "Client.h"
#include <Core/ConcurrentDispatch.h>
#include <Core/Settings.h>
#include <Core/Strings.h>
#include "CTFGameMode.h"
2014-03-09 21:43:38 +09:00
#include "Corpse.h"
#include "GameMap.h"
2014-03-09 21:43:38 +09:00
#include "Grenade.h"
#include "IGameMode.h"
#include "Player.h"
2014-03-09 21:43:38 +09:00
#include "TCGameMode.h"
#include "Weapon.h"
#include "World.h"
2014-03-09 21:43:38 +09:00
#include "ClientPlayer.h"
#include "ILocalEntity.h"
#include "NetClient.h"
2016-11-19 21:03:51 +09:00
DEFINE_SPADES_SETTING(cg_fov, "68");
DEFINE_SPADES_SETTING(cg_thirdperson, "0");
DEFINE_SPADES_SETTING(cg_manualFocus, "0");
DEFINE_SPADES_SETTING(cg_depthOfFieldAmount, "1");
DEFINE_SPADES_SETTING(cg_shake, "1");
2014-03-09 21:43:38 +09:00
static float nextRandom() {
2016-11-22 23:08:35 +02:00
return spades::real_dist(spades::client::mt_engine_client);
2014-03-09 21:43:38 +09:00
}
namespace spades {
namespace client {
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
#pragma mark - Drawing
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
bool Client::ShouldRenderInThirdPersonView() {
if (world && world->GetLocalPlayer()) {
if (!world->GetLocalPlayer()->IsAlive())
2014-03-09 21:43:38 +09:00
return true;
}
if ((int)cg_thirdperson != 0 && world->GetNumPlayers() <= 1) {
return true;
}
2014-03-09 21:43:38 +09:00
return false;
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
float Client::GetLocalFireVibration() {
float localFireVibration = 0.f;
localFireVibration = time - localFireVibrationTime;
localFireVibration = 1.f - localFireVibration / 0.1f;
if (localFireVibration < 0.f)
2014-03-09 21:43:38 +09:00
localFireVibration = 0.f;
return localFireVibration;
}
2016-11-20 19:13:00 +09:00
float Client::GetAimDownZoomScale() {
if (world == nullptr || world->GetLocalPlayer() == nullptr ||
world->GetLocalPlayer()->IsToolWeapon() == false ||
world->GetLocalPlayer()->IsAlive() == false)
2014-03-09 21:43:38 +09:00
return 1.f;
float delta = .8f;
switch (world->GetLocalPlayer()->GetWeapon()->GetWeaponType()) {
case SMG_WEAPON: delta = .8f; break;
case RIFLE_WEAPON: delta = 1.4f; break;
case SHOTGUN_WEAPON: delta = .4f; break;
2014-03-09 21:43:38 +09:00
}
float aimDownState = GetAimDownState();
return 1.f + powf(aimDownState, 5.f) * delta;
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
SceneDefinition Client::CreateSceneDefinition() {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
int shakeLevel = cg_shake;
2014-03-09 21:43:38 +09:00
SceneDefinition def;
def.time = (unsigned int)(time * 1000.f);
2016-11-20 19:13:00 +09:00
def.denyCameraBlur = true;
def.zFar = 200.f;
if (world) {
2014-03-09 21:43:38 +09:00
IntVector3 fogColor = world->GetFogColor();
renderer->SetFogColor(
MakeVector3(fogColor.x / 255.f, fogColor.y / 255.f, fogColor.z / 255.f));
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
Player *player = world->GetLocalPlayer();
2016-11-20 19:13:00 +09:00
2014-04-08 01:46:08 +09:00
def.blurVignette = .0f;
2016-11-20 19:13:00 +09:00
if (IsFollowing()) {
2014-03-09 21:43:38 +09:00
int limit = 100;
// if current following player has left,
// or removed,
// choose next player.
while (!world->GetPlayer(followingPlayerId) ||
world->GetPlayer(followingPlayerId)->GetFront().GetPoweredLength() <
.01f) {
2014-03-09 21:43:38 +09:00
FollowNextPlayer(false);
if ((limit--) <= 0) {
2014-03-09 21:43:38 +09:00
break;
}
}
player = world->GetPlayer(followingPlayerId);
}
if (player) {
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
float roll = 0.f;
float scale = 1.f;
float vibPitch = 0.f;
float vibYaw = 0.f;
if (ShouldRenderInThirdPersonView() ||
(IsFollowing() && player != world->GetLocalPlayer())) {
2014-03-09 21:43:38 +09:00
Vector3 center = player->GetEye();
Vector3 playerFront = player->GetFront2D();
Vector3 up = MakeVector3(0, 0, -1);
2016-11-20 19:13:00 +09:00
if ((!player->IsAlive()) && lastMyCorpse &&
player == world->GetLocalPlayer()) {
2014-03-09 21:43:38 +09:00
center = lastMyCorpse->GetCenter();
}
if (map->IsSolidWrapped((int)floorf(center.x), (int)floorf(center.y),
(int)floorf(center.z))) {
2014-03-09 21:43:38 +09:00
float z = center.z;
while (z > center.z - 5.f) {
if (!map->IsSolidWrapped((int)floorf(center.x),
(int)floorf(center.y), (int)floorf(z))) {
2014-03-09 21:43:38 +09:00
center.z = z;
break;
} else {
2014-03-09 21:43:38 +09:00
z -= 1.f;
}
}
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
float distance = 5.f;
if (player == world->GetLocalPlayer() &&
world->GetLocalPlayer()->GetTeamId() < 2 &&
!world->GetLocalPlayer()->IsAlive()) {
2014-03-09 21:43:38 +09:00
// deathcam.
float elapsedTime = time - lastAliveTime;
distance -= 3.f * expf(-elapsedTime * 1.f);
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
Vector3 eye = center;
// eye -= playerFront * 5.f;
// eye += up * 2.0f;
2014-03-09 21:43:38 +09:00
eye.x += cosf(followYaw) * cosf(followPitch) * distance;
eye.y += sinf(followYaw) * cosf(followPitch) * distance;
eye.z -= sinf(followPitch) * distance;
2016-11-20 19:13:00 +09:00
if (false) {
2014-03-09 21:43:38 +09:00
// settings for making limbo stuff
eye = center;
eye += playerFront * 3.f;
eye += up * -.1f;
eye += player->GetRight() * 2.f;
2014-03-09 21:43:38 +09:00
scale *= .6f;
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// try ray casting
GameMap::RayCastResult result;
result = map->CastRay2(center, (eye - center).Normalize(), 256);
if (result.hit) {
2014-03-09 21:43:38 +09:00
float dist = (result.hitPos - center).GetLength();
float curDist = (eye - center).GetLength();
dist -= 0.3f; // near clip plane
if (curDist > dist) {
2014-03-09 21:43:38 +09:00
float diff = curDist - dist;
eye += (center - eye).Normalize() * diff;
}
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
Vector3 front = center - eye;
front = front.Normalize();
2016-11-20 19:13:00 +09:00
if (FirstPersonSpectate == false) {
2014-12-17 01:17:03 +10:00
def.viewOrigin = eye;
def.viewAxis[0] = -Vector3::Cross(up, front).Normalize();
def.viewAxis[1] = -Vector3::Cross(front, def.viewAxis[0]).Normalize();
def.viewAxis[2] = front;
} else {
2014-12-17 01:17:03 +10:00
def.viewOrigin = player->GetEye();
def.viewAxis[0] = player->GetRight();
def.viewAxis[1] = player->GetUp();
def.viewAxis[2] = player->GetFront();
}
2016-11-20 19:13:00 +09:00
def.fovY = (float)cg_fov * static_cast<float>(M_PI) / 180.f;
def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() /
renderer->ScreenHeight()) *
2.f;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// update initial spectate pos
// this is not used now, but if the local player is
// is spectating, this is used when he/she's no
// longer following
followPos = def.viewOrigin;
followVel = MakeVector3(0, 0, 0);
2016-11-20 19:13:00 +09:00
} else if (player->GetTeamId() >= 2) {
2014-03-09 21:43:38 +09:00
// spectator view (noclip view)
Vector3 center = followPos;
Vector3 front;
Vector3 up = {0, 0, -1};
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
front.x = -cosf(followYaw) * cosf(followPitch);
front.y = -sinf(followYaw) * cosf(followPitch);
front.z = sinf(followPitch);
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.viewOrigin = center;
def.viewAxis[0] = -Vector3::Cross(up, front).Normalize();
def.viewAxis[1] = -Vector3::Cross(front, def.viewAxis[0]).Normalize();
def.viewAxis[2] = front;
2016-11-20 19:13:00 +09:00
def.fovY = (float)cg_fov * static_cast<float>(M_PI) / 180.f;
def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() /
renderer->ScreenHeight()) *
2.f;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// for 1st view, camera blur can be used
def.denyCameraBlur = false;
2016-11-20 19:13:00 +09:00
} else {
2014-03-09 21:43:38 +09:00
Vector3 front = player->GetFront();
Vector3 right = player->GetRight();
Vector3 up = player->GetUp();
2016-11-20 19:13:00 +09:00
Matrix4 eyeMatrix = clientPlayers[player->GetId()]->GetEyeMatrix();
def.viewOrigin = eyeMatrix.GetOrigin();
def.viewAxis[0] = -eyeMatrix.GetAxis(0);
def.viewAxis[1] = -eyeMatrix.GetAxis(2);
def.viewAxis[2] = eyeMatrix.GetAxis(1);
2016-11-20 19:13:00 +09:00
if (shakeLevel >= 1) {
float localFireVibration = GetLocalFireVibration();
localFireVibration *= localFireVibration;
if (player->GetTool() == Player::ToolSpade) {
2016-11-20 19:13:00 +09:00
localFireVibration *= 0.4f;
}
roll += (nextRandom() - nextRandom()) * 0.03f * localFireVibration;
scale += nextRandom() * 0.04f * localFireVibration;
vibPitch += localFireVibration * (1.f - localFireVibration) * 0.01f;
vibYaw += sinf(localFireVibration * (float)M_PI * 2.f) * 0.001f;
def.radialBlur += localFireVibration * 0.2f;
// sprint bob
{
float sp = SmoothStep(GetSprintState());
vibYaw += sinf(player->GetWalkAnimationProgress() *
static_cast<float>(M_PI) * 2.f) *
0.01f * sp;
roll -= sinf(player->GetWalkAnimationProgress() *
static_cast<float>(M_PI) * 2.f) *
0.005f * (sp);
float p = cosf(player->GetWalkAnimationProgress() *
static_cast<float>(M_PI) * 2.f);
p = p * p;
p *= p;
p *= p;
2016-11-20 19:13:00 +09:00
vibPitch += p * 0.01f * sp;
if (shakeLevel >= 2) {
vibYaw += coherentNoiseSamplers[0].Sample(
player->GetWalkAnimationProgress() * 2.5f) *
0.005f * sp;
vibPitch += coherentNoiseSamplers[1].Sample(
player->GetWalkAnimationProgress() * 2.5f) *
0.01f * sp;
roll += coherentNoiseSamplers[2].Sample(
player->GetWalkAnimationProgress() * 2.5f) *
0.008f * sp;
scale += sp * 0.1f;
}
2016-11-20 19:13:00 +09:00
}
}
2014-03-09 21:43:38 +09:00
scale /= GetAimDownZoomScale();
2016-11-20 19:13:00 +09:00
def.fovY = (float)cg_fov * static_cast<float>(M_PI) / 180.f;
def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() /
renderer->ScreenHeight()) *
2.f;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// for 1st view, camera blur can be used
def.denyCameraBlur = false;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
float aimDownState = GetAimDownState();
float per = aimDownState;
per *= per * per;
def.depthOfFieldFocalLength = per * 13.f + .054f;
2016-11-20 19:13:00 +09:00
2014-04-08 01:46:08 +09:00
def.blurVignette = .0f;
2014-03-09 21:43:38 +09:00
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// add vibration for both 1st/3rd view
{
// add grenade vibration
float grenVib = grenadeVibration;
if (grenVib > 0.f) {
if (shakeLevel >= 1) {
grenVib *= 10.f;
if (grenVib > 1.f)
grenVib = 1.f;
roll += (nextRandom() - nextRandom()) * 0.2f * grenVib;
vibPitch += (nextRandom() - nextRandom()) * 0.1f * grenVib;
vibYaw += (nextRandom() - nextRandom()) * 0.1f * grenVib;
scale -= (nextRandom() - nextRandom()) * 0.1f * grenVib;
def.radialBlur += grenVib * 0.8f;
}
}
}
{
// add grenade vibration
float grenVib = grenadeVibrationSlow;
if (grenVib > 0.f) {
if (shakeLevel >= 2) {
grenVib *= 4.f;
if (grenVib > 1.f)
grenVib = 1.f;
grenVib *= grenVib;
roll +=
coherentNoiseSamplers[0].Sample(time * 8.f) * 0.2f * grenVib;
vibPitch +=
coherentNoiseSamplers[1].Sample(time * 12.f) * 0.1f * grenVib;
vibYaw +=
coherentNoiseSamplers[2].Sample(time * 11.f) * 0.1f * grenVib;
}
2014-03-09 21:43:38 +09:00
}
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// add roll / scale
{
Vector3 right = def.viewAxis[0];
Vector3 up = def.viewAxis[1];
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.viewAxis[0] = right * cosf(roll) - up * sinf(roll);
def.viewAxis[1] = up * cosf(roll) + right * sinf(roll);
2016-11-20 19:13:00 +09:00
def.fovX = atanf(tanf(def.fovX * .5f) * scale) * 2.f;
def.fovY = atanf(tanf(def.fovY * .5f) * scale) * 2.f;
2014-03-09 21:43:38 +09:00
}
{
Vector3 u = def.viewAxis[1];
Vector3 v = def.viewAxis[2];
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.viewAxis[1] = u * cosf(vibPitch) - v * sinf(vibPitch);
def.viewAxis[2] = v * cosf(vibPitch) + u * sinf(vibPitch);
}
{
Vector3 u = def.viewAxis[0];
Vector3 v = def.viewAxis[2];
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.viewAxis[0] = u * cosf(vibYaw) - v * sinf(vibYaw);
def.viewAxis[2] = v * cosf(vibYaw) + u * sinf(vibYaw);
}
{
float wTime = world->GetTime();
if (wTime < lastHurtTime + .15f && wTime >= lastHurtTime) {
2014-03-09 21:43:38 +09:00
float per = 1.f - (wTime - lastHurtTime) / .15f;
per *= .5f - player->GetHealth() / 100.f * .3f;
def.blurVignette += per * 6.f;
}
if (wTime < lastHurtTime + .2f && wTime >= lastHurtTime) {
2014-03-09 21:43:38 +09:00
float per = 1.f - (wTime - lastHurtTime) / .2f;
per *= .5f - player->GetHealth() / 100.f * .3f;
def.saturation *= std::max(0.f, 1.f - per * 4.f);
}
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.zNear = 0.05f;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.skipWorld = false;
} else {
2014-03-09 21:43:38 +09:00
def.viewOrigin = MakeVector3(256, 256, 4);
def.viewAxis[0] = MakeVector3(-1, 0, 0);
def.viewAxis[1] = MakeVector3(0, 1, 0);
def.viewAxis[2] = MakeVector3(0, 0, 1);
2016-11-20 19:13:00 +09:00
def.fovY = (float)cg_fov * static_cast<float>(M_PI) / 180.f;
def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() /
renderer->ScreenHeight()) *
2.f;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.zNear = 0.05f;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.skipWorld = false;
}
2016-11-20 19:13:00 +09:00
} else {
2014-03-09 21:43:38 +09:00
def.viewOrigin = MakeVector3(0, 0, 0);
def.viewAxis[0] = MakeVector3(1, 0, 0);
def.viewAxis[1] = MakeVector3(0, 0, -1);
def.viewAxis[2] = MakeVector3(0, 0, 1);
2016-11-20 19:13:00 +09:00
def.fovY = (float)cg_fov * static_cast<float>(M_PI) / 180.f;
def.fovX =
atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() / renderer->ScreenHeight()) *
2.f;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.zNear = 0.05f;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.skipWorld = true;
2016-11-20 19:13:00 +09:00
renderer->SetFogColor(MakeVector3(0, 0, 0));
2014-03-09 21:43:38 +09:00
}
2016-11-20 19:13:00 +09:00
if (def.viewOrigin.z < 0.f) {
// Need to move the far plane because there's no vertical fog
def.zFar -= def.viewOrigin.z;
}
2014-03-09 21:43:38 +09:00
SPAssert(!isnan(def.viewOrigin.x));
SPAssert(!isnan(def.viewOrigin.y));
SPAssert(!isnan(def.viewOrigin.z));
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
def.radialBlur = std::min(def.radialBlur, 1.f);
2016-11-20 19:13:00 +09:00
if ((int)cg_manualFocus) {
// Depth of field is manually controlled
2015-06-20 18:36:29 +09:00
def.depthOfFieldNearBlurStrength = def.depthOfFieldFarBlurStrength =
0.5f * (float)cg_depthOfFieldAmount;
def.depthOfFieldFocalLength = focalLength;
2015-06-20 18:36:29 +09:00
} else {
def.depthOfFieldNearBlurStrength = cg_depthOfFieldAmount;
def.depthOfFieldFarBlurStrength = 0.f;
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
return def;
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
void Client::AddGrenadeToScene(spades::client::Grenade *g) {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
IModel *model;
model = renderer->RegisterModel("Models/Weapons/Grenade/Grenade.kv6");
2016-11-20 19:13:00 +09:00
if (g->GetPosition().z > 63.f) {
2014-03-09 21:43:38 +09:00
// work-around for water refraction problem
return;
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
ModelRenderParam param;
Matrix4 mat = Matrix4::Scale(0.03f);
mat = Matrix4::Translate(g->GetPosition()) * mat;
param.matrix = mat;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
renderer->RenderModel(model, param);
}
2016-11-20 19:13:00 +09:00
void Client::AddDebugObjectToScene(const spades::OBB3 &obb, const Vector4 &color) {
const Matrix4 &mat = obb.m;
2014-03-09 21:43:38 +09:00
Vector3 v[2][2][2];
v[0][0][0] = (mat * MakeVector3(0, 0, 0)).GetXYZ();
v[0][0][1] = (mat * MakeVector3(0, 0, 1)).GetXYZ();
v[0][1][0] = (mat * MakeVector3(0, 1, 0)).GetXYZ();
v[0][1][1] = (mat * MakeVector3(0, 1, 1)).GetXYZ();
v[1][0][0] = (mat * MakeVector3(1, 0, 0)).GetXYZ();
v[1][0][1] = (mat * MakeVector3(1, 0, 1)).GetXYZ();
v[1][1][0] = (mat * MakeVector3(1, 1, 0)).GetXYZ();
v[1][1][1] = (mat * MakeVector3(1, 1, 1)).GetXYZ();
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
renderer->AddDebugLine(v[0][0][0], v[1][0][0], color);
renderer->AddDebugLine(v[0][0][1], v[1][0][1], color);
renderer->AddDebugLine(v[0][1][0], v[1][1][0], color);
renderer->AddDebugLine(v[0][1][1], v[1][1][1], color);
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
renderer->AddDebugLine(v[0][0][0], v[0][1][0], color);
renderer->AddDebugLine(v[0][0][1], v[0][1][1], color);
renderer->AddDebugLine(v[1][0][0], v[1][1][0], color);
renderer->AddDebugLine(v[1][0][1], v[1][1][1], color);
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
renderer->AddDebugLine(v[0][0][0], v[0][0][1], color);
renderer->AddDebugLine(v[0][1][0], v[0][1][1], color);
renderer->AddDebugLine(v[1][0][0], v[1][0][1], color);
renderer->AddDebugLine(v[1][1][0], v[1][1][1], color);
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
void Client::DrawCTFObjects() {
SPADES_MARK_FUNCTION();
CTFGameMode *mode = static_cast<CTFGameMode *>(world->GetMode());
int tId;
IModel *base = renderer->RegisterModel("Models/MapObjects/CheckPoint.kv6");
IModel *intel = renderer->RegisterModel("Models/MapObjects/Intel.kv6");
for (tId = 0; tId < 2; tId++) {
CTFGameMode::Team &team = mode->GetTeam(tId);
2014-03-09 21:43:38 +09:00
IntVector3 col = world->GetTeam(tId).color;
Vector3 color = {col.x / 255.f, col.y / 255.f, col.z / 255.f};
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
ModelRenderParam param;
param.customColor = color;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// draw base
param.matrix = Matrix4::Translate(team.basePos);
param.matrix = param.matrix * Matrix4::Scale(.3f);
renderer->RenderModel(base, param);
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// draw flag
if (!mode->GetTeam(1 - tId).hasIntel) {
2014-03-09 21:43:38 +09:00
param.matrix = Matrix4::Translate(team.flagPos);
param.matrix = param.matrix * Matrix4::Scale(.1f);
renderer->RenderModel(intel, param);
}
}
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
void Client::DrawTCObjects() {
SPADES_MARK_FUNCTION();
TCGameMode *mode = static_cast<TCGameMode *>(world->GetMode());
int tId;
IModel *base = renderer->RegisterModel("Models/MapObjects/CheckPoint.kv6");
int cnt = mode->GetNumTerritories();
for (tId = 0; tId < cnt; tId++) {
2014-03-09 21:43:38 +09:00
TCGameMode::Territory *t = mode->GetTerritory(tId);
IntVector3 col;
if (t->ownerTeamId == 2) {
2014-03-09 21:43:38 +09:00
col = IntVector3::Make(255, 255, 255);
} else {
2014-03-09 21:43:38 +09:00
col = world->GetTeam(t->ownerTeamId).color;
}
Vector3 color = {col.x / 255.f, col.y / 255.f, col.z / 255.f};
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
ModelRenderParam param;
param.customColor = color;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// draw base
param.matrix = Matrix4::Translate(t->pos);
param.matrix = param.matrix * Matrix4::Scale(.3f);
renderer->RenderModel(base, param);
}
}
2016-11-20 19:13:00 +09:00
void Client::DrawScene() {
2014-03-09 21:43:38 +09:00
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
renderer->StartScene(lastSceneDef);
2016-11-20 19:13:00 +09:00
if (world) {
2014-03-09 21:43:38 +09:00
Player *p = world->GetLocalPlayer();
2016-11-20 19:13:00 +09:00
for (size_t i = 0; i < world->GetNumPlayerSlots(); i++)
if (world->GetPlayer(static_cast<unsigned int>(i))) {
2014-03-09 21:43:38 +09:00
SPAssert(clientPlayers[i]);
clientPlayers[i]->AddToScene();
}
std::vector<Grenade *> nades = world->GetAllGrenades();
for (size_t i = 0; i < nades.size(); i++) {
2014-03-09 21:43:38 +09:00
AddGrenadeToScene(nades[i]);
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
{
for (auto &c : corpses) {
2014-03-09 21:43:38 +09:00
Vector3 center = c->GetCenter();
if ((center - lastSceneDef.viewOrigin).GetPoweredLength() > 150.f * 150.f)
2014-03-09 21:43:38 +09:00
continue;
c->AddToScene();
}
}
2016-11-20 19:13:00 +09:00
if (IGameMode::m_CTF == world->GetMode()->ModeType()) {
2014-03-09 21:43:38 +09:00
DrawCTFObjects();
} else if (IGameMode::m_TC == world->GetMode()->ModeType()) {
2014-03-09 21:43:38 +09:00
DrawTCObjects();
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
{
for (auto &ent : localEntities) {
2014-03-09 21:43:38 +09:00
ent->Render3D();
}
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// draw block cursor
// FIXME: don't use debug line
if (p) {
if (p->IsReadyToUseTool() && p->GetTool() == Player::ToolBlock &&
p->IsAlive()) {
2014-03-09 21:43:38 +09:00
std::vector<IntVector3> blocks;
if (p->IsBlockCursorDragging()) {
blocks = std::move(world->CubeLine(p->GetBlockCursorDragPos(),
p->GetBlockCursorPos(), 256));
} else {
2014-03-09 21:43:38 +09:00
blocks.push_back(p->GetBlockCursorPos());
}
2016-11-20 19:13:00 +09:00
2014-03-11 03:42:04 +09:00
bool active = p->IsBlockCursorActive();
2016-11-20 19:13:00 +09:00
Vector4 color = {1, 1, 1, 1};
if (!active)
color = Vector4(1, 1, 0, 1);
if ((int)blocks.size() > p->GetNumBlocks())
color = MakeVector4(1, 0, 0, 1);
if (!active)
2014-03-11 03:42:04 +09:00
color.w *= 0.5f;
2016-11-20 19:13:00 +09:00
for (size_t i = 0; i < blocks.size(); i++) {
IntVector3 &v = blocks[i];
2016-11-20 19:13:00 +09:00
if (active) {
2016-11-20 19:13:00 +09:00
2014-03-11 03:42:04 +09:00
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z),
MakeVector3(v.x + 1, v.y, v.z), color);
renderer->AddDebugLine(MakeVector3(v.x, v.y + 1, v.z),
MakeVector3(v.x + 1, v.y + 1, v.z), color);
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z + 1),
MakeVector3(v.x + 1, v.y, v.z + 1), color);
renderer->AddDebugLine(MakeVector3(v.x, v.y + 1, v.z + 1),
MakeVector3(v.x + 1, v.y + 1, v.z + 1),
color);
2014-03-11 03:42:04 +09:00
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z),
MakeVector3(v.x + 1, v.y, v.z), color);
2016-11-20 19:13:00 +09:00
2014-03-11 03:42:04 +09:00
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z),
MakeVector3(v.x, v.y + 1, v.z), color);
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z + 1),
MakeVector3(v.x, v.y + 1, v.z + 1), color);
renderer->AddDebugLine(MakeVector3(v.x + 1, v.y, v.z),
MakeVector3(v.x + 1, v.y + 1, v.z), color);
renderer->AddDebugLine(MakeVector3(v.x + 1, v.y, v.z + 1),
MakeVector3(v.x + 1, v.y + 1, v.z + 1),
color);
2016-11-20 19:13:00 +09:00
2014-03-11 03:42:04 +09:00
renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z),
MakeVector3(v.x, v.y, v.z + 1), color);
renderer->AddDebugLine(MakeVector3(v.x, v.y + 1, v.z),
MakeVector3(v.x, v.y + 1, v.z + 1), color);
renderer->AddDebugLine(MakeVector3(v.x + 1, v.y, v.z),
MakeVector3(v.x + 1, v.y, v.z + 1), color);
renderer->AddDebugLine(MakeVector3(v.x + 1, v.y + 1, v.z),
MakeVector3(v.x + 1, v.y + 1, v.z + 1),
color);
} else {
2014-03-11 03:42:04 +09:00
// not active
2016-11-20 19:13:00 +09:00
2014-03-11 03:42:04 +09:00
const float ln = 0.1f;
{
float xx = v.x, yy = v.y, zz = v.z;
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx + ln, yy, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy + ln, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy, zz + ln), color);
2014-03-11 03:42:04 +09:00
}
{
float xx = v.x + 1, yy = v.y, zz = v.z;
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx - ln, yy, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy + ln, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy, zz + ln), color);
2014-03-11 03:42:04 +09:00
}
{
float xx = v.x, yy = v.y + 1, zz = v.z;
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx + ln, yy, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy - ln, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy, zz + ln), color);
2014-03-11 03:42:04 +09:00
}
{
float xx = v.x + 1, yy = v.y + 1, zz = v.z;
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx - ln, yy, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy - ln, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy, zz + ln), color);
2014-03-11 03:42:04 +09:00
}
{
float xx = v.x, yy = v.y, zz = v.z + 1;
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx + ln, yy, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy + ln, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy, zz - ln), color);
2014-03-11 03:42:04 +09:00
}
{
float xx = v.x + 1, yy = v.y, zz = v.z + 1;
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx - ln, yy, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy + ln, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy, zz - ln), color);
2014-03-11 03:42:04 +09:00
}
{
float xx = v.x, yy = v.y + 1, zz = v.z + 1;
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx + ln, yy, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy - ln, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy, zz - ln), color);
2014-03-11 03:42:04 +09:00
}
{
float xx = v.x + 1, yy = v.y + 1, zz = v.z + 1;
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx - ln, yy, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy - ln, zz), color);
renderer->AddDebugLine(Vector3(xx, yy, zz),
Vector3(xx, yy, zz - ln), color);
2014-03-11 03:42:04 +09:00
}
}
// --- one block drawn
} // end for
2016-11-20 19:13:00 +09:00
2014-03-11 03:42:04 +09:00
} // p->IsReadyToUseTool
2014-03-09 21:43:38 +09:00
}
}
2016-11-20 19:13:00 +09:00
for (size_t i = 0; i < flashDlights.size(); i++)
2014-03-09 21:43:38 +09:00
renderer->AddLight(flashDlights[i]);
flashDlightsOld.clear();
flashDlightsOld.swap(flashDlights);
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// draw player hottrack
// FIXME: don't use debug line
{
hitTag_t tag = hit_None;
Player *hottracked = HotTrackedPlayer(&tag);
if (hottracked) {
2014-03-09 21:43:38 +09:00
IntVector3 col = world->GetTeam(hottracked->GetTeamId()).color;
Vector4 color = Vector4::Make(col.x / 255.f, col.y / 255.f, col.z / 255.f, 1.f);
Vector4 color2 = Vector4::Make(1, 1, 1, 1);
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
Player::HitBoxes hb = hottracked->GetHitBoxes();
AddDebugObjectToScene(hb.head, (tag & hit_Head) ? color2 : color);
AddDebugObjectToScene(hb.torso, (tag & hit_Torso) ? color2 : color);
AddDebugObjectToScene(hb.limbs[0], (tag & hit_Legs) ? color2 : color);
AddDebugObjectToScene(hb.limbs[1], (tag & hit_Legs) ? color2 : color);
AddDebugObjectToScene(hb.limbs[2], (tag & hit_Arms) ? color2 : color);
2014-03-09 21:43:38 +09:00
}
}
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
renderer->EndScene();
}
2016-11-20 19:13:00 +09:00
Vector3 Client::Project(spades::Vector3 v) {
2014-03-09 21:43:38 +09:00
v -= lastSceneDef.viewOrigin;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// transform to NDC
Vector3 v2;
v2.x = Vector3::Dot(v, lastSceneDef.viewAxis[0]);
v2.y = Vector3::Dot(v, lastSceneDef.viewAxis[1]);
v2.z = Vector3::Dot(v, lastSceneDef.viewAxis[2]);
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
float tanX = tanf(lastSceneDef.fovX * .5f);
float tanY = tanf(lastSceneDef.fovY * .5f);
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
v2.x /= tanX * v2.z;
v2.y /= tanY * v2.z;
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
// transform to IRenderer 2D coord
v2.x = (v2.x + 1.f) / 2.f * renderer->ScreenWidth();
v2.y = (-v2.y + 1.f) / 2.f * renderer->ScreenHeight();
2016-11-20 19:13:00 +09:00
2014-03-09 21:43:38 +09:00
return v2;
}
}
}