diff --git a/Sources/Audio/ALFuncs.cpp b/Sources/Audio/ALFuncs.cpp index e5b7800d..537986ce 100644 --- a/Sources/Audio/ALFuncs.cpp +++ b/Sources/Audio/ALFuncs.cpp @@ -1,21 +1,21 @@ /* Copyright (c) 2013 yvt - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "ALFuncs.h" @@ -168,33 +168,33 @@ namespace al{ static void *GPA(const char *str) { if(!alLibrary){ - auto paths = spades::Split(s_alDriver, ";"); - std::string errors; - for (const std::string &path: paths) { - auto trimmedPath = spades::TrimSpaces(path); - try { - alLibrary = new spades::DynamicLibrary(trimmedPath.c_str()); - if (alLibrary) { - SPLog("'%s' loaded", trimmedPath.c_str()); - break; - } - } catch (const std::exception &ex) { - errors += trimmedPath; - errors += ":\n"; - errors += ex.what(); - } - } - if (!alLibrary) { - SPRaise("Failed to load a OpenAL driver.\n%s", errors.c_str()); - } + auto paths = spades::Split(s_alDriver, ";"); + std::string errors; + for (const std::string &path: paths) { + auto trimmedPath = spades::TrimSpaces(path); + try { + alLibrary = new spades::DynamicLibrary(trimmedPath.c_str()); + if (alLibrary) { + SPLog("'%s' loaded", trimmedPath.c_str()); + break; + } + } catch (const std::exception &ex) { + errors += trimmedPath; + errors += ":\n"; + errors += ex.what(); + } + } + if (!alLibrary) { + SPRaise("Failed to load a OpenAL driver.\n%s", errors.c_str()); + } } - + if(qalGetProcAddress){ void *v = qalGetProcAddress(str); if(v) return v; } - + return alLibrary->GetSymbol(str); } @@ -204,7 +204,7 @@ namespace al{ void InitEAX(void){ ALCdevice *pDevice = NULL; ALCcontext *pContext = NULL; - + pContext = qalcGetCurrentContext(); pDevice = qalcGetContextsDevice(pContext); @@ -246,9 +246,9 @@ namespace al{ SPRaise("Extension not found: '%s'", ALC_EXT_EFX_NAME); } - + } - + void Link(void) { SPLog("Linking with OpenAL library."); L(alEnable); @@ -306,7 +306,7 @@ namespace al{ L(alDopplerFactor); L(alDopplerVelocity); L(alDistanceModel); - + L(alcCreateContext); L(alcMakeContextCurrent); L(alcProcessContext); @@ -322,9 +322,9 @@ namespace al{ L(alcGetEnumValue); L(alcGetString); L(alcGetIntegerv); - + } - + const char *DescribeError(ALenum e){ switch(e){ case AL_NO_ERROR: @@ -343,7 +343,7 @@ namespace al{ return "Unknown error"; } } - + void CheckError(void){ ALenum e; e = qalGetError(); @@ -354,7 +354,7 @@ namespace al{ SPLog("OpenAL error %d: %s", (int)e, DescribeError(e)); } } - + void CheckError(const char *source, const char *fun, int line){ ALenum e; e = qalGetError(); diff --git a/Sources/Client/ClientPlayer.cpp b/Sources/Client/ClientPlayer.cpp index 2acd48d8..8976cf17 100644 --- a/Sources/Client/ClientPlayer.cpp +++ b/Sources/Client/ClientPlayer.cpp @@ -1,21 +1,21 @@ /* Copyright (c) 2013 yvt - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ @@ -49,15 +49,15 @@ DEFINE_SPADES_SETTING(cg_animations, "1"); namespace spades { namespace client { - + class SandboxedRenderer : public IRenderer { Handle base; AABB3 clipBox; bool allowDepthHack; - + void OnProhibitedAction() { } - + bool CheckVisibility(const AABB3 &box) { if (!clipBox.Contains(box) || !std::isfinite(box.min.x) || !std::isfinite(box.min.y) || !std::isfinite(box.min.z) || @@ -70,46 +70,46 @@ namespace spades { protected: ~SandboxedRenderer(){} public: - + SandboxedRenderer(IRenderer *base) : base(base) {} - + void SetClipBox(const AABB3 &b) { clipBox = b; } void SetAllowDepthHack(bool h) { allowDepthHack = h; } - + void Init() { OnProhibitedAction(); } void Shutdown() { OnProhibitedAction(); } - + IImage *RegisterImage(const char *filename) { return base->RegisterImage(filename); } IModel *RegisterModel(const char *filename) { return base->RegisterModel(filename); } - + IImage *CreateImage(Bitmap *bmp) { return base->CreateImage(bmp); } IModel *CreateModel(VoxelModel *m) { return base->CreateModel(m); } - + void SetGameMap(GameMap *) { OnProhibitedAction(); } - + void SetFogDistance(float) { OnProhibitedAction(); } void SetFogColor(Vector3) { OnProhibitedAction(); } - + void StartScene(const SceneDefinition&) { OnProhibitedAction(); } - + void AddLight(const client::DynamicLightParam& light) { Vector3 rad(light.radius, light.radius, light.radius); if (CheckVisibility(AABB3(light.origin - rad, light.origin + rad))) { base->AddLight(light); } } - + void RenderModel(IModel *model, const ModelRenderParam& p) { if (!model) { SPInvalidArgument("model"); @@ -127,7 +127,7 @@ namespace spades { void AddDebugLine(Vector3 a, Vector3 b, Vector4 color) { OnProhibitedAction(); } - + void AddSprite(IImage *image, Vector3 center, float radius, float rotation) { Vector3 rad(radius * 1.5f, radius * 1.5f, radius * 1.5f); if (CheckVisibility(AABB3(center - rad, center + rad))) { @@ -144,11 +144,11 @@ namespace spades { base->AddLongSprite(image, p1, p2, radius); } } - + void EndScene() { OnProhibitedAction(); } - + void MultiplyScreenColor(Vector3) { OnProhibitedAction(); } - + /** Sets color for image drawing. Deprecated because * some methods treats this as an alpha premultiplied, while * others treats this as an alpha non-premultiplied. @@ -156,12 +156,12 @@ namespace spades { void SetColor(Vector4 col) { base->SetColor(col); } - + /** Sets color for image drawing. Always alpha premultiplied. */ void SetColorAlphaPremultiplied(Vector4 col) { base->SetColorAlphaPremultiplied(col); } - + void DrawImage(IImage *img, const Vector2& outTopLeft) { if (allowDepthHack) @@ -197,28 +197,28 @@ namespace spades { else OnProhibitedAction(); } - + void DrawFlatGameMap(const AABB2& outRect, const AABB2& inRect) { OnProhibitedAction(); } - + void FrameDone() { OnProhibitedAction(); } - + void Flip() { OnProhibitedAction(); } - + Bitmap *ReadBitmap() { OnProhibitedAction(); return nullptr; } - + float ScreenWidth() { return base->ScreenWidth(); } float ScreenHeight() { return base->ScreenHeight(); } }; - + ClientPlayer::ClientPlayer(Player *p, Client *c): player(p), client(c){ SPADES_MARK_FUNCTION(); - + sprintState = 0.f; aimDownState = 0.f; toolRaiseState = 0.f; @@ -226,32 +226,32 @@ namespace spades { localFireVibrationTime = -100.f; time = 0.f; viewWeaponOffset = MakeVector3(0, 0, 0); - + ScriptContextHandle ctx; IRenderer *renderer = client->GetRenderer(); IAudioDevice *audio = client->GetAudioDevice(); - + sandboxedRenderer.Set(new SandboxedRenderer(renderer), false); renderer = sandboxedRenderer; - + static ScriptFunction spadeFactory("ISpadeSkin@ CreateThirdPersonSpadeSkin(Renderer@, AudioDevice@)"); spadeSkin = initScriptFactory( spadeFactory, renderer, audio ); - + static ScriptFunction spadeViewFactory("ISpadeSkin@ CreateViewSpadeSkin(Renderer@, AudioDevice@)"); spadeViewSkin = initScriptFactory( spadeViewFactory, renderer, audio ); - + static ScriptFunction blockFactory("IBlockSkin@ CreateThirdPersonBlockSkin(Renderer@, AudioDevice@)"); blockSkin = initScriptFactory( blockFactory, renderer, audio ); - + static ScriptFunction blockViewFactory("IBlockSkin@ CreateViewBlockSkin(Renderer@, AudioDevice@)"); blockViewSkin = initScriptFactory( blockViewFactory, renderer, audio ); - + static ScriptFunction grenadeFactory("IGrenadeSkin@ CreateThirdPersonGrenadeSkin(Renderer@, AudioDevice@)"); grenadeSkin = initScriptFactory( grenadeFactory, renderer, audio ); - + static ScriptFunction grenadeViewFactory("IGrenadeSkin@ CreateViewGrenadeSkin(Renderer@, AudioDevice@)"); grenadeViewSkin = initScriptFactory( grenadeViewFactory, renderer, audio ); - + static ScriptFunction rifleFactory("IWeaponSkin@ CreateThirdPersonRifleSkin(Renderer@, AudioDevice@)"); static ScriptFunction smgFactory("IWeaponSkin@ CreateThirdPersonSMGSkin(Renderer@, AudioDevice@)"); static ScriptFunction shotgunFactory("IWeaponSkin@ CreateThirdPersonShotgunSkin(Renderer@, AudioDevice@)"); @@ -274,19 +274,19 @@ namespace spades { default: SPAssert(false); } - + } ClientPlayer::~ClientPlayer() { spadeSkin->Release(); blockSkin->Release(); weaponSkin->Release(); grenadeSkin->Release(); - + spadeViewSkin->Release(); blockViewSkin->Release(); weaponViewSkin->Release(); grenadeViewSkin->Release(); - + } asIScriptObject* ClientPlayer::initScriptFactory( ScriptFunction& creator, IRenderer* renderer, IAudioDevice* audio ) @@ -303,12 +303,12 @@ namespace spades { void ClientPlayer::Invalidate() { player = NULL; } - + bool ClientPlayer::IsChangingTool() { return currentTool != player->GetTool() || toolRaiseState < .999f; } - + float ClientPlayer::GetLocalFireVibration() { float localFireVibration = 0.f; localFireVibration = time - localFireVibrationTime; @@ -317,10 +317,10 @@ namespace spades { localFireVibration = 0.f; return localFireVibration; } - + void ClientPlayer::Update(float dt) { time += dt; - + PlayerInput actualInput = player->GetInput(); WeaponInput actualWeapInput = player->GetWeaponInput(); Vector3 vel = player->GetVelocty(); @@ -335,29 +335,29 @@ namespace spades { if(sprintState < 0.f) sprintState = 0.f; } - + if(actualWeapInput.secondary && player->IsToolWeapon() && player->IsAlive()){ - // This is the only animation that can be turned off - // here; others affect the gameplay directly and - // turning them off would be considered cheating - if (cg_animations) { - aimDownState += dt * 8.f; - if(aimDownState > 1.f) - aimDownState = 1.f; - } else { - aimDownState = 1.f; - } - }else{ - if (cg_animations) { - aimDownState -= dt * 3.f; - if(aimDownState < 0.f) - aimDownState = 0.f; - } else { - aimDownState = 0.f; - } + // This is the only animation that can be turned off + // here; others affect the gameplay directly and + // turning them off would be considered cheating + if (cg_animations) { + aimDownState += dt * 8.f; + if(aimDownState > 1.f) + aimDownState = 1.f; + } else { + aimDownState = 1.f; + } + }else{ + if (cg_animations) { + aimDownState -= dt * 3.f; + if(aimDownState < 0.f) + aimDownState = 0.f; + } else { + aimDownState = 0.f; + } } - + if(currentTool == player->GetTool()) { toolRaiseState += dt * 4.f; if(toolRaiseState > 1.f) @@ -369,7 +369,7 @@ namespace spades { if(toolRaiseState < 0.f){ toolRaiseState = 0.f; currentTool = player->GetTool(); - + // play tool change sound if(player->IsLocalPlayer()) { auto *audioDevice = client->GetAudioDevice(); @@ -393,7 +393,7 @@ namespace spades { c = audioDevice->RegisterSound("Sounds/Weapons/Shotgun/RaiseLocal.wav"); break; } - + break; case Player::ToolGrenade: c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/RaiseLocal.wav"); @@ -406,7 +406,7 @@ namespace spades { toolRaiseState = 1.f; } } - + { float scale = dt; Vector3 vel = player->GetVelocty(); @@ -418,13 +418,13 @@ namespace spades { viewWeaponOffset.z += Vector3::Dot(vel, up) * scale; if(dt > 0.f) viewWeaponOffset *= powf(.02f, dt); - + if(currentTool == Player::ToolWeapon && player->GetWeaponInput().secondary) { - + if(dt > 0.f) viewWeaponOffset *= powf(.01f, dt); - + const float limitX = .003f; const float limitY = .003f; if(viewWeaponOffset.x < -limitX) @@ -437,7 +437,7 @@ namespace spades { viewWeaponOffset.z = Mix(viewWeaponOffset.z, limitY, .5f); } } - + // FIXME: should do for non-active skins? asIScriptObject *skin; if(ShouldRenderInThirdPersonView()){ @@ -470,17 +470,17 @@ namespace spades { interface.Update(dt); } } - + Matrix4 ClientPlayer::GetEyeMatrix() { Player *p = player; return Matrix4::FromAxis(-p->GetRight(), p->GetFront(), -p->GetUp(), p->GetEye()); } - + void ClientPlayer::SetSkinParameterForTool(Player::ToolType type, asIScriptObject *skin) { Player *p = player; if(currentTool == Player::ToolSpade) { - + ScriptISpadeSkin interface(skin); WeaponInput inp = p->GetWeaponInput(); if(p->GetTool() != Player::ToolSpade){ @@ -499,7 +499,7 @@ namespace spades { interface.SetActionProgress(0.f); } }else if(currentTool == Player::ToolBlock) { - + // TODO: smooth ready state ScriptIBlockSkin interface(skin); if(p->GetTool() != Player::ToolBlock){ @@ -511,13 +511,13 @@ namespace spades { }else{ interface.SetReadyState(0.f); } - + interface.SetBlockColor(MakeVector3(p->GetBlockColor()) / 255.f); }else if(currentTool == Player::ToolGrenade) { - + ScriptIGrenadeSkin interface(skin); interface.SetReadyState(1.f - p->GetTimeToNextGrenade() / 0.5f); - + WeaponInput inp = p->GetWeaponInput(); if(inp.primary) { interface.SetCookTime(p->GetGrenadeCookTime()); @@ -525,7 +525,7 @@ namespace spades { interface.SetCookTime(0.f); } }else if(currentTool == Player::ToolWeapon) { - + Weapon *w = p->GetWeapon(); ScriptIWeaponSkin interface(skin); interface.SetReadyState(1.f - w->TimeToNextFire() / w->GetDelay()); @@ -538,7 +538,7 @@ namespace spades { SPInvalidEnum("currentTool", currentTool); } } - + void ClientPlayer::SetCommonSkinParameter(asIScriptObject *skin){ asIScriptObject *curSkin; if(ShouldRenderInThirdPersonView()){ @@ -566,7 +566,7 @@ namespace spades { SPInvalidEnum("currentTool", currentTool); } } - + float sprint = SmoothStep(sprintState); float putdown = 1.f - toolRaiseState; putdown *= putdown; @@ -580,22 +580,22 @@ namespace spades { interface.SetMuted(client->IsMuted()); } } - + void ClientPlayer::AddToSceneFirstPersonView() { Player *p = player; IRenderer *renderer = client->GetRenderer(); World *world = client->GetWorld(); Matrix4 eyeMatrix = GetEyeMatrix(); - + sandboxedRenderer->SetClipBox(AABB3(eyeMatrix.GetOrigin() - Vector3(20.f, 20.f, 20.f), eyeMatrix.GetOrigin() + Vector3(20.f, 20.f, 20.f))); sandboxedRenderer->SetAllowDepthHack(true); - + if(client->flashlightOn){ float brightness; brightness = client->time - client->flashlightOnTime; brightness = 1.f - expf(-brightness * 5.f); - + // add flash light DynamicLightParam light; light.origin = (eyeMatrix * MakeVector3(0, -0.05f, -0.1f)).GetXYZ(); @@ -608,26 +608,26 @@ namespace spades { light.spotAxis[2] = p->GetFront(); light.image = renderer->RegisterImage("Gfx/Spotlight.png"); renderer->AddLight(light); - + light.color *= .3f; light.radius = 10.f; light.type = DynamicLightTypePoint; light.image = NULL; renderer->AddLight(light); - + // add glare renderer->SetColorAlphaPremultiplied(MakeVector4(1, .7f, .5f, 0) * brightness * .3f); renderer->AddSprite(renderer->RegisterImage("Gfx/Glare.png"), (eyeMatrix * MakeVector3(0, 0.3f, -0.3f)).GetXYZ(), .8f, 0.f); } - + Vector3 leftHand, rightHand; leftHand = MakeVector3(0, 0, 0); rightHand = MakeVector3(0, 0, 0); - + // view weapon - + Vector3 viewWeaponOffset = this->viewWeaponOffset; - + // bobbing { float sp = 1.f - aimDownState; @@ -638,19 +638,19 @@ namespace spades { vl *= vl; viewWeaponOffset.z += vl * 0.012f * sp; } - + // slow pulse { float sp = 1.f - aimDownState; float vl = sinf(world->GetTime() * 1.f); - + viewWeaponOffset.x += vl * 0.001f * sp; viewWeaponOffset.y += vl * 0.0007f * sp; viewWeaponOffset.z += vl * 0.003f * sp; } - + asIScriptObject *skin; - + if(currentTool == Player::ToolSpade) { skin = spadeViewSkin; }else if(currentTool == Player::ToolBlock) { @@ -662,11 +662,11 @@ namespace spades { }else{ SPInvalidEnum("currentTool", currentTool); } - + SetSkinParameterForTool(currentTool, skin); - + SetCommonSkinParameter(skin); - + // common process { ScriptIViewToolSkin interface(skin); @@ -682,23 +682,23 @@ namespace spades { leftHand = interface.GetLeftHandPosition(); rightHand = interface.GetRightHandPosition(); } - + // view hands if(leftHand.GetPoweredLength() > 0.001f && rightHand.GetPoweredLength() > 0.001f){ - - + + ModelRenderParam param; param.depthHack = true; - + IModel *model = renderer->RegisterModel("Models/Player/Arm.kv6"); IModel *model2 = renderer->RegisterModel("Models/Player/UpperArm.kv6"); - + IntVector3 col = p->GetColor(); param.customColor = MakeVector3(col.x/255.f, col.y/255.f, col.z/255.f); - + const float armlen = 0.5f; - + Vector3 shoulders[] = {{0.4f, 0.0f, 0.25f}, {-0.4f, 0.0f, 0.25f}}; Vector3 hands[] = {leftHand, rightHand}; @@ -708,65 +708,65 @@ namespace spades { Vector3 shoulder = shoulders[i]; Vector3 hand = hands[i]; Vector3 benddir = benddirs[i]; - + float len2 = (hand - shoulder).GetPoweredLength(); // len2/4 + x^2 = armlen^2 float bendlen = sqrtf(std::max(armlen*armlen - len2*.25f, 0.f)); - + Vector3 bend = Vector3::Cross(benddir, hand-shoulder); bend = bend.Normalize(); - + if(bend.z < 0.f) bend.z = -bend.z; - + Vector3 elbow = (hand + shoulder) * .5f; elbow += bend * bendlen; - + { Vector3 axises[3]; axises[2] = (hand - elbow).Normalize(); axises[0] = MakeVector3(0, 0, 1); axises[1] = Vector3::Cross(axises[2], axises[0]).Normalize(); axises[0] = Vector3::Cross(axises[1], axises[2]).Normalize(); - + Matrix4 mat = Matrix4::Scale(.05f); mat = Matrix4::FromAxis(axises[0], axises[1], axises[2], elbow) * mat; mat = eyeMatrix * mat; - + param.matrix = mat; renderer->RenderModel(model, param); } - + { Vector3 axises[3]; axises[2] = (elbow - shoulder).Normalize(); axises[0] = MakeVector3(0, 0, 1); axises[1] = Vector3::Cross(axises[2], axises[0]).Normalize(); axises[0] = Vector3::Cross(axises[1], axises[2]).Normalize(); - + Matrix4 mat = Matrix4::Scale(.05f); mat = Matrix4::FromAxis(axises[0], axises[1], axises[2], shoulder) * mat; mat = eyeMatrix * mat; - + param.matrix = mat; renderer->RenderModel(model2, param); } } - + } - + // --- local view ends - + } - - + + void ClientPlayer::AddToSceneThirdPersonView() { Player *p = player; IRenderer *renderer = client->GetRenderer(); World *world = client->GetWorld(); - - - + + + if(!p->IsAlive()){ if(!cg_ragdoll){ ModelRenderParam param; @@ -774,21 +774,21 @@ namespace spades { param.matrix = param.matrix * Matrix4::Scale(.1f); IntVector3 col = p->GetColor(); param.customColor = MakeVector3(col.x/255.f, col.y/255.f, col.z/255.f); - + IModel *model = renderer->RegisterModel("Models/Player/Dead.kv6"); renderer->RenderModel(model, param); } return; } - + auto origin = p->GetOrigin(); sandboxedRenderer->SetClipBox(AABB3(origin - Vector3(2.f, 2.f, 4.f), origin + Vector3(2.f, 2.f, 2.f))); sandboxedRenderer->SetAllowDepthHack(false); - + // ready for tool rendering asIScriptObject *skin; - + if(currentTool == Player::ToolSpade) { skin = spadeSkin; }else if(currentTool == Player::ToolBlock) { @@ -800,107 +800,107 @@ namespace spades { }else{ SPInvalidEnum("currentTool", currentTool); } - + SetSkinParameterForTool(currentTool, skin); - + SetCommonSkinParameter(skin); - + float pitchBias; { ScriptIThirdPersonToolSkin interface(skin); pitchBias = interface.GetPitchBias(); } - + ModelRenderParam param; IModel *model; Vector3 front = p->GetFront(); IntVector3 col = p->GetColor(); param.customColor = MakeVector3(col.x/255.f, col.y/255.f, col.z/255.f); - + float yaw = atan2(front.y, front.x) + M_PI * .5f; float pitch = -atan2(front.z, sqrt(front.x * front.x + front.y * front.y)); - + // lower axis Matrix4 lower = Matrix4::Translate(p->GetOrigin()); lower = lower * Matrix4::Rotate(MakeVector3(0,0,1), yaw); - + Matrix4 scaler = Matrix4::Scale(0.1f); scaler = scaler * Matrix4::Scale(-1,-1,1); - + PlayerInput inp = p->GetInput(); - + // lower Matrix4 torso, head, arms; if(inp.crouch){ Matrix4 leg1 = Matrix4::Translate(-0.25f, 0.2f, -0.1f); Matrix4 leg2 = Matrix4::Translate( 0.25f, 0.2f, -0.1f); - + float ang = sinf(p->GetWalkAnimationProgress() * M_PI * 2.f) * 0.6f; float walkVel = Vector3::Dot(p->GetVelocty(), p->GetFront2D()) * 4.f; leg1 = leg1 * Matrix4::Rotate(MakeVector3(1,0,0), ang * walkVel); leg2 = leg2 * Matrix4::Rotate(MakeVector3(1,0,0), -ang * walkVel); - + walkVel = Vector3::Dot(p->GetVelocty(), p->GetRight()) * 3.f; leg1 = leg1 * Matrix4::Rotate(MakeVector3(0,1,0), ang * walkVel); leg2 = leg2 * Matrix4::Rotate(MakeVector3(0,1,0), -ang * walkVel); - + leg1 = lower * leg1; leg2 = lower * leg2; - + model = renderer->RegisterModel("Models/Player/LegCrouch.kv6"); param.matrix = leg1 * scaler; renderer->RenderModel(model, param); param.matrix = leg2 * scaler; renderer->RenderModel(model, param); - + torso = Matrix4::Translate(0.f,0.f,-0.55f); torso = lower * torso; - + model = renderer->RegisterModel("Models/Player/TorsoCrouch.kv6"); param.matrix = torso * scaler; renderer->RenderModel(model, param); - + head = Matrix4::Translate(0.f,0.f,-0.0f); head = torso * head; - + arms = Matrix4::Translate(0.f,0.f,-0.0f); arms = torso * arms; }else{ Matrix4 leg1 = Matrix4::Translate(-0.25f, 0.f, -0.1f); Matrix4 leg2 = Matrix4::Translate( 0.25f, 0.f, -0.1f); - + float ang = sinf(p->GetWalkAnimationProgress() * M_PI * 2.f) * 0.6f; float walkVel = Vector3::Dot(p->GetVelocty(), p->GetFront2D()) * 4.f; leg1 = leg1 * Matrix4::Rotate(MakeVector3(1,0,0), ang * walkVel); leg2 = leg2 * Matrix4::Rotate(MakeVector3(1,0,0), -ang * walkVel); - + walkVel = Vector3::Dot(p->GetVelocty(), p->GetRight()) * 3.f; leg1 = leg1 * Matrix4::Rotate(MakeVector3(0,1,0), ang * walkVel); leg2 = leg2 * Matrix4::Rotate(MakeVector3(0,1,0), -ang * walkVel); - + leg1 = lower * leg1; leg2 = lower * leg2; - + model = renderer->RegisterModel("Models/Player/Leg.kv6"); param.matrix = leg1 * scaler; renderer->RenderModel(model, param); param.matrix = leg2 * scaler; renderer->RenderModel(model, param); - + torso = Matrix4::Translate(0.f,0.f,-1.0f); torso = lower * torso; - + model = renderer->RegisterModel("Models/Player/Torso.kv6"); param.matrix = torso * scaler; renderer->RenderModel(model, param); - + head = Matrix4::Translate(0.f,0.f,-0.0f); head = torso * head; - + arms = Matrix4::Translate(0.f,0.f,0.1f); arms = torso * arms; } - + float armPitch = pitch; if(inp.sprint) { armPitch -= .5f; @@ -910,20 +910,20 @@ namespace spades { armPitch = std::max(armPitch, -(float)M_PI * .5f); armPitch *= .9f; } - + arms = arms * Matrix4::Rotate(MakeVector3(1,0,0), armPitch); - + model = renderer->RegisterModel("Models/Player/Arms.kv6"); param.matrix = arms * scaler; renderer->RenderModel(model, param); - - + + head = head * Matrix4::Rotate(MakeVector3(1,0,0), pitch); - + model = renderer->RegisterModel("Models/Player/Head.kv6"); param.matrix = head * scaler; renderer->RenderModel(model, param); - + // draw tool { ScriptIThirdPersonToolSkin interface(skin); @@ -933,8 +933,8 @@ namespace spades { ScriptIToolSkin interface(skin); interface.AddToScene(); } - - + + // draw intel in ctf IGameMode* mode = world->GetMode(); if( mode && IGameMode::m_CTF == mode->ModeType() ){ @@ -943,35 +943,35 @@ namespace spades { if(tId < 3){ CTFGameMode::Team& team = ctfMode->GetTeam(p->GetTeamId()); if(team.hasIntel && team.carrier == p->GetId()){ - + IntVector3 col2 = world->GetTeam(1-p->GetTeamId()).color; param.customColor = MakeVector3(col2.x/255.f, col2.y/255.f, col2.z/255.f); Matrix4 mIntel = torso * Matrix4::Translate(0,0.6f,0.5f); - + model = renderer->RegisterModel("Models/MapObjects/Intel.kv6"); param.matrix = mIntel * scaler; renderer->RenderModel(model, param); - + param.customColor = MakeVector3(col.x/255.f, col.y/255.f, col.z/255.f); } } } - + // third person player rendering, done } - + void ClientPlayer::AddToScene() { SPADES_MARK_FUNCTION(); - + Player *p = player; IRenderer *renderer = client->GetRenderer(); const SceneDefinition& lastSceneDef = client->GetLastSceneDef(); - + if(p->GetTeamId() >= 2){ // spectator, or dummy player return; - + } // debug if(false){ @@ -979,23 +979,23 @@ namespace spades { renderer->SetColorAlphaPremultiplied(MakeVector4(1, 0, 0, 0)); renderer->AddLongSprite(img, lastSceneDef.viewOrigin + MakeVector3(0, 0, 1), p->GetOrigin(), 0.5f); } - + float distancePowered = (p->GetOrigin() - lastSceneDef.viewOrigin).GetPoweredLength(); if(distancePowered > 140.f * 140.f){ return; } - + if(!ShouldRenderInThirdPersonView()){ AddToSceneFirstPersonView(); } else { AddToSceneThirdPersonView(); } } - + void ClientPlayer::Draw2D() { if(!ShouldRenderInThirdPersonView()) { asIScriptObject *skin; - + if(currentTool == Player::ToolSpade) { skin = spadeViewSkin; }else if(currentTool == Player::ToolBlock) { @@ -1007,11 +1007,11 @@ namespace spades { }else{ SPInvalidEnum("currentTool", currentTool); } - + SetSkinParameterForTool(currentTool, skin); - + SetCommonSkinParameter(skin); - + // common process { ScriptIViewToolSkin interface(skin); @@ -1021,13 +1021,13 @@ namespace spades { } } } - + bool ClientPlayer::ShouldRenderInThirdPersonView() { if(player != player->GetWorld()->GetLocalPlayer()) return true; return client->ShouldRenderInThirdPersonView(); } - + void ClientPlayer::FiredWeapon() { World *world = player->GetWorld(); Vector3 muzzle; @@ -1035,7 +1035,7 @@ namespace spades { IRenderer *renderer = client->GetRenderer(); IAudioDevice *audioDevice = client->GetAudioDevice(); Player *p = player; - + // make dlight { Vector3 vec; @@ -1045,12 +1045,12 @@ namespace spades { .5f, 0.2f); mat = eyeMatrix * mat; - + vec = (mat * MakeVector3(0, 1, 0)).GetXYZ(); muzzle = vec; client->MuzzleFire(vec, player->GetFront(), player == world->GetLocalPlayer()); } - + if(cg_ejectBrass){ float dist = (player->GetOrigin() - lastSceneDef.viewOrigin).GetPoweredLength(); if(dist < 130.f * 130.f) { @@ -1083,7 +1083,7 @@ namespace spades { if(model){ Vector3 origin; origin = muzzle - p->GetFront() * 0.5f; - + Vector3 vel; vel = p->GetFront() * 0.5f + p->GetRight() + p->GetUp() * 0.2f; @@ -1097,17 +1097,17 @@ namespace spades { default: break; } - + ILocalEntity *ent; ent = new GunCasing(client, model, snd, snd2, origin, p->GetFront(), vel); client->AddLocalEntity(ent); - + } } } - + asIScriptObject *skin; // FIXME: what if current tool isn't weapon? if(ShouldRenderInThirdPersonView()){ @@ -1115,14 +1115,14 @@ namespace spades { }else{ skin = weaponViewSkin; } - + { ScriptIWeaponSkin interface(skin); interface.WeaponFired(); } - + } - + void ClientPlayer::ReloadingWeapon() { asIScriptObject *skin; // FIXME: what if current tool isn't weapon? @@ -1131,13 +1131,13 @@ namespace spades { }else{ skin = weaponViewSkin; } - + { ScriptIWeaponSkin interface(skin); interface.ReloadingWeapon(); } } - + void ClientPlayer::ReloadedWeapon() { asIScriptObject *skin; // FIXME: what if current tool isn't weapon? diff --git a/Sources/Client/Client_Input.cpp b/Sources/Client/Client_Input.cpp index 72721787..bcc26892 100644 --- a/Sources/Client/Client_Input.cpp +++ b/Sources/Client/Client_Input.cpp @@ -1,22 +1,22 @@ /* Copyright (c) 2013 yvt based on code of pysnip (c) Mathias Kaerlev 2011-2012. - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "Client.h" @@ -90,18 +90,18 @@ DEFINE_SPADES_SETTING(cg_keyAutoFocus, "MiddleMouseButton"); namespace spades { namespace client { - + bool Client::WantsToBeClosed() { return readyToClose; } - + bool FirstPersonSpectate = false; - + void Client::Closing() { SPADES_MARK_FUNCTION(); } - + bool Client::NeedsAbsoluteMouseCoordinate() { SPADES_MARK_FUNCTION(); if(scriptedUI->NeedsInput()) { @@ -116,20 +116,20 @@ namespace spades { } return false; } - + void Client::MouseEvent(float x, float y) { SPADES_MARK_FUNCTION(); - + if(scriptedUI->NeedsInput()) { scriptedUI->MouseEvent(x, y); return; } - + if(IsLimboViewActive()){ limbo->MouseEvent(x, y); return; } - + if(IsFollowing()){ SPAssert(world != nullptr); /* @@ -140,11 +140,11 @@ namespace spades { x = -x; y = -y; } */ - + x = -x; if (!cg_invertMouseY) y = -y; - + followYaw -= x * 0.003f; followPitch -= y * 0.003f; if(followPitch < -M_PI*.45f) followPitch = -static_cast(M_PI)*.45f; @@ -156,7 +156,7 @@ namespace spades { if(p->IsAlive()){ x /= GetAimDownZoomScale(); y /= GetAimDownZoomScale(); - + float rad = x * x + y * y; if(rad > 0.f) { if((float)cg_mouseExpPower < 0.001f || @@ -168,40 +168,40 @@ namespace spades { factor *= factor; rad /= factor; rad = powf(rad, (float)cg_mouseExpPower * 0.5f - 0.5f); - + // shouldn't happen... if(isnan(rad)) rad = 1.f; - + x *= rad; y *= rad; } - + if(aimDownState > 0.f) { float scale = cg_zoomedMouseSensScale; scale = powf(scale, aimDownState); x *= scale; y *= scale; } - + x *= (float)cg_mouseSensitivity; y *= (float)cg_mouseSensitivity; - + if(cg_invertMouseY) y = -y; - + p->Turn(x * 0.003f, y * 0.003f); } } } - + void Client::WheelEvent(float x, float y) { SPADES_MARK_FUNCTION(); - + if(scriptedUI->NeedsInput()) { scriptedUI->WheelEvent(x, y); return; } - + if(y > .5f) { KeyEvent("WheelDown", true); KeyEvent("WheelDown", false); @@ -210,37 +210,37 @@ namespace spades { KeyEvent("WheelUp", false); } } - + void Client::TextInputEvent(const std::string &ch){ SPADES_MARK_FUNCTION(); - + if (scriptedUI->NeedsInput() && !scriptedUI->isIgnored(ch)) { scriptedUI->TextInputEvent(ch); return; } - + // we don't get "/" here anymore } - + void Client::TextEditingEvent(const std::string &ch, int start, int len) { SPADES_MARK_FUNCTION(); - + if (scriptedUI->NeedsInput() && !scriptedUI->isIgnored(ch)) { scriptedUI->TextEditingEvent(ch, start, len); return; } } - + bool Client::AcceptsTextInput() { SPADES_MARK_FUNCTION(); - + if(scriptedUI->NeedsInput()) { return scriptedUI->AcceptsTextInput(); } return false; } - + AABB2 Client::GetTextInputRect() { SPADES_MARK_FUNCTION(); if(scriptedUI->NeedsInput()) { @@ -248,7 +248,7 @@ namespace spades { } return AABB2(); } - + static bool CheckKey(const std::string& cfg, const std::string& input) { if(cfg.empty()) @@ -272,10 +272,10 @@ namespace spades { } return false; } - + void Client::KeyEvent(const std::string& name, bool down){ SPADES_MARK_FUNCTION(); - + if(scriptedUI->NeedsInput()) { if(!scriptedUI->isIgnored(name)) { scriptedUI->KeyEvent(name, down); @@ -286,7 +286,7 @@ namespace spades { } return; } - + if(name == "Escape"){ if(down){ if(inGameLimbo){ @@ -332,13 +332,13 @@ namespace spades { } if(world->GetLocalPlayer()){ Player *p = world->GetLocalPlayer(); - + if(p->IsAlive() && p->GetTool() == Player::ToolBlock && down) { if(paletteView->KeyInput(name)){ return; } } - + if(cg_debugCorpse){ if(name == "p" && down){ Corpse *corp; @@ -346,7 +346,7 @@ namespace spades { corp = new Corpse(renderer, map, victim); corp->AddImpulse(victim->GetFront() * 32.f); corpses.emplace_back(corp); - + if(corpses.size() > corpseHardLimit){ corpses.pop_front(); }else if(corpses.size() > corpseSoftLimit){ @@ -412,14 +412,14 @@ namespace spades { (!w->IsReloading()) && world->GetLocalPlayer()->GetTool() == Player::ToolWeapon){ if(world->GetLocalPlayer()->IsToolWeapon()){ - if(weapInput.secondary) { - // if we send WeaponInput after sending Reload, - // server might cancel the reload. - // https://github.com/infogulch/pyspades/blob/895879ed14ddee47bb278a77be86d62c7580f8b7/pyspades/server.py#343 - hasDelayedReload = true; - weapInput.secondary = false; - return; - } + if(weapInput.secondary) { + // if we send WeaponInput after sending Reload, + // server might cancel the reload. + // https://github.com/infogulch/pyspades/blob/895879ed14ddee47bb278a77be86d62c7580f8b7/pyspades/server.py#343 + hasDelayedReload = true; + weapInput.secondary = false; + return; + } } world->GetLocalPlayer()->Reload(); net->SendReload(); @@ -590,8 +590,8 @@ namespace spades { } } } - - + + } } diff --git a/Sources/Client/Client_LocalEnts.cpp b/Sources/Client/Client_LocalEnts.cpp index 4306c55b..16a4184c 100644 --- a/Sources/Client/Client_LocalEnts.cpp +++ b/Sources/Client/Client_LocalEnts.cpp @@ -1,22 +1,22 @@ /* Copyright (c) 2013 yvt based on code of pysnip (c) Mathias Kaerlev 2011-2012. - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "Client.h" @@ -60,28 +60,28 @@ DEFINE_SPADES_SETTING(cg_autoFocusSpeed, "0.4"); namespace spades { namespace client { - - + + #pragma mark - Local Entities / Effects - - + + void Client::RemoveAllCorpses(){ SPADES_MARK_FUNCTION(); - + corpses.clear(); lastMyCorpse = nullptr; } - - + + void Client::RemoveAllLocalEntities(){ SPADES_MARK_FUNCTION(); - + localEntities.clear(); } - + void Client::RemoveInvisibleCorpses(){ SPADES_MARK_FUNCTION(); - + decltype(corpses)::iterator it; std::vector its; int cnt = (int)corpses.size() - corpseSoftLimit; @@ -96,13 +96,13 @@ namespace spades { } cnt--; } - + for(size_t i = 0; i < its.size(); i++) corpses.erase(its[i]); - + } - - + + Player *Client::HotTrackedPlayer( hitTag_t* hitFlag ){ if(!world) return nullptr; @@ -114,10 +114,10 @@ namespace spades { Vector3 origin = p->GetEye(); Vector3 dir = p->GetFront(); World::WeaponRayCastResult result = world->WeaponRayCast(origin, dir, p); - + if(result.hit == false || result.player == nullptr) return nullptr; - + // don't hot track enemies (non-spectator only) if(result.player->GetTeamId() != p->GetTeamId() && p->GetTeamId() < 2) @@ -127,27 +127,27 @@ namespace spades { } return result.player; } - + bool Client::IsMuted() { // prevent to play loud sound at connection // caused by saved packets return time < worldSetTime + .05f; } - + void Client::Bleed(spades::Vector3 v){ SPADES_MARK_FUNCTION(); - + if(!cg_blood) return; - + // distance cull if((v - lastSceneDef.viewOrigin).GetPoweredLength() > 150.f * 150.f) return; - - if ((int)cg_particles < 1) - return; - + + if ((int)cg_particles < 1) + return; + Handle img = renderer->RegisterImage("Gfx/White.tga"); Vector4 color = {0.5f, 0.02f, 0.04f, 1.f}; for(int i = 0; i < 10; i++){ @@ -162,11 +162,11 @@ namespace spades { ent->SetRadius(0.1f + GetRandom()*GetRandom()*0.2f); ent->SetLifeTime(3.f, 0.f, 1.f); localEntities.emplace_back(ent); - } - - if((int) cg_particles < 2) - return; - + } + + if((int) cg_particles < 2) + return; + color = MakeVector4(.7f, .35f, .37f, .6f); for(int i = 0; i < 2; i++){ ParticleSpriteEntity *ent = @@ -184,7 +184,7 @@ namespace spades { ent->SetLifeTime(.20f + GetRandom() * .2f, 0.06f, .20f); localEntities.emplace_back(ent); } - + color.w *= .1f; for(int i = 0; i < 1; i++){ ParticleSpriteEntity *ent = @@ -203,20 +203,20 @@ namespace spades { localEntities.emplace_back(ent); } } - + void Client::EmitBlockFragments(Vector3 origin, IntVector3 c){ SPADES_MARK_FUNCTION(); - + // distance cull float distPowered = (origin - lastSceneDef.viewOrigin).GetPoweredLength(); if(distPowered > 150.f * 150.f) return; - - if ((int)cg_particles < 1) - return; - + + if ((int)cg_particles < 1) + return; + Handle img = renderer->RegisterImage("Gfx/White.tga"); Vector4 color = {c.x / 255.f, c.y / 255.f, c.z / 255.f, 1.f}; @@ -235,10 +235,10 @@ namespace spades { ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak); localEntities.emplace_back(ent); } - - if ((int)cg_particles < 2) - return; - + + if ((int)cg_particles < 2) + return; + if(distPowered < 32.f * 32.f){ for(int i = 0; i < 16; i++){ @@ -257,7 +257,7 @@ namespace spades { localEntities.emplace_back(ent); } } - + color += (MakeVector4(1, 1, 1, 1) - color) * .2f; color.w *= .2f; for(int i = 0; i < 2; i++){ @@ -275,23 +275,23 @@ namespace spades { ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); localEntities.emplace_back(ent); } - + } - + void Client::EmitBlockDestroyFragments(IntVector3 blk, IntVector3 c){ SPADES_MARK_FUNCTION(); - + Vector3 origin = {blk.x + .5f, blk.y + .5f, blk.z + .5f}; - + // distance cull if((origin - lastSceneDef.viewOrigin).GetPoweredLength() > 150.f * 150.f) return; - - if ((int)cg_particles < 1) - return; - + + if ((int)cg_particles < 1) + return; + Handle img = renderer->RegisterImage("Gfx/White.tga"); Vector4 color = {c.x / 255.f, c.y / 255.f, c.z / 255.f, 1.f}; @@ -310,7 +310,7 @@ namespace spades { localEntities.emplace_back(ent); } } - + void Client::MuzzleFire(spades::Vector3 origin, spades::Vector3 dir, bool local) { @@ -320,14 +320,14 @@ namespace spades { l.type = DynamicLightTypePoint; l.color = MakeVector3(3.f, 1.6f, 0.5f); flashDlights.push_back(l); - - if ((int)cg_particles < 1) - return; - + + if ((int)cg_particles < 1) + return; + Vector4 color; Vector3 velBias = {0, 0, -0.5f}; color = MakeVector4( .8f, .8f, .8f, .3f); - + // rapid smoke for(int i = 0; i < 2; i++){ ParticleSpriteEntity *ent = @@ -346,7 +346,7 @@ namespace spades { localEntities.emplace_back(ent); } } - + void Client::GrenadeExplosion(spades::Vector3 origin){ float dist = (origin - lastSceneDef.viewOrigin).GetLength(); if(dist > 170.f) @@ -354,7 +354,7 @@ namespace spades { grenadeVibration += 2.f / (dist + 5.f); if(grenadeVibration > 1.f) grenadeVibration = 1.f; - + DynamicLightParam l; l.origin = origin; l.radius = 16.f; @@ -362,10 +362,10 @@ namespace spades { l.color = MakeVector3(3.f, 1.6f, 0.5f); l.useLensFlare = true; flashDlights.push_back(l); - - if ((int)cg_particles < 1) - return; - + + if ((int)cg_particles < 1) + return; + Vector3 velBias = {0,0,0}; if(!map->ClipBox(origin.x, origin.y, origin.z)){ if(map->ClipBox(origin.x + 1.f, origin.y, origin.z)){ @@ -387,7 +387,7 @@ namespace spades { velBias.z += 1.f; } } - + Vector4 color; color = MakeVector4( .6f, .6f, .6f, 1.f); // rapid smoke @@ -407,7 +407,7 @@ namespace spades { ent->SetLifeTime(1.8f + GetRandom()*0.1f, 0.f, .20f); localEntities.emplace_back(ent); } - + // slow smoke color.w = .25f; for(int i = 0; i < 8; i++){ @@ -422,21 +422,21 @@ namespace spades { ent->SetRadius(1.5f + GetRandom()*GetRandom()*0.8f, 0.2f); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); - switch ((int) cg_particles) { - case 1: - ent->SetLifeTime(0.8f + GetRandom() * 1.f, 0.1f, 8.f); - break; - case 2: - ent->SetLifeTime(1.5f + GetRandom() * 2.f, 0.1f, 8.f); - break; - case 3: - default: - ent->SetLifeTime(2.f + GetRandom() * 5.f, 0.1f, 8.f); - break; - } + switch ((int) cg_particles) { + case 1: + ent->SetLifeTime(0.8f + GetRandom() * 1.f, 0.1f, 8.f); + break; + case 2: + ent->SetLifeTime(1.5f + GetRandom() * 2.f, 0.1f, 8.f); + break; + case 3: + default: + ent->SetLifeTime(2.f + GetRandom() * 5.f, 0.1f, 8.f); + break; + } localEntities.emplace_back(ent); } - + // fragments Handle img = renderer->RegisterImage("Gfx/White.tga"); color = MakeVector4(0.01, 0.03, 0, 1.f); @@ -457,7 +457,7 @@ namespace spades { ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak); localEntities.emplace_back(ent); } - + // fire smoke color= MakeVector4(1.f, .7f, .4f, .2f) * 5.f; for(int i = 0; i < 4; i++){ @@ -478,7 +478,7 @@ namespace spades { localEntities.emplace_back(ent); } } - + void Client::GrenadeExplosionUnderwater(spades::Vector3 origin){ float dist = (origin - lastSceneDef.viewOrigin).GetLength(); if(dist > 170.f) @@ -486,18 +486,18 @@ namespace spades { grenadeVibration += 1.5f / (dist + 5.f); if(grenadeVibration > 1.f) grenadeVibration = 1.f; - - if((int) cg_particles < 1) - return; - + + if((int) cg_particles < 1) + return; + Vector3 velBias = {0,0,0}; - + Vector4 color; color = MakeVector4( .95f, .95f, .95f, .6f); // water1 - Handle img = renderer->RegisterImage("Textures/WaterExpl.png"); - if((int) cg_particles < 2) - color.w = .3f; + Handle img = renderer->RegisterImage("Textures/WaterExpl.png"); + if((int) cg_particles < 2) + color.w = .3f; for(int i = 0; i < 7; i++){ ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); @@ -513,12 +513,12 @@ namespace spades { ent->SetLifeTime(3.f + GetRandom()*0.3f, 0.f, .60f); localEntities.emplace_back(ent); } - + // water2 img = renderer->RegisterImage("Textures/Fluid.png"); color.w = .9f; if((int) cg_particles < 2) - color.w = .4f; + color.w = .4f; for(int i = 0; i < 16; i++){ ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); @@ -534,11 +534,11 @@ namespace spades { ent->SetLifeTime(3.f + GetRandom()*0.3f, .7f, .60f); localEntities.emplace_back(ent); } - + // slow smoke - color.w = .4f; - if((int) cg_particles < 2) - color.w = .2f; + color.w = .4f; + if((int) cg_particles < 2) + color.w = .2f; for(int i = 0; i < 8; i++){ ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 20.f); @@ -551,20 +551,20 @@ namespace spades { ent->SetRadius(1.4f + GetRandom()*GetRandom()*0.8f, 0.2f); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); - switch ((int)cg_particles) { - case 1: - ent->SetLifeTime(3.f + GetRandom() * 5.f, 0.1f, 8.f); - break; - case 2: - case 3: - default: - ent->SetLifeTime(6.f + GetRandom() * 5.f, 0.1f, 8.f); - break; - - } + switch ((int)cg_particles) { + case 1: + ent->SetLifeTime(3.f + GetRandom() * 5.f, 0.1f, 8.f); + break; + case 2: + case 3: + default: + ent->SetLifeTime(6.f + GetRandom() * 5.f, 0.1f, 8.f); + break; + + } localEntities.emplace_back(ent); } - + // fragments img = renderer->RegisterImage("Gfx/White.tga"); color = MakeVector4(1,1,1, 0.7f); @@ -586,22 +586,22 @@ namespace spades { ent->SetBlockHitAction(ParticleSpriteEntity::Delete); localEntities.emplace_back(ent); } - - + + // TODO: wave? } - - + + void Client::BulletHitWaterSurface(spades::Vector3 origin){ float dist = (origin - lastSceneDef.viewOrigin).GetLength(); if(dist > 150.f) return; if(!cg_waterImpact) return; - - if((int) cg_particles < 1) - return; - + + if((int) cg_particles < 1) + return; + Vector4 color; color = MakeVector4( .95f, .95f, .95f, .3f); // water1 @@ -622,7 +622,7 @@ namespace spades { ent->SetLifeTime(3.f + GetRandom()*0.3f, 0.1f, .60f); localEntities.emplace_back(ent); } - + // water2 img = renderer->RegisterImage("Textures/Fluid.png"); color.w = .9f; @@ -642,8 +642,8 @@ namespace spades { ent->SetLifeTime(3.f + GetRandom()*0.3f, GetRandom() * 0.3f, .60f); localEntities.emplace_back(ent); } - - + + // fragments img = renderer->RegisterImage("Gfx/White.tga"); color = MakeVector4(1,1,1, 0.7f); @@ -664,13 +664,13 @@ namespace spades { ent->SetBlockHitAction(ParticleSpriteEntity::Delete); localEntities.emplace_back(ent); } - - + + // TODO: wave? } - + #pragma mark - Camera Control - + enum { AutoFocusPoints = 4 }; void Client::UpdateAutoFocus(float dt) { if (autoFocusEnabled && world && (int)cg_manualFocus) { @@ -681,7 +681,7 @@ namespace spades { const Vector3 camDir = lastSceneDef.viewAxis[2].Normalize(); const Vector3 camX = lastSceneDef.viewAxis[0].Normalize() * measureRange; const Vector3 camY = lastSceneDef.viewAxis[1].Normalize() * measureRange; - + float distances[AutoFocusPoints * AutoFocusPoints]; std::size_t numValidDistances = 0; Vector3 camDir1 = camDir - camX - camY; @@ -691,43 +691,43 @@ namespace spades { Vector3 camDir2 = camDir1; for (int y = 0; y < AutoFocusPoints; ++y) { float dist = RayCastForAutoFocus(camOrigin, camDir2); - + dist *= lenScale; - + if (std::isfinite(dist) && dist > 0.8f) { distances[numValidDistances++] = dist; } - + camDir2 += camDY; } camDir1 += camDX; } - + if (numValidDistances > 0) { // Take median std::sort(distances, distances + numValidDistances); - + float dist = (numValidDistances & 1) ? distances[numValidDistances >> 1] : (distances[numValidDistances >> 1] + distances[(numValidDistances >> 1) - 1]) * 0.5f; - + targetFocalLength = dist; - + } } - + // Change the actual focal length slowly { float dist = 1.f / targetFocalLength; float curDist = 1.f / focalLength; const float maxSpeed = cg_autoFocusSpeed; - + if (dist > curDist) { curDist = std::min(dist, curDist + maxSpeed * dt); } else { curDist = std::max(dist, curDist - maxSpeed * dt); } - + focalLength = 1.f / curDist; } } @@ -735,7 +735,7 @@ namespace spades { const Vector3 &direction) { SPAssert(world); - + const auto &lastSceneDef = this->lastSceneDef; World::WeaponRayCastResult result = world->WeaponRayCast(origin, @@ -744,7 +744,7 @@ namespace spades { if (result.hit) { return Vector3::Dot(result.hitPos - origin, lastSceneDef.viewAxis[2]); } - + return std::nan(nullptr); } diff --git a/Sources/Client/Client_Scene.cpp b/Sources/Client/Client_Scene.cpp index 6a852b0c..feb07ff4 100644 --- a/Sources/Client/Client_Scene.cpp +++ b/Sources/Client/Client_Scene.cpp @@ -1,22 +1,22 @@ /* Copyright (c) 2013 yvt based on code of pysnip (c) Mathias Kaerlev 2011-2012. - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "Client.h" @@ -53,9 +53,9 @@ static float nextRandom() { namespace spades { namespace client { - + #pragma mark - Drawing - + bool Client::ShouldRenderInThirdPersonView() { if(world && world->GetLocalPlayer()){ if(!world->GetLocalPlayer()->IsAlive()) @@ -66,7 +66,7 @@ namespace spades { } return false; } - + float Client::GetLocalFireVibration() { float localFireVibration = 0.f; localFireVibration = time - localFireVibrationTime; @@ -75,7 +75,7 @@ namespace spades { localFireVibration = 0.f; return localFireVibration; } - + float Client::GetAimDownZoomScale(){ if(world == nullptr || world->GetLocalPlayer() == nullptr || @@ -97,27 +97,27 @@ namespace spades { float aimDownState = GetAimDownState(); return 1.f + powf(aimDownState, 5.f) * delta; } - + SceneDefinition Client::CreateSceneDefinition() { SPADES_MARK_FUNCTION(); - - int shakeLevel = cg_shake; - + + int shakeLevel = cg_shake; + SceneDefinition def; def.time = (unsigned int)(time * 1000.f); - def.denyCameraBlur = true; - def.zFar = 200.f; - + def.denyCameraBlur = true; + def.zFar = 200.f; + if(world){ IntVector3 fogColor = world->GetFogColor(); renderer->SetFogColor(MakeVector3(fogColor.x / 255.f, fogColor.y / 255.f, fogColor.z / 255.f)); - + Player *player = world->GetLocalPlayer(); - + def.blurVignette = .0f; - + if(IsFollowing()){ int limit = 100; // if current following player has left, @@ -133,7 +133,7 @@ namespace spades { player = world->GetPlayer(followingPlayerId); } if(player){ - + float roll = 0.f; float scale = 1.f; float vibPitch = 0.f; @@ -143,7 +143,7 @@ namespace spades { Vector3 center = player->GetEye(); Vector3 playerFront = player->GetFront2D(); Vector3 up = MakeVector3(0,0,-1); - + if((!player->IsAlive()) && lastMyCorpse && player == world->GetLocalPlayer()){ center = lastMyCorpse->GetCenter(); @@ -163,7 +163,7 @@ namespace spades { } } } - + float distance = 5.f; if(player == world->GetLocalPlayer() && world->GetLocalPlayer()->GetTeamId() < 2 && @@ -172,14 +172,14 @@ namespace spades { float elapsedTime = time - lastAliveTime; distance -= 3.f * expf(-elapsedTime * 1.f); } - + Vector3 eye = center; //eye -= playerFront * 5.f; //eye += up * 2.0f; eye.x += cosf(followYaw) * cosf(followPitch) * distance; eye.y += sinf(followYaw) * cosf(followPitch) * distance; eye.z -= sinf(followPitch) * distance; - + if(false){ // settings for making limbo stuff eye = center; @@ -188,7 +188,7 @@ namespace spades { eye += player->GetRight() *2.f; scale *= .6f; } - + // try ray casting GameMap::RayCastResult result; result = map->CastRay2(center, (eye - center).Normalize(), 256); @@ -201,10 +201,10 @@ namespace spades { eye += (center - eye).Normalize() * diff; } } - + Vector3 front = center - eye; front = front.Normalize(); - + if(FirstPersonSpectate == false){ def.viewOrigin = eye; def.viewAxis[0] = -Vector3::Cross(up, front).Normalize(); @@ -216,100 +216,100 @@ namespace spades { def.viewAxis[1] = player->GetUp(); def.viewAxis[2] = player->GetFront(); } - + def.fovY = (float)cg_fov * static_cast(M_PI) /180.f; def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() / renderer->ScreenHeight()) * 2.f; - + // 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); - + }else if(player->GetTeamId() >= 2){ // spectator view (noclip view) Vector3 center = followPos; Vector3 front; Vector3 up = {0, 0, -1}; - + front.x = -cosf(followYaw) * cosf(followPitch); front.y = -sinf(followYaw) * cosf(followPitch); front.z = sinf(followPitch); - + 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; - + def.fovY = (float)cg_fov * static_cast(M_PI) /180.f; def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() / renderer->ScreenHeight()) * 2.f; - + // for 1st view, camera blur can be used def.denyCameraBlur = false; - + }else{ Vector3 front = player->GetFront(); Vector3 right = player->GetRight(); Vector3 up = player->GetUp(); - - if (shakeLevel >= 1) { - float localFireVibration = GetLocalFireVibration(); - localFireVibration *= localFireVibration; - - if(player->GetTool() == Player::ToolSpade) { - 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(M_PI) * 2.f) * 0.01f * sp; - roll -= sinf(player->GetWalkAnimationProgress() * static_cast(M_PI) * 2.f) * 0.005f * (sp); - float p = cosf(player->GetWalkAnimationProgress() * static_cast(M_PI) * 2.f); - p = p * p; p *= p; p *= p; p *= p; - vibPitch += p * 0.01f * sp; - } - } - + + if (shakeLevel >= 1) { + float localFireVibration = GetLocalFireVibration(); + localFireVibration *= localFireVibration; + + if(player->GetTool() == Player::ToolSpade) { + 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(M_PI) * 2.f) * 0.01f * sp; + roll -= sinf(player->GetWalkAnimationProgress() * static_cast(M_PI) * 2.f) * 0.005f * (sp); + float p = cosf(player->GetWalkAnimationProgress() * static_cast(M_PI) * 2.f); + p = p * p; p *= p; p *= p; p *= p; + vibPitch += p * 0.01f * sp; + } + } + scale /= GetAimDownZoomScale(); - + def.viewOrigin = player->GetEye(); def.viewAxis[0] = right; def.viewAxis[1] = up; def.viewAxis[2] = front; - + def.fovY = (float)cg_fov * static_cast(M_PI) /180.f; def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() / renderer->ScreenHeight()) * 2.f; - + // for 1st view, camera blur can be used def.denyCameraBlur = false; - + float aimDownState = GetAimDownState(); float per = aimDownState; per *= per * per; def.depthOfFieldFocalLength = per * 13.f + .054f; - + def.blurVignette = .0f; - - - + + + } - + // add vibration for both 1st/3rd view { // add grenade vibration @@ -322,100 +322,100 @@ namespace spades { vibPitch += (nextRandom() - nextRandom()) * 0.1f * grenVib; vibYaw += (nextRandom() - nextRandom()) * 0.1f * grenVib; scale -= (nextRandom()-nextRandom()) * 0.1f * grenVib; - + def.radialBlur += grenVib * 0.8f; } } - + // add roll / scale { Vector3 right = def.viewAxis[0]; Vector3 up = def.viewAxis[1]; - + def.viewAxis[0] = right * cosf(roll) - up * sinf(roll); def.viewAxis[1] = up * cosf(roll) + right * sinf(roll); - - def.fovX = atanf(tanf(def.fovX * .5f) * scale) * 2.f; - def.fovY = atanf(tanf(def.fovY * .5f) * scale) * 2.f; + + def.fovX = atanf(tanf(def.fovX * .5f) * scale) * 2.f; + def.fovY = atanf(tanf(def.fovY * .5f) * scale) * 2.f; } { Vector3 u = def.viewAxis[1]; Vector3 v = def.viewAxis[2]; - + 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]; - + 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){ + wTime >= lastHurtTime){ 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){ + wTime >= lastHurtTime){ 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); } } - + def.zNear = 0.05f; - + def.skipWorld = false; }else{ 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); - + def.fovY = (float)cg_fov * static_cast(M_PI) /180.f; def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() / renderer->ScreenHeight()) * 2.f; - + def.zNear = 0.05f; - + def.skipWorld = false; } - + }else{ 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); - + def.fovY = (float)cg_fov * static_cast(M_PI) /180.f; def.fovX = atanf(tanf(def.fovY * .5f) * renderer->ScreenWidth() / renderer->ScreenHeight()) * 2.f; - + def.zNear = 0.05f; - + def.skipWorld = true; - + renderer->SetFogColor(MakeVector3(0,0,0)); } - - if (def.viewOrigin.z < 0.f) { - // Need to move the far plane because there's no vertical fog - def.zFar -= def.viewOrigin.z; - } - + + if (def.viewOrigin.z < 0.f) { + // Need to move the far plane because there's no vertical fog + def.zFar -= def.viewOrigin.z; + } + SPAssert(!isnan(def.viewOrigin.x)); SPAssert(!isnan(def.viewOrigin.y)); SPAssert(!isnan(def.viewOrigin.z)); - + def.radialBlur = std::min(def.radialBlur, 1.f); - + if ((int)cg_manualFocus) { // Depth of field is manually controlled def.depthOfFieldNearBlurStrength = def.depthOfFieldFarBlurStrength = @@ -425,29 +425,29 @@ namespace spades { def.depthOfFieldNearBlurStrength = cg_depthOfFieldAmount; def.depthOfFieldFarBlurStrength = 0.f; } - + return def; } - + void Client::AddGrenadeToScene(spades::client::Grenade *g) { SPADES_MARK_FUNCTION(); - + IModel *model; model = renderer->RegisterModel("Models/Weapons/Grenade/Grenade.kv6"); - + if(g->GetPosition().z > 63.f) { // work-around for water refraction problem return; } - + ModelRenderParam param; Matrix4 mat = Matrix4::Scale(0.03f); mat = Matrix4::Translate(g->GetPosition()) * mat; param.matrix = mat; - + renderer->RenderModel(model, param); } - + void Client::AddDebugObjectToScene(const spades::OBB3 &obb, const Vector4& color) { const Matrix4& mat = obb.m; Vector3 v[2][2][2]; @@ -459,23 +459,23 @@ namespace spades { 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(); - + 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); - + 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); - + 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); } - + void Client::DrawCTFObjects() { SPADES_MARK_FUNCTION(); CTFGameMode *mode = static_cast(world->GetMode()); @@ -488,15 +488,15 @@ namespace spades { Vector3 color = { col.x / 255.f, col.y / 255.f, col.z / 255.f }; - + ModelRenderParam param; param.customColor = color; - + // draw base param.matrix = Matrix4::Translate(team.basePos); param.matrix = param.matrix * Matrix4::Scale(.3f); renderer->RenderModel(base, param); - + // draw flag if(!mode->GetTeam(1-tId).hasIntel){ param.matrix = Matrix4::Translate(team.flagPos); @@ -505,7 +505,7 @@ namespace spades { } } } - + void Client::DrawTCObjects() { SPADES_MARK_FUNCTION(); TCGameMode *mode = static_cast(world->GetMode()); @@ -523,26 +523,26 @@ namespace spades { Vector3 color = { col.x / 255.f, col.y / 255.f, col.z / 255.f }; - + ModelRenderParam param; param.customColor = color; - + // draw base param.matrix = Matrix4::Translate(t->pos); param.matrix = param.matrix * Matrix4::Scale(.3f); renderer->RenderModel(base, param); - + } } - + void Client::DrawScene(){ SPADES_MARK_FUNCTION(); - + renderer->StartScene(lastSceneDef); - + if(world){ Player *p = world->GetLocalPlayer(); - + for(size_t i = 0; i < world->GetNumPlayerSlots(); i++) if(world->GetPlayer(static_cast(i))){ SPAssert(clientPlayers[i]); @@ -552,7 +552,7 @@ namespace spades { for(size_t i = 0; i < nades.size(); i++){ AddGrenadeToScene(nades[i]); } - + { for(auto& c: corpses){ Vector3 center = c->GetCenter(); @@ -561,19 +561,19 @@ namespace spades { c->AddToScene(); } } - + if( IGameMode::m_CTF == world->GetMode()->ModeType() ){ DrawCTFObjects(); } else if( IGameMode::m_TC == world->GetMode()->ModeType() ){ DrawTCObjects(); } - + { for(auto& ent: localEntities){ ent->Render3D(); } } - + // draw block cursor // FIXME: don't use debug line if(p){ @@ -589,9 +589,9 @@ namespace spades { }else{ blocks.push_back(p->GetBlockCursorPos()); } - + bool active = p->IsBlockCursorActive(); - + Vector4 color = {1,1,1,1}; if(!active) color = Vector4(1,1,0,1); @@ -599,12 +599,12 @@ namespace spades { color = MakeVector4(1,0,0,1); if(!active) color.w *= 0.5f; - + for(size_t i = 0; i < blocks.size(); i++){ IntVector3& v = blocks[i]; - + if(active) { - + renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z), MakeVector3(v.x+1, v.y, v.z), color); @@ -620,7 +620,7 @@ namespace spades { 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, v.z), MakeVector3(v.x, v.y+1, v.z), color); @@ -633,7 +633,7 @@ namespace spades { renderer->AddDebugLine(MakeVector3(v.x+1, v.y, v.z+1), MakeVector3(v.x+1, v.y+1, v.z+1), color); - + renderer->AddDebugLine(MakeVector3(v.x, v.y, v.z), MakeVector3(v.x, v.y, v.z+1), color); @@ -648,7 +648,7 @@ namespace spades { color); }else{ // not active - + const float ln = 0.1f; { float xx = v.x, yy = v.y, zz = v.z; @@ -698,20 +698,20 @@ namespace spades { renderer->AddDebugLine(Vector3(xx, yy, zz), Vector3(xx, yy-ln, zz), color); renderer->AddDebugLine(Vector3(xx, yy, zz), Vector3(xx, yy, zz-ln), color); } - + } // --- one block drawn } // end for - + } // p->IsReadyToUseTool } } - + for(size_t i = 0; i < flashDlights.size(); i++) renderer->AddLight(flashDlights[i]); flashDlightsOld.clear(); flashDlightsOld.swap(flashDlights); - + // draw player hottrack // FIXME: don't use debug line { @@ -721,7 +721,7 @@ namespace spades { 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); - + Player::HitBoxes hb = hottracked->GetHitBoxes(); AddDebugObjectToScene(hb.head, (tag & hit_Head) ? color2 : color ); AddDebugObjectToScene(hb.torso, (tag & hit_Torso) ? color2 : color ); @@ -730,29 +730,29 @@ namespace spades { AddDebugObjectToScene(hb.limbs[2], (tag & hit_Arms) ? color2 : color ); } } - + renderer->EndScene(); } - + Vector3 Client::Project(spades::Vector3 v){ v -= lastSceneDef.viewOrigin; - + // 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]); - + float tanX = tanf(lastSceneDef.fovX * .5f); float tanY = tanf(lastSceneDef.fovY * .5f); - + v2.x /= tanX * v2.z; v2.y /= tanY * v2.z; - + // 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(); - + return v2; } diff --git a/Sources/Client/Corpse.cpp b/Sources/Client/Corpse.cpp index 0c9ae0f6..3cc57213 100644 --- a/Sources/Client/Corpse.cpp +++ b/Sources/Client/Corpse.cpp @@ -1,21 +1,21 @@ /* Copyright (c) 2013 yvt - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "Corpse.h" @@ -38,29 +38,29 @@ namespace spades { Player *p): renderer(renderer), map(map) { SPADES_MARK_FUNCTION(); - + IntVector3 col = p->GetWorld()->GetTeam(p->GetTeamId()).color; color = MakeVector3(col.x / 255.f, col.y / 255.f, col.z / 255.f); - + bool crouch = p->GetInput().crouch; Vector3 front = p->GetFront(); - + float yaw = atan2(front.y, front.x) + static_cast(M_PI) * .5f; //float pitch = -atan2(front.z, sqrt(front.x * front.x + front.y * front.y)); - + // lower axis Matrix4 lower = Matrix4::Translate(p->GetOrigin()); lower = lower * Matrix4::Rotate(MakeVector3(0,0,1), yaw); - + Matrix4 torso; - + if(crouch){ lower = lower * Matrix4::Translate(0, 0, -0.4f); torso = lower * Matrix4::Translate(0, 0, -0.3f); - + SetNode(Torso1, torso*MakeVector3(0.4f, -.15f, 0.1f)); SetNode(Torso2, @@ -69,20 +69,20 @@ namespace spades { torso*MakeVector3(-0.4f, .8f, 0.7f)); SetNode(Torso4, torso*MakeVector3(0.4f, .8f, 0.7f)); - + SetNode(Leg1, lower*MakeVector3(-0.4f, .1f, 1.f)); SetNode(Leg2, lower*MakeVector3(0.4f, .1f, 1.f)); - + SetNode(Arm1, torso*MakeVector3(0.2f, -.4f, .2f)); SetNode(Arm2, torso*MakeVector3(-0.2f, -.4f, .2f)); - + }else{ torso = lower * Matrix4::Translate(0, 0, -1.1f); - + SetNode(Torso1, torso*MakeVector3(0.4f, 0.f, 0.1f)); SetNode(Torso2, @@ -91,29 +91,29 @@ namespace spades { torso*MakeVector3(-0.4f, .0f, 1.f)); SetNode(Torso4, torso*MakeVector3(0.4f, .0f, 1.f)); - + SetNode(Leg1, lower*MakeVector3(-0.4f, .0f, 1.f)); SetNode(Leg2, lower*MakeVector3(0.4f, .0f, 1.f)); - + SetNode(Arm1, torso*MakeVector3(0.2f, -.4f, .2f)); SetNode(Arm2, torso*MakeVector3(-0.2f, -.4f, .2f)); - + } - + SetNode(Head, (nodes[Torso1].pos + nodes[Torso2].pos) * .5f + MakeVector3(0,0,-0.6f)); - - + + } - + static float VelNoise() { return (GetRandom() - GetRandom()) * 2.f; } - + void Corpse::SetNode(NodeType n, spades::Vector3 v){ SPAssert(n >= 0); SPAssert(n < NodeCount); nodes[n].pos = v; @@ -122,16 +122,16 @@ namespace spades { 0.f); nodes[n].lastPos = v; nodes[n].lastForce = MakeVector3(0, 0,0); - + } void Corpse::SetNode(NodeType n, spades::Vector4 v){ SetNode(n, v.GetXYZ()); } - + Corpse::~Corpse(){ - + } - + void Corpse::Spring(NodeType n1, NodeType n2, float distance, @@ -145,18 +145,18 @@ namespace spades { float dist = diff.GetLength(); Vector3 force = diff.Normalize() * (distance - dist); force *= dt * 50.f; - + b.vel += force; a.vel -= force; - + b.pos += force / (dt * 50.f) * 0.5f; a.pos -= force / (dt * 50.f) * 0.5f; - + Vector3 velMid = (a.vel + b.vel) * .5f; float dump = 1.f - powf(.1f, dt); a.vel += (velMid - a.vel) * dump; b.vel += (velMid - b.vel) * dump; - + } void Corpse::Spring(NodeType n1a, NodeType n1b, @@ -174,20 +174,20 @@ namespace spades { float dist = diff.GetLength(); Vector3 force = diff.Normalize() * (distance - dist); force *= dt * 50.f; - + b.vel += force; force *= .5f; x.vel -= force; y.vel -= force; - + Vector3 velMid = (x.vel + y.vel) * .25f + b.vel * .5f; float dump = 1.f - powf(.05f, dt); x.vel += (velMid - x.vel) * dump; y.vel += (velMid - y.vel) * dump; b.vel += (velMid - b.vel) * dump; - + } - + static float MyACos(float v){ SPAssert(!isnan(v)); if(v >= 1.f) return 0.f; @@ -214,48 +214,48 @@ namespace spades { float ln1 = d1.GetLength(); float ln2 = d2.GetLength(); float dot = Vector3::Dot(d1, d2) / (ln1 * ln2 + 0.0000001f); - + if(dot >= minDot && dot <= maxDot) return; - + Vector3 diff = n2.pos - n1.pos; float strength = 0.f; - + Vector3 a1 = Vector3::Cross(d1, diff); a1 = Vector3::Cross(d1, a1).Normalize(); - + Vector3 a2 = Vector3::Cross(d2, diff); a2 = Vector3::Cross(d2, a2).Normalize(); - + //a1=-a1; a2=-a2; //a1 = -a1; a2 = -a2; - + if(dot > maxDot){ strength = MyACos(dot) - MyACos(maxDot); }else if(dot < minDot){ strength = MyACos(dot) - MyACos(minDot); } - + SPAssert(!isnan(strength)); - + strength *= 20.f; strength *= dt; - + a1 *= strength; a2 *= strength; - + a2 *= 0.f; - + n2.vel += a1; n1.vel += a2; nBase.vel -= a1 + a2; - + /* d1 += a1 * 0.01; d2 += a2 * 0.01; float nd = Vector3::Dot(d1, d2) / (d1.GetLength() * d2.GetLength()); - + if(dot > maxDot){ if(nd < dot) printf("GOOD %f -> %f\n", dot, nd); @@ -279,42 +279,42 @@ namespace spades { Vector3 diff = n2.pos - n1.pos; float ln1 = diff.GetLength(); float dot = Vector3::Dot(diff, dir) / (ln1 + 0.000000001f); - + if(dot >= minDot && dot <= maxDot) return; - + float strength = 0.f; - + Vector3 a1 = Vector3::Cross(dir, diff); a1 = Vector3::Cross(diff, a1).Normalize(); - + Vector3 a2 = -a1; //a1=-a1; a2=-a2; //a1 = -a1; - + if(dot > maxDot){ strength = MyACos(dot) - MyACos(maxDot); }else if(dot < minDot){ strength = MyACos(dot) - MyACos(minDot); } - + SPAssert(!isnan(strength)); - + strength *= 100.f; strength *= dt; - + a1 *= strength; a2 *= strength; - + n2.vel += a1; n1.vel += a2; //nBase.vel -= a1 + a2; - + /* d1 += a1 * 0.01; d2 += a2 * 0.01; float nd = Vector3::Dot(d1, d2) / (d1.GetLength() * d2.GetLength()); - + if(dot > maxDot){ if(nd < dot) printf("GOOD %f -> %f\n", dot, nd); @@ -327,11 +327,11 @@ namespace spades { printf("BAD %f -> %f\n", dot, nd); }*/ } - + static float fractf(float v){ return v - floorf(v); } - + static void CheckEscape(GameMap *map, IntVector3 hitBlock, IntVector3 a, IntVector3 b, @@ -370,31 +370,31 @@ namespace spades { SPAssert(false); return; } - + if(dist < bestDist){ bestDist = dist; bestDir = dir; } } - + void Corpse::LineCollision(NodeType a, NodeType b, float dt){ if(!r_corpseLineCollision) return; Node& n1 = nodes[a]; Node& n2 = nodes[b]; - + IntVector3 hitBlock; - + if(map->CastRay(n1.lastPos, n2.lastPos, 16.f, hitBlock)) { GameMap::RayCastResult res1 = map->CastRay2(n1.lastPos, n2.lastPos - n1.lastPos, 8); GameMap::RayCastResult res2 = map->CastRay2(n2.lastPos, n1.lastPos - n2.lastPos, 8); - + if(!res1.hit) return; if(!res2.hit) return; if(res1.startSolid || res2.startSolid){ return; } - + // really hit? if(Vector3::Dot(res1.hitPos - n1.lastPos, n2.lastPos - n1.lastPos) > (n2.pos-n1.pos).GetPoweredLength()){ @@ -412,23 +412,23 @@ namespace spades { < 0.f){ return; } - + Vector3 blockPos; blockPos.x = hitBlock.x + .5f; blockPos.y = hitBlock.y + .5f; blockPos.z = hitBlock.z + .5f; - + float inlen = (res1.hitPos - res2.hitPos).GetLength(); - + IntVector3 ivec = {0, 0, 0}; - + ivec.x += res1.normal.x; ivec.y += res1.normal.y; ivec.z += res1.normal.z; ivec.x += res2.normal.x; ivec.y += res2.normal.y; ivec.z += res2.normal.z; - + Vector3 dir = {0.f, 0.f, 0.f}; if(ivec.x == 0 && ivec.y == 0 && ivec.z == 0) { // hanging. which direction to escape? @@ -474,25 +474,25 @@ namespace spades { dir.x = ivec.x; dir.y = ivec.y; dir.z = ivec.z; - + Vector3 normDir = dir; // |D| - + n1.vel -= normDir * std::min(Vector3::Dot(normDir, n1.vel), 0.f); n2.vel -= normDir * std::min(Vector3::Dot(normDir, n2.vel), 0.f); - + dir *= dt * inlen * 5.f; - + n1.vel += dir; n2.vel += dir; - + // friction n1.vel -= (n1.vel - normDir * Vector3::Dot(normDir, n1.vel)) * .2f; n2.vel -= (n2.vel - normDir * Vector3::Dot(normDir, n2.vel)) * .2f; - + } - + } - + void Corpse::AngularMomentum(int eId, NodeType a, NodeType b){ @@ -503,19 +503,19 @@ namespace spades { e.node1 = a; e.node2 = b; return; } - + Vector3 force = e.lastVelDiff - e.velDiff; force *= .5f; nodes[b].vel += force; nodes[a].vel -= force; - + e.lastVelDiff = e.velDiff; } void Corpse::ApplyConstraint(float dt) { SPADES_MARK_FUNCTION(); - - + + AngularMomentum(0, Torso1, Torso2); AngularMomentum(1, @@ -532,23 +532,23 @@ namespace spades { Torso3, Leg1); AngularMomentum(7, Torso4, Leg2); - + Spring(Torso1, Torso2, 0.8f, dt); Spring(Torso3, Torso4, 0.8f, dt); - + Spring(Torso1, Torso4, 0.9f, dt); Spring(Torso2, Torso3, 0.9f, dt); - + Spring(Torso1, Torso3, 1.204f, dt); Spring(Torso2, Torso4, 1.204f, dt); - - + + Spring(Arm1, Torso1, 1.f, dt); Spring(Arm2, Torso2, @@ -557,33 +557,33 @@ namespace spades { 1.f, dt); Spring(Leg2, Torso4, 1.f, dt); - + AngleSpring(Torso1, Arm1, Torso3, -1.f, 0.6f, dt); AngleSpring(Torso2, Arm2, Torso4, -1.f, 0.6f, dt); - + AngleSpring(Torso3, Leg1, Torso2, -1.f, -0.2f, dt); AngleSpring(Torso4, Leg2, Torso1, -1.f, -0.2f, dt); - + Spring(Torso1, Torso2, Head, .6f, dt); /* AngleSpring(Torso1, Torso2, Head, 0.5f, 1.f, dt); - + AngleSpring(Torso2, Torso1, Head, 0.5f, 1.f, dt); */ - + LineCollision(Torso1, Torso2, dt); LineCollision(Torso2, Torso3, dt); LineCollision(Torso3, Torso4, dt); @@ -594,57 +594,57 @@ namespace spades { LineCollision(Torso2, Arm2, dt); LineCollision(Torso3, Leg1, dt); LineCollision(Torso4, Leg2, dt); - - + + return; AngleSpring(Torso4, Torso1, Head, 0.5f, 1.f, dt); - + AngleSpring(Torso3, Torso2, Head, 0.5f, 1.f, dt); - + AngleSpring(Torso4, Torso2, Head, 0.5f, 1.f, dt); - + AngleSpring(Torso3, Torso1, Head, 0.5f, 1.f, dt); } - + void Corpse::Update(float dt) { SPADES_MARK_FUNCTION(); float damp = 1.f; - float damp2 = 1.f; + float damp2 = 1.f; if(dt > 0.f){ damp = powf(.9f, dt); damp2 = powf(.371f, dt); - } + } //dt *= 0.1f; - + for(int i = 0; i 63.f){ node.vel.z -= dt * 6.f; // buoyancy node.vel *= damp; }else{ - node.vel.z += dt * 32.f; // gravity - node.vel.z *= damp2; - } - + node.vel.z += dt * 32.f; // gravity + node.vel.z *= damp2; + } + //node.vel *= damp; - + if(!map->ClipBox(oldPos.x, oldPos.y, oldPos.z)){ - + if(map->ClipBox(node.pos.x, oldPos.y, oldPos.z)){ @@ -652,11 +652,11 @@ namespace spades { if(fabsf(node.vel.x) < .3f) node.vel.x = 0.f; node.pos.x = oldPos.x; - + node.vel.y *= .5f; node.vel.z *= .5f; } - + if(map->ClipBox(node.pos.x, node.pos.y, oldPos.z)){ @@ -664,11 +664,11 @@ namespace spades { if(fabsf(node.vel.y) < .3f) node.vel.y = 0.f; node.pos.y = oldPos.y; - + node.vel.x *= .5f; node.vel.z *= .5f; } - + if(map->ClipBox(node.pos.x, node.pos.y, node.pos.z)){ @@ -676,18 +676,18 @@ namespace spades { if(fabsf(node.vel.z) < .3f) node.vel.z = 0.f; node.pos.z = oldPos.z; - + node.vel.x *= .5f; node.vel.y *= .5f; } - + if(map->ClipBox(node.pos.x, node.pos.y, node.pos.z)){ // TODO: getting out block //node.pos = oldPos; //node.vel *= .5f; } } - + /* if(map->ClipBox(node.pos.x, node.pos.y, @@ -718,23 +718,23 @@ namespace spades { } node.vel *= .8f; //node.pos = oldPos; - + if(node.vel.GetLength() < .02f){ node.vel *= 0.f; } }*/ - + node.lastPos = node.pos; node.lastForce = node.vel; } ApplyConstraint(dt); - + for(int i = 0; i AddDebugLine(nodes[Torso4].pos, nodes[Torso1].pos, col); - + renderer->AddDebugLine(nodes[Torso2].pos, nodes[Torso4].pos, col); renderer->AddDebugLine(nodes[Torso1].pos, nodes[Torso3].pos, col); - - + + renderer->AddDebugLine(nodes[Torso1].pos, nodes[Arm1].pos, col); renderer->AddDebugLine(nodes[Torso2].pos, nodes[Arm2].pos, col); - + renderer->AddDebugLine(nodes[Torso3].pos, nodes[Leg1].pos, col); renderer->AddDebugLine(nodes[Torso4].pos, nodes[Leg2].pos, col); - - + + renderer->AddDebugLine((nodes[Torso1].pos+nodes[Torso2].pos)*.5f, nodes[Head].pos, col); return; } - + ModelRenderParam param; param.customColor = color; - + IModel *model; Matrix4 scaler = Matrix4::Scale(.1f); - + // draw torso Matrix4 torso; Vector3 tX, tY; @@ -801,9 +801,9 @@ namespace spades { tY = Vector3::Cross(tX, tZ).Normalize(); Vector3 tOrigin = tY1 * .5f; torso = Matrix4::FromAxis(tX, -tZ, -tY, tOrigin); - + param.matrix = torso * scaler; - + model = renderer->RegisterModel ("Models/Player/Torso.kv6"); renderer->RenderModel(model, param); @@ -812,13 +812,13 @@ namespace spades { { Vector3 headBase = (torso * MakeVector3(0.0f, 0.f, 0.f)).GetXYZ(); - + model = renderer->RegisterModel ("Models/Player/Head.kv6"); - + Vector3 aX, aY, aZ; Vector3 center = (nodes[Torso1].pos + nodes[Torso2].pos) * .5f; - + aZ = nodes[Head].pos - center; aZ = -torso.GetAxis(2); aZ = aZ.Normalize(); @@ -826,73 +826,73 @@ namespace spades { aY = Vector3::Cross(aY, aZ).Normalize(); aX = Vector3::Cross(aY, aZ).Normalize(); param.matrix = Matrix4::FromAxis(-aX, aY, -aZ, headBase) * scaler; - + renderer->RenderModel(model, param); } - + // draw Arms { Vector3 arm1Base = (torso * MakeVector3(0.4f, 0.f, 0.2f)).GetXYZ(); Vector3 arm2Base = (torso * MakeVector3(-0.4f, 0.f, 0.2f)).GetXYZ(); - + model = renderer->RegisterModel ("Models/Player/Arm.kv6"); - + Vector3 aX, aY, aZ; - + aZ = nodes[Arm1].pos - nodes[Torso1].pos; aZ = aZ.Normalize(); aY = nodes[Torso2].pos - nodes[Torso1].pos; aY = Vector3::Cross(aY, aZ).Normalize(); aX = Vector3::Cross(aY, aZ).Normalize(); param.matrix = Matrix4::FromAxis(aX, aY, aZ, arm1Base) * scaler; - + renderer->RenderModel(model, param); - + aZ = nodes[Arm2].pos - nodes[Torso2].pos; aZ = aZ.Normalize(); aY = nodes[Torso1].pos - nodes[Torso2].pos; aY = Vector3::Cross(aY, aZ).Normalize(); aX = Vector3::Cross(aY, aZ).Normalize(); param.matrix = Matrix4::FromAxis(aX, aY, aZ, arm2Base) * scaler; - + renderer->RenderModel(model, param); } - + // draw Leg { Vector3 leg1Base = (torso * MakeVector3(0.25f, 0.f, 0.9f)).GetXYZ(); Vector3 leg2Base = (torso * MakeVector3(-0.25f, 0.f, 0.9f)).GetXYZ(); - + model = renderer->RegisterModel ("Models/Player/Leg.kv6"); - + Vector3 aX, aY, aZ; - + aZ = nodes[Leg1].pos - nodes[Torso3].pos; aZ = aZ.Normalize(); aY = nodes[Torso1].pos - nodes[Torso2].pos; aY = Vector3::Cross(aY, aZ).Normalize(); aX = Vector3::Cross(aY, aZ).Normalize(); param.matrix = Matrix4::FromAxis(aX, aY, aZ, leg1Base) * scaler; - + renderer->RenderModel(model, param); - + aZ = nodes[Leg2].pos - nodes[Torso4].pos; aZ = aZ.Normalize(); aY = nodes[Torso1].pos - nodes[Torso2].pos; aY = Vector3::Cross(aY, aZ).Normalize(); aX = Vector3::Cross(aY, aZ).Normalize(); param.matrix = Matrix4::FromAxis(aX, aY, aZ, leg2Base) * scaler; - + renderer->RenderModel(model, param); } } - + Vector3 Corpse::GetCenter() { Vector3 v = {0,0,0}; for(int i = 0; i < NodeCount; i++) @@ -900,12 +900,12 @@ namespace spades { v *= 1.f / (float)NodeCount; return v; } - + bool Corpse::IsVisibleFrom(spades::Vector3 eye){ // distance culled? if((eye - GetCenter()).GetLength() > 150.f) return false; - + for(int i = 0; i < NodeCount; i++){ IntVector3 outBlk; if(map->CastRay(eye, nodes[i].pos, @@ -914,7 +914,7 @@ namespace spades { } return false; } - + void Corpse::AddImpulse(spades::Vector3 v){ for(int i = 0; i < NodeCount; i++) nodes[i].vel += v; diff --git a/Sources/Client/GameMapWrapper.cpp b/Sources/Client/GameMapWrapper.cpp index f4d1244d..59a7695d 100644 --- a/Sources/Client/GameMapWrapper.cpp +++ b/Sources/Client/GameMapWrapper.cpp @@ -1,21 +1,21 @@ /* Copyright (c) 2013 yvt - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "GameMapWrapper.h" @@ -31,51 +31,51 @@ namespace spades { namespace client { - - + + GameMapWrapper::GameMapWrapper(GameMap *mp): map(mp) { SPADES_MARK_FUNCTION(); - + width = mp->Width(); height = mp->Height(); depth = mp->Depth(); linkMap = new uint8_t[width*height*depth]; memset(linkMap, 0, width * height * depth); } - + GameMapWrapper::~GameMapWrapper() { SPADES_MARK_FUNCTION(); delete[] linkMap; } - + void GameMapWrapper::Rebuild() { SPADES_MARK_FUNCTION(); - + Stopwatch stopwatch; - + GameMap *m = map; memset(linkMap, 0, width * height * depth); - + for(int x = 0; x < width; x++) for(int y = 0; y < height; y++) SetLink(x, y, depth - 1, Root); - + Deque queue(width * height * 2); - + for(int x = 0; x < width; x++) for(int y = 0; y < height; y++) if(m->IsSolid(x, y, depth - 2)){ SetLink(x, y, depth-2, PositiveZ); queue.Push(CellPos(x, y, depth - 2)); } - + while(!queue.IsEmpty()){ CellPos p = queue.Front(); queue.Shift(); - + int x = p.x, y = p.y, z = p.z; - + if(p.x > 0 && m->IsSolid(x-1,y,z) && GetLink(x-1,y,z) == Invalid){ SetLink(x-1, y, z, PositiveX); queue.Push(CellPos(x-1, y, z)); @@ -101,28 +101,28 @@ namespace spades { queue.Push(CellPos(x, y, z+1)); } } - + SPLog("%.3f msecs to rebuild", stopwatch.GetTime() * 1000.); - + } - + void GameMapWrapper::AddBlock(int x, int y, int z, uint32_t color){ SPADES_MARK_FUNCTION(); - + GameMap *m = map; - + if(GetLink(x, y, z) != Invalid) { SPAssert(m->IsSolid(x, y, z)); return; } - + m->Set(x, y, z, true, color); - + if(GetLink(x, y, z) != Invalid) { return; } - + LinkType l = Invalid; if(x > 0 && m->IsSolid(x - 1, y, z) && GetLink(x-1, y, z) != Invalid){ @@ -155,7 +155,7 @@ namespace spades { SPAssert(GetLink(x, y, z+1) != NegativeZ); } SetLink(x, y, z, l); - + if(l == Invalid) return; // if there's invalid block around this block, @@ -165,12 +165,12 @@ namespace spades { while(!queue.IsEmpty()){ CellPos p = queue.Front(); queue.Shift(); - + int x = p.x, y = p.y, z = p.z; SPAssert(m->IsSolid(x,y,z)); - + LinkType thisLink = GetLink(x, y, z); - + if(p.x > 0 && m->IsSolid(x-1,y,z) && GetLink(x-1,y,z) == Invalid && thisLink != NegativeX){ SetLink(x-1, y, z, PositiveX); @@ -202,50 +202,50 @@ namespace spades { queue.Push(CellPos(x, y, z+1)); } } - + } - - template - static inline bool EqualTwoCond(T a, T b, T c, bool cond) { - return a == b || (cond && a == c); - } - + + template + static inline bool EqualTwoCond(T a, T b, T c, bool cond) { + return a == b || (cond && a == c); + } + std::vector GameMapWrapper::RemoveBlocks(const std::vector& cells) { SPADES_MARK_FUNCTION(); - + if(cells.empty()) return std::vector(); - + GameMap *m = map; - + // solid, but unlinked cells std::vector unlinkedCells; Deque queue(1024); - + // unlink children for(size_t i = 0; i < cells.size(); i++){ CellPos pos = cells[i]; m->Set(pos.x, pos.y, pos.z, false, 0); // if(GetLink(pos.x, pos.y, pos.z) == Invalid){ - // this block is already disconnected. - // } - - if(GetLink(pos.x, pos.y, pos.z) == Marked){ - continue; - } + // this block is already disconnected. + // } + + if(GetLink(pos.x, pos.y, pos.z) == Marked){ + continue; + } SPAssert(GetLink(pos.x, pos.y, pos.z) != Root); - + SetLink(pos.x, pos.y, pos.z, Invalid); queue.Push(pos); - + while(!queue.IsEmpty()){ pos = queue.Front(); queue.Shift(); - + if(m->IsSolid(pos.x, pos.y, pos.z)) unlinkedCells.push_back(pos); // don't "continue;" when non-solid - + int x = pos.x, y = pos.y, z = pos.z; if(x > 0 && EqualTwoCond(GetLink(x-1,y,z), PositiveX, Invalid, m->IsSolid(x-1, y, z))){ SetLink(x-1, y, z, Marked); @@ -272,18 +272,18 @@ namespace spades { queue.Push(CellPos(x, y, z+1)); } } - + } - - // remove "visited" mark + + // remove "visited" mark for(size_t i = 0; i < unlinkedCells.size(); i++){ - const CellPos& pos = unlinkedCells[i]; - if(GetLink(pos.x, pos.y, pos.z) == Marked) - SetLink(pos.x, pos.y, pos.z, Invalid); - } - + const CellPos& pos = unlinkedCells[i]; + if(GetLink(pos.x, pos.y, pos.z) == Marked) + SetLink(pos.x, pos.y, pos.z, Invalid); + } + SPAssert(queue.IsEmpty()); - + // start relinking for(size_t i = 0; i < unlinkedCells.size(); i++){ const CellPos& pos = unlinkedCells[i]; @@ -293,7 +293,7 @@ namespace spades { // don't use SPAssert() continue; } - + LinkType newLink = Invalid; if(z < depth - 1 && GetLink(x,y,z+1) != Invalid){ newLink = PositiveZ; @@ -308,21 +308,21 @@ namespace spades { }else if(z > 0 && GetLink(x,y,z-1) != Invalid){ newLink = NegativeZ; } - + if(newLink != Invalid){ SetLink(x, y, z, newLink); queue.Push(pos); } - + } - + while(!queue.IsEmpty()){ CellPos p = queue.Front(); queue.Shift(); - + int x = p.x, y = p.y, z = p.z; LinkType thisLink = GetLink(x,y,z); - + if(p.x > 0 && m->IsSolid(x-1,y,z) && GetLink(x-1,y,z) == Invalid && thisLink != NegativeX){ SetLink(x-1, y, z, PositiveX); @@ -354,10 +354,10 @@ namespace spades { queue.Push(CellPos(x, y, z+1)); } } - + std::vector floatingBlocks; floatingBlocks.reserve(unlinkedCells.size()); - + for(size_t i = 0; i < unlinkedCells.size(); i++){ const CellPos& p = unlinkedCells[i]; if(!m->IsSolid(p.x, p.y, p.z)) @@ -366,7 +366,7 @@ namespace spades { floatingBlocks.push_back(p); } } - + return floatingBlocks; } } diff --git a/Sources/Client/MumbleLink.cpp b/Sources/Client/MumbleLink.cpp index 65a40036..9d1c8b84 100644 --- a/Sources/Client/MumbleLink.cpp +++ b/Sources/Client/MumbleLink.cpp @@ -37,115 +37,115 @@ namespace spades { #endif }; - MumbleLink::MumbleLink() : - metre_per_block(0.63), + MumbleLink::MumbleLink() : + metre_per_block(0.63), mumbleLinkedMemory(nullptr), priv(new MumbleLinkPrivate()) {} - MumbleLink::~MumbleLink() { - #ifdef WIN32 - UnmapViewOfFile(mumbleLinkedMemory); - if (priv->obj != nullptr) - CloseHandle(priv->obj); - #else - munmap(mumbleLinkedMemory, sizeof(*mumbleLinkedMemory)); - if (priv->fd > 0) - close(priv->fd); - #endif - } + MumbleLink::~MumbleLink() { +#ifdef WIN32 + UnmapViewOfFile(mumbleLinkedMemory); + if (priv->obj != nullptr) + CloseHandle(priv->obj); +#else + munmap(mumbleLinkedMemory, sizeof(*mumbleLinkedMemory)); + if (priv->fd > 0) + close(priv->fd); +#endif + } - void MumbleLink::set_mumble_vector3(float mumble_vec[3], - const spades::Vector3 &vec) { - mumble_vec[0] = vec.x; - mumble_vec[1] = vec.z; - mumble_vec[2] = vec.y; - } + void MumbleLink::set_mumble_vector3(float mumble_vec[3], + const spades::Vector3 &vec) { + mumble_vec[0] = vec.x; + mumble_vec[1] = vec.z; + mumble_vec[2] = vec.y; + } - bool MumbleLink::init() { - assert(mumbleLinkedMemory == nullptr); - #ifdef WIN32 - priv->obj = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink"); - if (priv->obj == nullptr) - return false; + bool MumbleLink::init() { + assert(mumbleLinkedMemory == nullptr); +#ifdef WIN32 + priv->obj = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink"); + if (priv->obj == nullptr) + return false; - mumbleLinkedMemory = static_cast(MapViewOfFile( - priv->obj, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*mumbleLinkedMemory))); + mumbleLinkedMemory = static_cast(MapViewOfFile( + priv->obj, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*mumbleLinkedMemory))); - if (mumbleLinkedMemory == nullptr) { - CloseHandle(priv->obj); - priv->obj = nullptr; - return false; - } - #else - std::string name = "/MumbleLink." + std::to_string(getuid()); + if (mumbleLinkedMemory == nullptr) { + CloseHandle(priv->obj); + priv->obj = nullptr; + return false; + } +#else + std::string name = "/MumbleLink." + std::to_string(getuid()); - priv->fd = shm_open(name.c_str(), O_RDWR, S_IRUSR | S_IWUSR); + priv->fd = shm_open(name.c_str(), O_RDWR, S_IRUSR | S_IWUSR); - if (priv->fd < 0) { - return false; - } + if (priv->fd < 0) { + return false; + } - mumbleLinkedMemory = static_cast( - (mmap(nullptr, sizeof(*mumbleLinkedMemory), PROT_READ | PROT_WRITE, - MAP_SHARED, priv->fd, 0))); + mumbleLinkedMemory = static_cast( + (mmap(nullptr, sizeof(*mumbleLinkedMemory), PROT_READ | PROT_WRITE, + MAP_SHARED, priv->fd, 0))); - if (mumbleLinkedMemory == MAP_FAILED) { - mumbleLinkedMemory = nullptr; - return false; - } - #endif - return true; - } + if (mumbleLinkedMemory == MAP_FAILED) { + mumbleLinkedMemory = nullptr; + return false; + } +#endif + return true; + } - void MumbleLink::setContext(const std::string &context) { - if (mumbleLinkedMemory == nullptr) - return; - size_t len(std::min(256, static_cast(context.size()))); - std::memcpy(mumbleLinkedMemory->context, context.c_str(), len); - mumbleLinkedMemory->context_len = len; - } + void MumbleLink::setContext(const std::string &context) { + if (mumbleLinkedMemory == nullptr) + return; + size_t len(std::min(256, static_cast(context.size()))); + std::memcpy(mumbleLinkedMemory->context, context.c_str(), len); + mumbleLinkedMemory->context_len = len; + } - void MumbleLink::setIdentity(const std::string &identity) { - if (mumbleLinkedMemory == nullptr) - return; - std::wcsncpy(mumbleLinkedMemory->identity, - std::wstring(identity.begin(), identity.end()).c_str(), 256); - } + void MumbleLink::setIdentity(const std::string &identity) { + if (mumbleLinkedMemory == nullptr) + return; + std::wcsncpy(mumbleLinkedMemory->identity, + std::wstring(identity.begin(), identity.end()).c_str(), 256); + } - void MumbleLink::update(spades::client::Player *player) { - if (mumbleLinkedMemory == nullptr || player == nullptr) - return; + void MumbleLink::update(spades::client::Player *player) { + if (mumbleLinkedMemory == nullptr || player == nullptr) + return; - if (mumbleLinkedMemory->uiVersion != 2) { - wcsncpy(mumbleLinkedMemory->name, L"OpenSpades", 256); - wcsncpy(mumbleLinkedMemory->description, L"OpenSpades Link plugin.", 2048); - mumbleLinkedMemory->uiVersion = 2; - } - mumbleLinkedMemory->uiTick++; + if (mumbleLinkedMemory->uiVersion != 2) { + wcsncpy(mumbleLinkedMemory->name, L"OpenSpades", 256); + wcsncpy(mumbleLinkedMemory->description, L"OpenSpades Link plugin.", 2048); + mumbleLinkedMemory->uiVersion = 2; + } + mumbleLinkedMemory->uiTick++; - // Left handed coordinate system. - // X positive towards "right". - // Y positive towards "up". - // Z positive towards "front". - // - // 1 unit = 1 meter + // Left handed coordinate system. + // X positive towards "right". + // Y positive towards "up". + // Z positive towards "front". + // + // 1 unit = 1 meter - // Unit vector pointing out of the avatar's eyes aka "At"-vector. - set_mumble_vector3(mumbleLinkedMemory->fAvatarFront, player->GetFront()); + // Unit vector pointing out of the avatar's eyes aka "At"-vector. + set_mumble_vector3(mumbleLinkedMemory->fAvatarFront, player->GetFront()); - // Unit vector pointing out of the top of the avatar's head aka "Up"-vector - // (here Top points straight up). - set_mumble_vector3(mumbleLinkedMemory->fAvatarTop, player->GetUp()); + // Unit vector pointing out of the top of the avatar's head aka "Up"-vector + // (here Top points straight up). + set_mumble_vector3(mumbleLinkedMemory->fAvatarTop, player->GetUp()); - // Position of the avatar (here standing slightly off the origin) - set_mumble_vector3(mumbleLinkedMemory->fAvatarPosition, - player->GetPosition() * metre_per_block); + // Position of the avatar (here standing slightly off the origin) + set_mumble_vector3(mumbleLinkedMemory->fAvatarPosition, + player->GetPosition() * metre_per_block); - // Same as avatar but for the camera. - set_mumble_vector3(mumbleLinkedMemory->fCameraPosition, - player->GetPosition() * metre_per_block); - set_mumble_vector3(mumbleLinkedMemory->fCameraFront, player->GetFront()); - set_mumble_vector3(mumbleLinkedMemory->fCameraTop, player->GetUp()); - } + // Same as avatar but for the camera. + set_mumble_vector3(mumbleLinkedMemory->fCameraPosition, + player->GetPosition() * metre_per_block); + set_mumble_vector3(mumbleLinkedMemory->fCameraFront, player->GetFront()); + set_mumble_vector3(mumbleLinkedMemory->fCameraTop, player->GetUp()); + } } diff --git a/Sources/Client/NetClient.cpp b/Sources/Client/NetClient.cpp index 5bf317a3..441ba25f 100644 --- a/Sources/Client/NetClient.cpp +++ b/Sources/Client/NetClient.cpp @@ -1,22 +1,22 @@ /* Copyright (c) 2013 yvt based on code of pysnip (c) Mathias Kaerlev 2011-2012. - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include @@ -47,9 +47,9 @@ DEFINE_SPADES_SETTING(cg_unicode, "1"); namespace spades { namespace client { - + static const char UtfSign = -1; - + enum{ BLUE_FLAG = 0, GREEN_FLAG = 1, @@ -95,7 +95,7 @@ namespace spades { PacketTypeVersionSend = 34, // C2S }; - + static std::string EncodeString(std::string str) { auto str2 = CP437::Encode(str, -1); if(!cg_unicode) { @@ -110,27 +110,27 @@ namespace spades { } return str; } - + static std::string DecodeString(std::string s) { if(s.size() > 0 && s[0] == UtfSign){ return s.substr(1); } return CP437::Decode(s); } - + class NetPacketReader { std::vector data; size_t pos; public: NetPacketReader(ENetPacket *packet){ SPADES_MARK_FUNCTION(); - + data.resize(packet->dataLength); memcpy(data.data(), packet->data, packet->dataLength); enet_packet_destroy(packet); pos = 1; } - + NetPacketReader(const std::vector inData){ data = inData; pos = 1; @@ -140,7 +140,7 @@ namespace spades { } uint32_t ReadInt() { SPADES_MARK_FUNCTION(); - + uint32_t value = 0; if(pos + 4 > data.size()){ SPRaise("Received packet truncated"); @@ -153,7 +153,7 @@ namespace spades { } uint16_t ReadShort() { SPADES_MARK_FUNCTION(); - + uint32_t value = 0; if(pos + 2 > data.size()){ SPRaise("Received packet truncated"); @@ -164,7 +164,7 @@ namespace spades { } uint8_t ReadByte() { SPADES_MARK_FUNCTION(); - + if(pos >= data.size()){ SPRaise("Received packet truncated"); } @@ -179,7 +179,7 @@ namespace spades { v = ReadInt(); return f; } - + IntVector3 ReadIntColor() { SPADES_MARK_FUNCTION(); IntVector3 col; @@ -188,7 +188,7 @@ namespace spades { col.x = ReadByte(); return col; } - + Vector3 ReadFloatColor() { SPADES_MARK_FUNCTION(); Vector3 col; @@ -197,11 +197,11 @@ namespace spades { col.x = ReadByte() / 255.f; return col; } - + std::vector GetData() { return data; } - + std::string ReadData(size_t siz) { if(pos + siz > data.size()){ SPRaise("Received packet truncated"); @@ -214,7 +214,7 @@ namespace spades { return std::string(data.data() + pos, data.size() - pos); } - + std::string ReadString(size_t siz){ // convert to C string once so that // null-chars are removed @@ -229,7 +229,7 @@ namespace spades { s = DecodeString(s); return s; } - + void DumpDebug() { #if 1 char buf[1024]; @@ -245,20 +245,20 @@ namespace spades { sprintf(buf, " %02x", (unsigned int)(unsigned char)data[i]); str += buf; } - - + + SPLog("%s", str.c_str()); #endif } }; - + class NetPacketWriter { std::vector data; public: NetPacketWriter(PacketType type){ data.push_back(type); } - + void Write(uint8_t v){ SPADES_MARK_FUNCTION_DEBUG(); data.push_back(v); @@ -288,14 +288,14 @@ namespace spades { Write((uint8_t)v.y); Write((uint8_t)v.x); } - + void Write(std::string str){ str = EncodeString(str); data.insert(data.end(), str.begin(), str.end()); } - + void Write(std::string str, size_t fillLen){ str = EncodeString(str); Write(str.substr(0, fillLen)); @@ -305,23 +305,23 @@ namespace spades { sz++; } } - + ENetPacket *CreatePacket(int flag = ENET_PACKET_FLAG_RELIABLE) { return enet_packet_create(data.data(), data.size(), flag); } }; - + NetClient::NetClient(Client *c): client(c), host(nullptr), peer(nullptr){ SPADES_MARK_FUNCTION(); - + enet_initialize(); SPLog("ENet initialized"); - + host = enet_host_create(NULL, 1, 1, 100000, 100000); @@ -329,44 +329,44 @@ namespace spades { if(!host){ SPRaise("Failed to create ENet host"); } - + if(enet_host_compress_with_range_coder(host) < 0) SPRaise("Failed to enable ENet Range coder."); - + SPLog("ENet Range Coder Enabled"); - + peer = NULL; status = NetClientStatusNotConnected; - + lastPlayerInput = 0; lastWeaponInput = 0; - + savedPlayerPos.resize(32); savedPlayerFront.resize(32); savedPlayerTeam.resize(32); playerPosRecords.resize(32); - + std::fill(savedPlayerTeam.begin(), savedPlayerTeam.end(), -1); - + bandwidthMonitor.reset(new BandwidthMonitor(host)); } NetClient::~NetClient(){ SPADES_MARK_FUNCTION(); - + Disconnect(); if(host) enet_host_destroy(host); bandwidthMonitor.reset(); SPLog("ENet host destroyed"); } - + void NetClient::Connect(const ServerAddress& hostname) { SPADES_MARK_FUNCTION(); - + Disconnect(); SPAssert(status == NetClientStatusNotConnected); - + if( hostname.protocol() != ProtocolVersion::Unknown ) { cg_protocolVersion = (int)hostname.protocol(); } @@ -385,33 +385,33 @@ namespace spades { ENetAddress addr = hostname.asAddress(); SPLog("Connecting to %u:%u", (unsigned int)addr.host, (unsigned int)addr.port); - + savedPackets.clear(); - + peer = enet_host_connect(host, &addr, 1, (int)cg_protocolVersion); if(peer == NULL){ SPRaise("Failed to create ENet peer"); } - + status = NetClientStatusConnecting; statusString = _Tr("NetClient", "Connecting to the server"); timeToTryMapLoad = 0; - + protocolVersion = cg_protocolVersion; } - + void NetClient::Disconnect() { SPADES_MARK_FUNCTION(); - + if(!peer) return; enet_peer_disconnect(peer, 0); - + status = NetClientStatusNotConnected; statusString = _Tr("NetClient", "Not connected"); - + savedPackets.clear(); - + ENetEvent event; SPLog("Waiting for graceful disconnection"); while(enet_host_service(host, &event, 1000) > 0){ @@ -429,50 +429,50 @@ namespace spades { // discard } } - - + + SPLog("Connection terminated"); enet_peer_reset(peer); // FXIME: release peer peer = NULL; } - + int NetClient::GetPing() { SPADES_MARK_FUNCTION(); - + if(status == NetClientStatusNotConnected) return -1; - + auto rtt = peer->roundTripTime; if(rtt == 0) return -1; return static_cast(rtt); } - + void NetClient::DoEvents(int timeout) { SPADES_MARK_FUNCTION(); - + if(status == NetClientStatusNotConnected) return; - + // don't allow changin cg_protocolVersion if((int)cg_protocolVersion != protocolVersion) { cg_protocolVersion = protocolVersion; } - + if(bandwidthMonitor) bandwidthMonitor->Update(); - + ENetEvent event; while(enet_host_service(host, &event, timeout) > 0){ if(event.type == ENET_EVENT_TYPE_DISCONNECT) { if(GetWorld()){ client->SetWorld(NULL); } - + enet_peer_reset(peer); peer = NULL; status = NetClientStatusNotConnected; - + SPLog("Disconnected (data = 0x%08x)", (unsigned int)event.data); statusString = "Disconnected: " + DisconnectReasonString(event.data); @@ -487,7 +487,7 @@ namespace spades { if(reader.GetType() != PacketTypeMapStart){ SPRaise("Unexpected packet: %d", (int)reader.GetType()); } - + mapSize = reader.ReadInt(); status = NetClientStatusReceivingMap; statusString = _Tr("NetClient", "Loading snapshot"); @@ -497,22 +497,22 @@ namespace spades { }else if(status == NetClientStatusReceivingMap){ if(event.type == ENET_EVENT_TYPE_RECEIVE){ NetPacketReader reader(event.packet); - + if(reader.GetType() == PacketTypeMapChunk){ std::vector dt = reader.GetData(); dt.erase(dt.begin()); mapData.insert(mapData.end(), dt.begin(), dt.end()); - + timeToTryMapLoad = 200; - + statusString = _Tr("NetClient", "Loading snapshot ({0}/{1})", mapData.size(), mapSize); - + if(mapSize == mapData.size()){ status = NetClientStatusConnected; statusString = _Tr("NetClient", "Connected"); - + try{ MapLoaded(); }catch(const std::exception& ex){ @@ -528,25 +528,25 @@ namespace spades { statusString = _Tr("NetClient", "Error"); throw; } - + }catch(...){ Disconnect(); statusString = _Tr("NetClient", "Error"); throw; } - + } - + }else{ reader.DumpDebug(); - + if(reader.GetType() != PacketTypeWorldUpdate && reader.GetType() != PacketTypeExistingPlayer && reader.GetType() != PacketTypeCreatePlayer && tryMapLoadOnPacketType){ status = NetClientStatusConnected; statusString = _Tr("NetClient", "Connected"); - + try{ MapLoaded(); }catch(const std::exception& ex){ @@ -574,10 +574,10 @@ namespace spades { stillLoading: savedPackets.push_back(reader.GetData()); } - + //Handle(reader); - - + + } } }else if(status == NetClientStatusConnected){ @@ -595,7 +595,7 @@ namespace spades { } } } - + if(status == NetClientStatusReceivingMap){ if(timeToTryMapLoad > 0){ timeToTryMapLoad--; @@ -626,11 +626,11 @@ namespace spades { } } } - + World *NetClient::GetWorld(){ return client->GetWorld(); } - + Player * NetClient::GetPlayerOrNull(int pId){ SPADES_MARK_FUNCTION(); if(!GetWorld()) @@ -649,7 +649,7 @@ namespace spades { SPRaise("Invalid Player ID %d: Doesn't exist", pId); return GetWorld()->GetPlayer(pId); } - + Player *NetClient::GetLocalPlayer() { SPADES_MARK_FUNCTION(); if(!GetWorld()) @@ -658,7 +658,7 @@ namespace spades { SPRaise("Failed to get local player: no local player"); return GetWorld()->GetLocalPlayer(); } - + Player *NetClient::GetLocalPlayerOrNull() { SPADES_MARK_FUNCTION(); if(!GetWorld()) @@ -677,14 +677,14 @@ namespace spades { inp.sprint = (bits & (1 << 7)) != 0; return inp; } - + WeaponInput ParseWeaponInput(uint8_t bits){ WeaponInput inp; inp.primary = ((bits & (1)) != 0); inp.secondary = ((bits & (1 << 1)) != 0); return inp; } - + std::string NetClient::DisconnectReasonString(enet_uint32 num){ switch(num){ case 1: @@ -703,10 +703,10 @@ namespace spades { return _Tr("NetClient", "Unknown Reason"); } } - + void NetClient::Handle(spades::client::NetPacketReader & reader) { SPADES_MARK_FUNCTION(); - + switch(reader.GetType()){ case PacketTypePositionData: { @@ -757,7 +757,7 @@ namespace spades { front.x = reader.ReadFloat(); front.y = reader.ReadFloat(); front.z = reader.ReadFloat(); - + savedPlayerPos[idx] = pos; savedPlayerFront[idx] = front; if(pos.x != 0.f || @@ -780,7 +780,7 @@ namespace spades { if(p != GetWorld()->GetLocalPlayer()){ p->SetPosition(pos); p->SetOrientation(front); - + PosRecord& rec = playerPosRecords[idx]; if(rec.valid) { float timespan = GetWorld()->GetTime() - rec.time; @@ -789,7 +789,7 @@ namespace spades { vel *= 1.f / 32.f; p->SetVelocity(vel); } - + rec.valid = true; rec.pos = pos; rec.time = GetWorld()->GetTime(); @@ -807,9 +807,9 @@ namespace spades { { int pId = reader.ReadByte(); Player *p = GetPlayer(pId); - + PlayerInput inp = ParsePlayerInput(reader.ReadByte()); - + if(GetWorld()->GetLocalPlayer() == p) { // handle "/fly" jump if(inp.jump) { @@ -817,27 +817,27 @@ namespace spades { } break; } - + p->SetInput(inp); } break; - + case PacketTypeWeaponInput: if(!GetWorld()) break; { int pId = reader.ReadByte(); Player *p = GetPlayer(pId); - + WeaponInput inp = ParseWeaponInput(reader.ReadByte()); - + if(GetWorld()->GetLocalPlayer() == p) break; - + p->SetWeaponInput(inp); } break; - + // Hit Packet is Client-to-Server! case PacketTypeSetHP: { @@ -852,7 +852,7 @@ namespace spades { HurtTypeFall, hurtPos); } break; - + case PacketTypeGrenadePacket: if(!GetWorld()) break; @@ -873,12 +873,12 @@ namespace spades { // emit by Player break; }*/ - + Grenade *g = new Grenade(GetWorld(), pos, vel, fuseLen); GetWorld()->AddGrenade(g); } break; - + case PacketTypeSetTool: { Player *p = GetPlayer(reader.ReadByte()); @@ -911,11 +911,11 @@ namespace spades { int team = reader.ReadByte(); int weapon = reader.ReadByte(); int tool = reader.ReadByte(); - int kills = reader.ReadInt(); + int kills = reader.ReadInt(); IntVector3 color = reader.ReadIntColor(); std::string name = reader.ReadRemainingString(); // TODO: decode name? - + WeaponType wType; switch(weapon){ case 0: @@ -930,12 +930,12 @@ namespace spades { default: SPRaise("Received invalid weapon: %d", weapon); } - + Player *p = new Player(GetWorld(), pId, wType, team, savedPlayerPos[pId], GetWorld()->GetTeam(team).color); p->SetHeldBlockColor(color); //p->SetOrientation(savedPlayerFront[pId]); GetWorld()->SetPlayer(pId, p); - + switch(tool){ case 0: p->SetTool(Player::ToolSpade); break; case 1: p->SetTool(Player::ToolBlock); break; @@ -944,11 +944,11 @@ namespace spades { default: SPRaise("Received invalid tool type: %d", tool); } - + World::PlayerPersistent& pers = GetWorld()->GetPlayerPersistent(pId); pers.name = name; pers.kills = kills; - + savedPlayerTeam[pId] = team; } break; @@ -963,7 +963,7 @@ namespace spades { pos.x = reader.ReadFloat(); pos.y = reader.ReadFloat(); pos.z = reader.ReadFloat(); - + IGameMode* mode = GetWorld()->GetMode(); if( mode && IGameMode::m_CTF == mode->ModeType() ){ CTFGameMode *ctf = static_cast(mode); @@ -986,11 +986,11 @@ namespace spades { if(type >= tc->GetNumTerritories()){ SPRaise("Invalid territory id specified: %d (max = %d)", (int)type, tc->GetNumTerritories() - 1); } - + if(state > 2){ SPRaise("Invalid state %d specified for territory owner.", (int)state); } - + TCGameMode::Territory *t = tc->GetTerritory(type); t->pos = pos; t->ownerTeamId = state;/* @@ -1014,7 +1014,7 @@ namespace spades { pos.z = reader.ReadFloat() - 2.f; std::string name = reader.ReadRemainingString(); // TODO: decode name? - + if( pId < 0 || pId >= 32 ) { SPLog( "Ignoring player 32 (bug in pyspades?: %s)", name.c_str() ); break; @@ -1033,43 +1033,43 @@ namespace spades { default: SPRaise("Received invalid weapon: %d", weapon); } - + Player *p = new Player(GetWorld(), pId, wType, team, savedPlayerPos[pId], - + GetWorld()->GetTeam(team).color); p->SetPosition(pos); GetWorld()->SetPlayer(pId, p); - + World::PlayerPersistent& pers = GetWorld()->GetPlayerPersistent(pId); - + if(!name.empty()) // sometimes becomes empty pers.name = name; - + playerPosRecords[pId].valid = false; - + if(pId == GetWorld()->GetLocalPlayerIndex()){ client->LocalPlayerCreated(); lastPlayerInput = 0xffffffff; lastWeaponInput = 0xffffffff; - SendHeldBlockColor(); // ensure block color synchronized + SendHeldBlockColor(); // ensure block color synchronized }else{ - if(team < 2 && pId < (int)playerPosRecords.size()) { - PosRecord& rec = playerPosRecords[pId]; - - rec.valid = true; - rec.pos = pos; - rec.time = GetWorld()->GetTime(); - } + if(team < 2 && pId < (int)playerPosRecords.size()) { + PosRecord& rec = playerPosRecords[pId]; + + rec.valid = true; + rec.pos = pos; + rec.time = GetWorld()->GetTime(); + } if(savedPlayerTeam[pId] != team && team < 2){ - + client->PlayerJoinedTeam(p); - + savedPlayerTeam[pId] = team; } } - + } break; case PacketTypeBlockAction: @@ -1080,7 +1080,7 @@ namespace spades { pos.x = reader.ReadInt(); pos.y = reader.ReadInt(); pos.z = reader.ReadInt(); - + std::vector cells; if(action == 0){ bool replace = GetWorld()->GetMap()->IsSolidWrapped(pos.x, pos.y, pos.z); @@ -1097,7 +1097,7 @@ namespace spades { cells.push_back(pos); client->PlayerDestroyedBlockWithWeaponOrTool(pos); GetWorld()->DestroyBlock(cells); - + if(p && p->GetTool() == Player::ToolSpade){ p->GotBlock(); } @@ -1128,20 +1128,20 @@ namespace spades { pos2.x = reader.ReadInt(); pos2.y = reader.ReadInt(); pos2.z = reader.ReadInt(); - + IntVector3 col = p ? p->GetBlockColor(): temporaryPlayerBlockColor; std::vector cells; cells = GetWorld()->CubeLine(pos1, pos2, 50); - + for(size_t i = 0; i < cells.size(); i++){ if(!GetWorld()->GetMap()->IsSolid(cells[i].x, cells[i].y, cells[i].z)){ GetWorld()->CreateBlock(cells[i], col); - + } } - - + + if(p){ p->UsedBlocks(static_cast (cells.size())); client->PlayerCreatedBlock(p); @@ -1158,21 +1158,21 @@ namespace spades { IntVector3 teamColors[2]; teamColors[0] = reader.ReadIntColor(); teamColors[1] = reader.ReadIntColor(); - + std::string teamNames[2]; teamNames[0] = reader.ReadString(10); teamNames[1] = reader.ReadString(10); - + World::Team& t1 = GetWorld()->GetTeam(0); World::Team& t2 = GetWorld()->GetTeam(1); t1.color = teamColors[0]; t2.color = teamColors[1]; t1.name = teamNames[0]; t2.name = teamNames[1]; - + GetWorld()->SetFogColor(fogColor); GetWorld()->SetLocalPlayerIndex(pId); - + int mode = reader.ReadByte(); if(mode == 0){ // CTF @@ -1180,15 +1180,15 @@ namespace spades { try{ CTFGameMode::Team& mt1 = mode->GetTeam(0); CTFGameMode::Team& mt2 = mode->GetTeam(1); - + mt1.score = reader.ReadByte(); mt2.score = reader.ReadByte(); mode->SetCaptureLimit(reader.ReadByte()); - + int intelFlags = reader.ReadByte(); mt1.hasIntel = (intelFlags & 1) != 0; mt2.hasIntel = (intelFlags & 2) != 0; - + if(mt2.hasIntel){ mt1.carrier = reader.ReadByte(); reader.ReadData(11); @@ -1197,7 +1197,7 @@ namespace spades { mt1.flagPos.y = reader.ReadFloat(); mt1.flagPos.z = reader.ReadFloat(); } - + if(mt1.hasIntel){ mt2.carrier = reader.ReadByte(); reader.ReadData(11); @@ -1206,15 +1206,15 @@ namespace spades { mt2.flagPos.y = reader.ReadFloat(); mt2.flagPos.z = reader.ReadFloat(); } - + mt1.basePos.x = reader.ReadFloat(); mt1.basePos.y = reader.ReadFloat(); mt1.basePos.z = reader.ReadFloat(); - + mt2.basePos.x = reader.ReadFloat(); mt2.basePos.y = reader.ReadFloat(); mt2.basePos.z = reader.ReadFloat(); - + GetWorld()->SetMode(mode); }catch(...){ delete mode; @@ -1225,13 +1225,13 @@ namespace spades { TCGameMode *mode = new TCGameMode(GetWorld()); try{ int numTer = reader.ReadByte(); - + for(int i = 0; i < numTer; i++){ TCGameMode::Territory ter; ter.pos.x = reader.ReadFloat(); ter.pos.y = reader.ReadFloat(); ter.pos.z = reader.ReadFloat(); - + int state = reader.ReadByte(); ter.ownerTeamId = state; ter.progressBasePos = 0.f; @@ -1241,7 +1241,7 @@ namespace spades { ter.mode = mode; mode->AddTerritory(ter); } - + GetWorld()->SetMode(mode); }catch(...){ delete mode; @@ -1268,7 +1268,7 @@ namespace spades { default: SPInvalidEnum("kt", kt); } - + int respawnTime = reader.ReadByte(); switch(type){ case KillTypeFall: @@ -1328,9 +1328,9 @@ namespace spades { case PacketTypePlayerLeft: { Player *p = GetPlayer(reader.ReadByte()); - + client->PlayerLeaving(p); - + savedPlayerTeam[p->GetId()] = -1; playerPosRecords[p->GetId()].valid = false; GetWorld()->SetPlayer(p->GetId(), NULL); @@ -1342,29 +1342,29 @@ namespace spades { int territoryId = reader.ReadByte(); bool winning = reader.ReadByte() != 0; int state = reader.ReadByte(); - + IGameMode* mode = GetWorld()->GetMode(); - if(mode == NULL) break; + if(mode == NULL) break; if( mode->ModeType() != IGameMode::m_TC ) { SPRaise("Received PacketTypeTerritoryCapture in non-TC gamemode"); } TCGameMode *tc = static_cast(mode); - + if(territoryId >= tc->GetNumTerritories()){ SPRaise("Invalid territory id %d specified (max = %d)", territoryId, tc->GetNumTerritories()-1); } - + client->TeamCapturedTerritory(state, territoryId); - + TCGameMode::Territory *t = tc->GetTerritory(territoryId); - + t->ownerTeamId = state; t->progressBasePos = 0.f; t->progressRate = 0.f; t->progressStartTime = 0.f; t->capturingTeamId = -1; - + if(winning) client->TeamWon(state); } @@ -1375,24 +1375,24 @@ namespace spades { int capturingTeam = reader.ReadByte(); int rate = (int8_t)reader.ReadByte(); float progress = reader.ReadFloat(); - + IGameMode* mode = GetWorld()->GetMode(); - if(mode == NULL) break; + if(mode == NULL) break; if( mode->ModeType() != IGameMode::m_TC ) { SPRaise("Received PacketTypeProgressBar in non-TC gamemode"); } TCGameMode *tc = static_cast(mode); - + if(territoryId >= tc->GetNumTerritories()){ SPRaise("Invalid territory id %d specified (max = %d)", territoryId, tc->GetNumTerritories()-1); } - + if(progress < -0.1f || progress > 1.1f) SPRaise("Progress value out of range(%f)", progress); - + TCGameMode::Territory *t = tc->GetTerritory(territoryId); - + t->progressBasePos = progress; t->progressRate = (float)rate * TC_CAPTURE_RATE; t->progressStartTime = GetWorld()->GetTime(); @@ -1403,7 +1403,7 @@ namespace spades { { if(!GetWorld()) SPRaise("No world"); IGameMode* mode = GetWorld()->GetMode(); - if(mode == NULL) break; + if(mode == NULL) break; if( mode->ModeType() != IGameMode::m_CTF ) { SPRaise("Received PacketTypeIntelCapture in non-TC gamemode"); } @@ -1413,7 +1413,7 @@ namespace spades { GetWorld()->GetPlayerPersistent(p->GetId()).kills += 10; ctf->GetTeam(p->GetTeamId()).hasIntel = false; ctf->GetTeam(p->GetTeamId()).score++; - + bool winning = reader.ReadByte() != 0; if(winning) client->TeamWon(p->GetTeamId()); @@ -1423,7 +1423,7 @@ namespace spades { { Player *p = GetPlayer(reader.ReadByte()); IGameMode* mode = GetWorld()->GetMode(); - if(mode == NULL) break; + if(mode == NULL) break; if( mode->ModeType() != IGameMode::m_CTF ) { SPRaise("Received PacketTypeIntelPickup in non-TC gamemode"); } @@ -1438,21 +1438,21 @@ namespace spades { { Player *p = GetPlayer(reader.ReadByte()); IGameMode* mode = GetWorld()->GetMode(); - if(mode == NULL) break; + if(mode == NULL) break; if( mode->ModeType() != IGameMode::m_CTF ) { SPRaise("Received PacketTypeIntelPickup in non-TC gamemode"); } CTFGameMode *ctf = static_cast(mode); CTFGameMode::Team& team = ctf->GetTeam(p->GetTeamId()); team.hasIntel = false; - + Vector3 pos; pos.x = reader.ReadFloat(); pos.y = reader.ReadFloat(); pos.z = reader.ReadFloat(); - + ctf->GetTeam(1 - p->GetTeamId()).flagPos = pos; - + client->PlayerDropIntel(p); } break; @@ -1527,7 +1527,7 @@ namespace spades { reader.DumpDebug(); } } - + void NetClient::SendJoin(int team, WeaponType weapType, std::string name, int kills){ SPADES_MARK_FUNCTION(); int weapId; @@ -1537,7 +1537,7 @@ namespace spades { case SHOTGUN_WEAPON: weapId = 2; break; default: SPInvalidEnum("weapType", weapType); } - + NetPacketWriter wri(PacketTypeExistingPlayer); wri.Write((uint8_t)GetWorld()->GetLocalPlayerIndex()); wri.Write((uint8_t)team); @@ -1548,7 +1548,7 @@ namespace spades { wri.Write(name, 16); enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendPosition(){ SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypePositionData); @@ -1561,7 +1561,7 @@ namespace spades { enet_peer_send(peer, 0, wri.CreatePacket()); //printf("> (%f %f %f)\n", v.x, v.y, v.z); } - + void NetClient::SendOrientation(spades::Vector3 v){ SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeOrientationData); @@ -1572,7 +1572,7 @@ namespace spades { enet_peer_send(peer, 0, wri.CreatePacket()); //printf("> (%f %f %f)\n", v.x, v.y, v.z); } - + void NetClient::SendPlayerInput(PlayerInput inp) { SPADES_MARK_FUNCTION(); @@ -1596,7 +1596,7 @@ namespace spades { enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendWeaponInput( WeaponInput inp) { SPADES_MARK_FUNCTION(); uint8_t bits = 0; @@ -1613,13 +1613,13 @@ namespace spades { enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendBlockAction(spades::IntVector3 v, BlockActionType type){ SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeBlockAction); wri.Write((uint8_t)GetLocalPlayer()->GetId()); - + switch(type){ case BlockActionCreate: wri.Write((uint8_t)0); break; case BlockActionTool: wri.Write((uint8_t)1); break; @@ -1627,44 +1627,44 @@ namespace spades { case BlockActionGrenade: wri.Write((uint8_t)3); break; default: SPInvalidEnum("type", type); } - + wri.Write((uint32_t)v.x); wri.Write((uint32_t)v.y); wri.Write((uint32_t)v.z); - + enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendBlockLine(spades::IntVector3 v1, spades::IntVector3 v2) { SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeBlockLine); wri.Write((uint8_t)GetLocalPlayer()->GetId()); - + wri.Write((uint32_t)v1.x); wri.Write((uint32_t)v1.y); wri.Write((uint32_t)v1.z); wri.Write((uint32_t)v2.x); wri.Write((uint32_t)v2.y); wri.Write((uint32_t)v2.z); - + enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendReload() { SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeWeaponReload); wri.Write((uint8_t)GetLocalPlayer()->GetId()); - + // these value should be 255, or // NetClient will think reload was done when // it receives echoed WeaponReload packet wri.Write((uint8_t)255); // clip_ammo; not used? wri.Write((uint8_t)255); // reserve_ammo; not used? - + enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendHeldBlockColor() { SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeSetColour); @@ -1672,9 +1672,9 @@ namespace spades { IntVector3 v = GetLocalPlayer()->GetBlockColor(); wri.WriteColor(v); enet_peer_send(peer, 0, wri.CreatePacket()); - + } - + void NetClient::SendTool(){ SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeSetTool); @@ -1691,34 +1691,34 @@ namespace spades { default: SPInvalidEnum("tool", GetLocalPlayer()->GetTool()); } - + enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendGrenade(spades::client::Grenade *g){ SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeGrenadePacket); wri.Write((uint8_t)GetLocalPlayer()->GetId()); - + wri.Write(g->GetFuse()); - + Vector3 v = g->GetPosition(); wri.Write(v.x); wri.Write(v.y); wri.Write(v.z); - + v = g->GetVelocity(); wri.Write(v.x); wri.Write(v.y); wri.Write(v.z); enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendHit(int targetPlayerId, HitType type){ SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeHitPacket); wri.Write((uint8_t)targetPlayerId); - + switch(type){ case HitTypeTorso: wri.Write((uint8_t)0); @@ -1740,7 +1740,7 @@ namespace spades { } enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendChat(std::string text, bool global) { SPADES_MARK_FUNCTION(); @@ -1751,7 +1751,7 @@ namespace spades { wri.Write((uint8_t)0); enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::SendWeaponChange(WeaponType wt){ SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeChangeWeapon); @@ -1768,9 +1768,9 @@ namespace spades { break; } enet_peer_send(peer, 0, wri.CreatePacket()); - + } - + void NetClient::SendTeamChange(int team) { SPADES_MARK_FUNCTION(); NetPacketWriter wri(PacketTypeChangeTeam); @@ -1799,7 +1799,7 @@ namespace spades { SPLog("Sending version back."); enet_peer_send(peer, 0, wri.CreatePacket()); } - + void NetClient::MapLoaded() { SPADES_MARK_FUNCTION(); MemoryStream compressed(mapData.data(), @@ -1807,30 +1807,30 @@ namespace spades { DeflateStream inflate(&compressed, CompressModeDecompress, false); GameMap *map; map = GameMap::Load(&inflate); - + SPLog("Map decoding succeeded."); - + // now initialize world World *w = new World(); w->SetMap(map); map->Release(); SPLog("World initialized."); - + client->SetWorld(w); - + mapData.clear(); - + SPAssert(GetWorld()); - + SPLog("World loaded. Processing saved packets (%d)...", (int)savedPackets.size()); - + for(size_t i = 0; i < playerPosRecords.size(); i++) playerPosRecords[i].valid = false; std::fill(savedPlayerTeam.begin(), savedPlayerTeam.end(), -1); - + // do saved packets try{ for(size_t i =0;i 0.5) { lastUp = host->totalSentData / sw.GetTime(); @@ -1861,7 +1861,7 @@ namespace spades { sw.Reset(); } } - - + + } } diff --git a/Sources/Client/Player.cpp b/Sources/Client/Player.cpp index 35af6370..b0ee0270 100644 --- a/Sources/Client/Player.cpp +++ b/Sources/Client/Player.cpp @@ -1,22 +1,22 @@ /* - Copyright (c) 2013 yvt, + Copyright (c) 2013 yvt, based on code of pysnip (c) Mathias Kaerlev 2011-2012. - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "Player.h" @@ -34,14 +34,14 @@ namespace spades { namespace client { - + Player::Player(World *w, int playerId, WeaponType wType, int teamId, Vector3 position, IntVector3 color): world(w){ SPADES_MARK_FUNCTION(); - + lastClimbTime = -100; lastJumpTime = -100; lastJump = false; @@ -56,53 +56,53 @@ namespace spades { eye = MakeVector3(0,0,0); moveDistance = 0.f; moveSteps = 0; - + this->playerId = playerId; this->weapon = Weapon::CreateWeapon(wType, this); this->weaponType = wType; this->teamId = teamId; this->weapon->Reset(); this->color = color; - + health = 100; grenades = 3; blockStocks = 50; blockColor = IntVector3::Make(111, 111, 111); - + nextSpadeTime = 0.f; nextDigTime = 0.f; nextGrenadeTime = 0.f; nextBlockTime = 0.f; firstDig = false; lastReloadingTime = 0.f; - + pendingPlaceBlock = false; - + blockCursorActive = false; blockCursorDragging = false; - + holdingGrenade = false; reloadingServerSide = false; canPending = false; } - + Player::~Player() { SPADES_MARK_FUNCTION(); delete weapon; } - + bool Player::IsLocalPlayer(){ if(!world) return false; return world->GetLocalPlayer() == this; } - + void Player::SetInput(PlayerInput newInput) { SPADES_MARK_FUNCTION(); - + if(!IsAlive()) return; - + if(newInput.crouch != input.crouch && !airborne) { if(newInput.crouch) position.z += 0.9f; @@ -111,14 +111,14 @@ namespace spades { } input = newInput; } - + void Player::SetWeaponInput(WeaponInput newInput){ SPADES_MARK_FUNCTION(); auto *listener = GetWorld()->GetListener(); - + if(!IsAlive()) return; - + if(input.sprint && !input.crouch && (input.moveBackward || input.moveForward || input.moveLeft || input.moveRight)){ newInput.primary = false; newInput.secondary = false; @@ -166,11 +166,11 @@ namespace spades { if(nextBlockTime > world->GetTime() + std::max(GetToolPrimaryDelay(), GetToolSecondaryDelay())) { - nextBlockTime = world->GetTime() + - std::max(GetToolPrimaryDelay(), + nextBlockTime = world->GetTime() + + std::max(GetToolPrimaryDelay(), GetToolSecondaryDelay()); - } - + } + if(world->GetTime() < nextBlockTime){ newInput.primary = false; newInput.secondary = false; @@ -218,7 +218,7 @@ namespace spades { } } } - + blockCursorDragging = false; blockCursorActive = false; } @@ -226,17 +226,17 @@ namespace spades { if(newInput.primary != weapInput.primary || newInput.primary){ if(newInput.primary){ - + if(!weapInput.primary) lastSingleBlockBuildSeqDone = false; if(IsBlockCursorActive() && blockStocks > 0){ if(listener && this == world->GetLocalPlayer()) listener->LocalPlayerBlockAction(blockCursorPos, BlockActionCreate); - + lastSingleBlockBuildSeqDone = true; // blockStocks--; decrease when created - + nextBlockTime = world->GetTime() + GetToolPrimaryDelay(); }else if(blockStocks > 0 && airborne && canPending && this == world->GetLocalPlayer()) { @@ -245,7 +245,7 @@ namespace spades { }else if(!IsBlockCursorActive()) { // wait for building becoming possible } - + blockCursorDragging = false; blockCursorActive = false; }else{ @@ -264,12 +264,12 @@ namespace spades { }else{ SPAssert(false); } - + weapInput = newInput; - - + + } - + void Player::Reload() { SPADES_MARK_FUNCTION(); if(health == 0){ @@ -281,99 +281,99 @@ namespace spades { weapon->IsReloading()) reloadingServerSide = true; } - + void Player::ReloadDone(int clip, int stock) { reloadingServerSide = false; weapon->ReloadDone(clip, stock); } - + void Player::Restock() { SPADES_MARK_FUNCTION(); if(health == 0){ // dead man cannot restock return; } - + weapon->Restock(); grenades = 3; blockStocks = 50; health = 100; - + if(world->GetListener()) world->GetListener()->PlayerRestocked(this); } - + void Player::GotBlock() { if(blockStocks < 50) blockStocks++; } - + void Player::SetTool(spades::client::Player::ToolType t) { SPADES_MARK_FUNCTION(); - + if(t == tool) return; tool = t; holdingGrenade = false; blockCursorActive = false; blockCursorDragging = false; - + reloadingServerSide = false; - + WeaponInput inp; SetWeaponInput(inp); - + weapon->AbortReload(); - + if(world->GetListener()) world->GetListener()->PlayerChangedTool(this); } - + void Player::SetHeldBlockColor(spades::IntVector3 col){ blockColor = col; } - + void Player::SetPosition(const spades::Vector3 &v){ SPADES_MARK_FUNCTION(); - + position = v; eye = v; - + } - + void Player::SetVelocity(const spades::Vector3 &v) { SPADES_MARK_FUNCTION(); - + velocity = v; } - + void Player::SetOrientation(const spades::Vector3 &v) { SPADES_MARK_FUNCTION(); - + orientation = v; } - + void Player::Turn(float longitude, float latitude){ SPADES_MARK_FUNCTION(); - + Vector3 o = GetFront(); float lng = atan2f(o.y, o.x); float lat = atan2f(o.z, sqrtf(o.x*o.x+o.y*o.y)); - + lng += longitude; lat += latitude; - + if(lat < -static_cast(M_PI) * .49f) lat = -static_cast(M_PI) * .49f; if(lat > static_cast(M_PI) * .49f) lat = static_cast(M_PI) * .49f; - + o.x = cosf(lng) * cosf(lat); o.y = sinf(lng) * cosf(lat); o.z = sinf(lat); SetOrientation(o); } - + void Player::SetHP(int hp, HurtType type, spades::Vector3 p) { @@ -387,18 +387,18 @@ namespace spades { p); } } - + void Player::Update(float dt) { SPADES_MARK_FUNCTION(); auto* listener = world->GetListener(); - + MovePlayer(dt); - + if(!IsAlive()) { // do death cleanup blockCursorDragging = false; } - + if(tool == ToolSpade){ if(weapInput.primary){ if(world->GetTime() > nextSpadeTime){ @@ -417,7 +417,7 @@ namespace spades { auto *map = GetWorld()->GetMap(); result = map->CastRay2(GetEye(), GetFront(), 12); canPending = false; - + if(blockCursorDragging) { // check the starting point is not floating auto start = blockCursorDragPos; @@ -438,19 +438,19 @@ namespace spades { blockCursorDragging = false; } } - + if(result.hit && (result.hitBlock + result.normal).z < 62 && (!OverlapsWithOneBlock(result.hitBlock + result.normal)) && BoxDistanceToBlock(result.hitBlock + result.normal) < 3.f && !pendingPlaceBlock){ - + // Building is possible, and there's no delayed block placement. blockCursorActive = true; blockCursorPos = result.hitBlock + result.normal; - + }else if(pendingPlaceBlock){ - + // Delayed Block Placement: When player attempts to place a block while jumping and // placing block is currently impossible, building will be delayed until it becomes // possible, as long as player is airborne. @@ -465,24 +465,24 @@ namespace spades { BoxDistanceToBlock(pendingPlaceBlockPos) < 3.f){ // now building became possible. SPAssert(this == world->GetLocalPlayer()); - + if(GetWorld()->GetListener()) GetWorld()->GetListener()->LocalPlayerBlockAction(pendingPlaceBlockPos, BlockActionCreate); - + pendingPlaceBlock = false; lastSingleBlockBuildSeqDone = true; // blockStocks--; decrease when created - + nextBlockTime = world->GetTime() + GetToolPrimaryDelay(); } - + }else{ // Delayed Block Placement can be activated only when the only reason making placement // impossible is that block to be placed overlaps with the player's hitbox. canPending = result.hit && (result.hitBlock + result.normal).z < 62 && BoxDistanceToBlock(result.hitBlock + result.normal) < 3.f; - + blockCursorActive = false; int dist = 11; for(; dist >= 1 && @@ -497,10 +497,10 @@ namespace spades { GetFront(), dist); } - + blockCursorPos = result.hitBlock + result.normal; } - + }else if(tool == ToolWeapon){ }else if(tool == ToolGrenade){ if(holdingGrenade){ @@ -509,13 +509,13 @@ namespace spades { } } } - + if(tool != ToolWeapon) weapon->SetShooting(false); if(weapon->FrameNext(dt)){ FireWeapon(); } - + if(weapon->IsReloading()) { lastReloadingTime = world->GetTime(); }else if(reloadingServerSide) { @@ -527,27 +527,27 @@ namespace spades { } } } - + bool Player::RayCastApprox(spades::Vector3 start, spades::Vector3 dir){ Vector3 diff = position - start; - + // |P-A| * cos(theta) float c = Vector3::Dot(diff, dir); - + // |P-A|^2 float sq = diff.GetPoweredLength(); - + // |P-A| * sin(theta) float dist = sqrtf(sq - c * c); - + return dist < 8.f; } - - static float GetHorizontalLength(const Vector3 &v) - { - return std::sqrt(v.x * v.x + v.y * v.y); - } - + + static float GetHorizontalLength(const Vector3 &v) + { + return std::sqrt(v.x * v.x + v.y * v.y); + } + enum class HitBodyPart { None, Head, @@ -555,49 +555,49 @@ namespace spades { Limb1, Limb2, Arms }; - + void Player::FireWeapon() { SPADES_MARK_FUNCTION(); - + Vector3 muzzle = GetEye(); muzzle += GetFront() * 0.01f; - + // for hit-test debugging std::map playerHits; std::vector bulletVectors; - + //Vector3 right = GetRight(); //Vector3 up = GetUp(); - + int pellets = weapon->GetPelletSize(); float spread = weapon->GetSpread(); GameMap *map = world->GetMap(); - + // pyspades takes destroying more than one block as a // speed hack (shotgun does this) bool blockDestroyed = false; - + Vector3 dir2 = GetFront(); for(int i =0 ; i < pellets; i++){ - + // AoS 0.75's way (dir2 shouldn't be normalized!) dir2.x += (GetRandom() - GetRandom()) * spread; dir2.y += (GetRandom() - GetRandom()) * spread; dir2.z += (GetRandom() - GetRandom()) * spread; Vector3 dir = dir2.Normalize(); - + bulletVectors.push_back(dir); - + // first do map raycast GameMap::RayCastResult mapResult; mapResult = map->CastRay2(muzzle, dir, 500); - + Player *hitPlayer = NULL; float hitPlayerDistance = 0.f; HitBodyPart hitPart = HitBodyPart::None; - + for(int i = 0; i < world->GetNumPlayerSlots(); i++){ Player *other = world->GetPlayer(i); if(other == this || other == NULL) @@ -608,10 +608,10 @@ namespace spades { // quickly reject players unlikely to be hit if(!other->RayCastApprox(muzzle, dir)) continue; - + HitBoxes hb = other->GetHitBoxes(); Vector3 hitPos; - + if(hb.head.RayCast(muzzle, dir, &hitPos)) { float dist = GetHorizontalLength(hitPos - muzzle); if(hitPlayer == NULL || @@ -622,7 +622,7 @@ namespace spades { } } if(hb.torso.RayCast(muzzle, dir, &hitPos)) { - float dist = GetHorizontalLength(hitPos - muzzle); + float dist = GetHorizontalLength(hitPos - muzzle); if(hitPlayer == NULL || dist < hitPlayerDistance){ hitPlayer = other; @@ -646,23 +646,23 @@ namespace spades { } } } - + Vector3 finalHitPos; finalHitPos = muzzle + dir * 128.f; - + if(hitPlayer == nullptr && !mapResult.hit) { // might hit water surface. - + } - + if(mapResult.hit && GetHorizontalLength(mapResult.hitPos - muzzle) < 128.f && (hitPlayer == NULL || GetHorizontalLength(mapResult.hitPos - muzzle) < hitPlayerDistance)){ IntVector3 outBlockCoord = mapResult.hitBlock; // TODO: set correct ray distance // FIXME: why ray casting twice? - + finalHitPos = mapResult.hitPos; - + if(outBlockCoord.x >= 0 && outBlockCoord.y >= 0 && outBlockCoord.z >= 0 && outBlockCoord.x < map->Width() && outBlockCoord.y < map->Height() && outBlockCoord.z < map->Depth()){ @@ -682,10 +682,10 @@ namespace spades { int y = outBlockCoord.y; int z = outBlockCoord.z; SPAssert(map->IsSolid(x, y, z)); - + Vector3 blockF = {x + .5f, y + .5f, z + .5f}; float distance = GetHorizontalLength(blockF - muzzle); - + uint32_t color = map->GetColor(x, y, z); int health = color >> 24; health -= weapon->GetDamage(HitTypeBlock, distance); @@ -697,23 +697,23 @@ namespace spades { world->GetLocalPlayer() == this) world->GetListener()->LocalPlayerBlockAction (outBlockCoord, BlockActionTool); - + } color = (color & 0xffffff) | ((uint32_t)health << 24); if(map->IsSolid(x, y, z)) map->Set(x, y, z, true, color); - + if(world->GetListener()) world->GetListener()->BulletHitBlock(mapResult.hitPos, mapResult.hitBlock, mapResult.normal); } } - }else if(hitPlayer != NULL){ + }else if(hitPlayer != NULL){ if(hitPlayerDistance < 128.f){ - + finalHitPos = muzzle + dir * hitPlayerDistance; - + switch(hitPart) { case HitBodyPart::Head: playerHits[hitPlayer->GetId()].numHeadHits++; @@ -734,7 +734,7 @@ namespace spades { SPAssert(false); break; } - + if(world->GetListener()){ switch(hitPart) { case HitBodyPart::Head: @@ -769,20 +769,20 @@ namespace spades { } } } - + if(world->GetListener() && this != world->GetLocalPlayer()) world->GetListener()->AddBulletTracer(this, muzzle, finalHitPos); - + // one pellet done } - + // do hit test debugging auto *debugger = world->GetHitTestDebugger(); if(debugger && IsLocalPlayer()) { debugger->SaveImage(playerHits, bulletVectors); } - + // in AoS 0.75's way Vector3 o = orientation; Vector3 rec = weapon->GetRecoil(); @@ -792,29 +792,29 @@ namespace spades { o += GetRight() * rec.x * sinf(world->GetTime() * 10.f); o = o.Normalize(); SetOrientation(o); - + reloadingServerSide = false; } - + void Player::ThrowGrenade(){ SPADES_MARK_FUNCTION(); - + if(!holdingGrenade) return; grenades--; - + Vector3 muzzle = GetEye() + GetFront() * 0.1f; Vector3 vel = GetFront() * 1.f; float fuse = world->GetTime() - grenadeTime; fuse = 3.f - fuse; - + if(health <= 0){ // drop, don't throw vel = MakeVector3(0,0,0); } - + vel += GetVelocty(); - + if(this == world->GetLocalPlayer()){ Grenade *gren = new Grenade(world, muzzle, vel, fuse); world->AddGrenade(gren); @@ -825,26 +825,26 @@ namespace spades { if(world->GetListener()) world->GetListener()->PlayerThrownGrenade(this, NULL); } - + holdingGrenade = false; } - + void Player::DigWithSpade(){ SPADES_MARK_FUNCTION(); - + IntVector3 outBlockCoord; GameMap *map = world->GetMap(); Vector3 muzzle = GetEye(), dir = GetFront(); - + // TODO: set correct ray distance // first do map raycast GameMap::RayCastResult mapResult; mapResult = map->CastRay2(muzzle, dir, 256); - + outBlockCoord = mapResult.hitBlock; - + // TODO: set correct ray distance if(mapResult.hit && BoxDistanceToBlock(mapResult.hitBlock + mapResult.normal) < 3.f && outBlockCoord.x >= 0 && outBlockCoord.y >= 0 && outBlockCoord.z >= 0 && @@ -852,17 +852,17 @@ namespace spades { outBlockCoord.z < map->Depth()){ if(outBlockCoord.z < 62){ SPAssert(map->IsSolid(outBlockCoord.x, outBlockCoord.y, outBlockCoord.z)); - + // send destroy command only for local cmd if(this == world->GetLocalPlayer()) { - + if(world->GetListener()) world->GetListener()->LocalPlayerBlockAction (outBlockCoord, BlockActionDig); - - + + } - + if(world->GetListener()) world->GetListener()->PlayerHitBlockWithSpade(this, mapResult.hitPos, @@ -874,14 +874,14 @@ namespace spades { world->GetListener()->PlayerMissedSpade(this); } } - + void Player::UseSpade() { SPADES_MARK_FUNCTION(); - + bool missed = true; - + Vector3 muzzle = GetEye(), dir = GetFront(); - + IntVector3 outBlockCoord; GameMap *map = world->GetMap(); // TODO: set correct ray distance @@ -890,10 +890,10 @@ namespace spades { mapResult = map->CastRay2(muzzle, dir, 256); - + Player *hitPlayer = NULL; int hitFlag = 0; - + for(int i = 0; i < world->GetNumPlayerSlots(); i++){ Player *other = world->GetPlayer(i); if(other == this || other == NULL) @@ -906,27 +906,27 @@ namespace spades { if((eye - other->GetEye()).GetChebyshevLength() >= MELEE_DISTANCE_F) continue; - + Vector3 diff = other->GetEye() - eye; Vector3 view; view.x = Vector3::Dot(diff, GetRight()); view.y = Vector3::Dot(diff, GetUp()); view.z = Vector3::Dot(diff, GetFront()); - + if(view.z < 0.f) continue; - + view.x /= view.z; view.y /= view.z; view.z = 0.f; - + if(view.GetChebyshevLength() < 5.f) { hitPlayer = other; hitFlag = 1; break; } } - + outBlockCoord = mapResult.hitBlock; if(mapResult.hit && BoxDistanceToBlock(mapResult.hitBlock + mapResult.normal) < 3.f && (hitPlayer == NULL) && @@ -941,7 +941,7 @@ namespace spades { int z = outBlockCoord.z; SPAssert(map->IsSolid(x, y, z)); missed = false; - + uint32_t color = map->GetColor(x, y, z); int health = color >> 24; health -= 55; @@ -957,7 +957,7 @@ namespace spades { color = (color & 0xffffff) | ((uint32_t)health << 24); if(map->IsSolid(x, y, z)) map->Set(x, y, z, true, color); - + if(world->GetListener()) world->GetListener()->PlayerHitBlockWithSpade(this, mapResult.hitPos, @@ -965,8 +965,8 @@ namespace spades { mapResult.normal); } }else if(hitPlayer != NULL){ - - + + if(world->GetListener()){ if(hitFlag) world->GetListener()->BulletHitPlayer(hitPlayer, @@ -974,50 +974,50 @@ namespace spades { hitPlayer->GetEye(), this); } - - + + } - + if(missed){ if(world->GetListener()) world->GetListener()->PlayerMissedSpade(this); } } - + Vector3 Player::GetFront() { SPADES_MARK_FUNCTION_DEBUG(); return orientation; } - + Vector3 Player::GetFront2D() { SPADES_MARK_FUNCTION_DEBUG(); return MakeVector3(orientation.x, orientation.y, 0.f).Normalize(); } - + Vector3 Player::GetRight() { SPADES_MARK_FUNCTION_DEBUG(); return -Vector3::Cross(MakeVector3(0,0,-1), GetFront2D()).Normalize(); } - + Vector3 Player::GetLeft(){ SPADES_MARK_FUNCTION_DEBUG(); return -GetRight(); } - + Vector3 Player::GetUp() { SPADES_MARK_FUNCTION_DEBUG(); return Vector3::Cross(GetRight(), GetFront()) .Normalize(); } - + bool Player::GetWade() { SPADES_MARK_FUNCTION_DEBUG(); return GetOrigin().z > 62.f; } - + Vector3 Player::GetOrigin() { SPADES_MARK_FUNCTION_DEBUG(); Vector3 v = eye; @@ -1025,10 +1025,10 @@ namespace spades { v.z += .3f; return v; } - + void Player::BoxClipMove(float fsynctics) { SPADES_MARK_FUNCTION(); - + float f = fsynctics * 32.f; float nx = f * velocity.x + position.x; float ny = f * velocity.y + position.y; @@ -1041,20 +1041,20 @@ namespace spades { offset = .9f; m = 1.35f; } - + float nz = position.z + offset; - + float z; GameMap *map = world->GetMap(); - - + + if(velocity.x < 0.f) f = -0.45f; else f = 0.45f; - + z = m; - + while(z >= -1.36f && !map->ClipBox(nx + f, position.y - .45f, nz + z) && !map->ClipBox(nx + f, position.y + .45f, nz + z)) @@ -1076,14 +1076,14 @@ namespace spades { }else{ velocity.x = 0.f; } - + if(velocity.y < 0.f) f = -0.45f; else f = 0.45f; - + z = m; - + while(z >= -1.36f && !map->ClipBox(position.x - .45f, ny + f, nz + z) && !map->ClipBox(position.x + .45f, ny + f, nz + z)) @@ -1106,7 +1106,7 @@ namespace spades { }else if(!climb){ velocity.y = 0.f; } - + if(climb){ velocity.x *= .5f; velocity.y *= .5f; @@ -1118,7 +1118,7 @@ namespace spades { m = -m; nz += velocity.z * fsynctics * 32.f; } - + airborne = true; if(map->ClipBox(position.x - .45f, position.y - .45f, nz + m) || map->ClipBox(position.x - .45f, position.y + .45f, nz + m) || @@ -1132,14 +1132,14 @@ namespace spades { }else{ position.z = nz - offset; } - + RepositionPlayer(position); } - + bool Player::IsOnGroundOrWade() { return ((velocity.z >= 0.f && velocity.z < .017f) && !airborne); } - + void Player::ForceJump() { velocity.z = -0.36f; lastJump = true; @@ -1148,7 +1148,7 @@ namespace spades { lastJumpTime = world->GetTime(); } } - + void Player::MovePlayer(float fsynctics) { if(input.jump && (!lastJump) && IsOnGroundOrWade()) { @@ -1161,7 +1161,7 @@ namespace spades { }else if(!input.jump){ lastJump = false; } - + float f = fsynctics; if(airborne) f *= 0.1f; @@ -1175,7 +1175,7 @@ namespace spades { if((input.moveForward || input.moveBackward) && (input.moveRight || input.moveLeft)) f /= sqrtf(2.f); - + // looking up or down should alter speed const float maxVertLookSlowdown = 0.9f; const float vertLookSlowdownStart = 0.65f; // about 40 degrees @@ -1200,30 +1200,30 @@ namespace spades { velocity.x -= left.x * f; velocity.y -= left.y * f; } - + // this is a linear approximation that's // done in pysnip // accurate computation is not difficult f = fsynctics + 1.f; velocity.z += fsynctics; velocity.z /= f; // air friction - + if(wade) f = fsynctics * 6.f + 1.f; else if(!airborne) f = fsynctics * 4.f + 1.f; - + velocity.x /= f; velocity.y /= f; - + float f2 = velocity.z; BoxClipMove(fsynctics); - + // hit ground if(velocity.z == 0.f && (f2 > FALL_SLOW_DOWN)) { velocity.x *= .5f; velocity.y *= .5f; - + if(f2 > FALL_DAMAGE_VELOCITY){ f2 -= FALL_DAMAGE_VELOCITY; if(world->GetListener()){ @@ -1235,7 +1235,7 @@ namespace spades { } } } - + if(velocity.z >= 0.f && velocity.z < .017f && !input.sneak && !input.crouch && !(weapInput.secondary && IsToolWeapon())){ @@ -1245,12 +1245,12 @@ namespace spades { float dy = f * velocity.y; float dist = sqrtf(dx*dx+dy*dy); moveDistance += dist * .3f; - + bool madeFootstep = false; while(moveDistance > 1.f){ moveSteps++; moveDistance -= 1.f; - + if(world->GetListener() && !madeFootstep){ world->GetListener()->PlayerMadeFootstep(this); madeFootstep = true; @@ -1258,19 +1258,19 @@ namespace spades { } } } - + bool Player::TryUncrouch(bool move) { SPADES_MARK_FUNCTION(); - + float x1 = position.x + 0.45f; float x2 = position.x - 0.45f; float y1 = position.y + 0.45f; float y2 = position.y - 0.45f; float z1 = position.z + 2.25f; float z2 = position.z - 1.35f; - + GameMap *map = world->GetMap(); - + // lower feet if(airborne && !(map->ClipBox(x1, y1, z1) || @@ -1290,19 +1290,19 @@ namespace spades { } return false; } - + void Player::RepositionPlayer(const spades::Vector3 & pos2){ SPADES_MARK_FUNCTION(); - + eye = position = pos2; float f = lastClimbTime - world->GetTime(); if(f > -.25f) eye.z += (f + .25f) / .25f; } - + float Player::GetToolPrimaryDelay() { SPADES_MARK_FUNCTION_DEBUG(); - + switch(tool){ case ToolWeapon: return weapon->GetDelay(); @@ -1316,10 +1316,10 @@ namespace spades { SPInvalidEnum("tool", tool); } } - + float Player::GetToolSecondaryDelay() { SPADES_MARK_FUNCTION_DEBUG(); - + switch(tool){ case ToolBlock: return GetToolPrimaryDelay(); @@ -1329,36 +1329,36 @@ namespace spades { SPInvalidEnum("tool", tool); } } - + float Player::GetSpadeAnimationProgress() { SPADES_MARK_FUNCTION_DEBUG(); - + SPAssert(tool == ToolSpade); SPAssert(weapInput.primary); return 1.f - (nextSpadeTime - world->GetTime()) / GetToolPrimaryDelay(); } - + float Player::GetDigAnimationProgress() { SPADES_MARK_FUNCTION_DEBUG(); - + SPAssert(tool == ToolSpade); SPAssert(weapInput.secondary); return 1.f - (nextDigTime - world->GetTime()) / GetToolSecondaryDelay(); } - + float Player::GetTimeToNextGrenade() { return nextGrenadeTime - world->GetTime(); } - + void Player::KilledBy(KillType type, Player *killer, int respawnTime) { SPADES_MARK_FUNCTION(); health = 0; weapon->SetShooting(false); - + // if local player is killed while cooking grenade, // drop the live grenade. if(this == world->GetLocalPlayer() && @@ -1368,59 +1368,59 @@ namespace spades { } if(world->GetListener()) world->GetListener()->PlayerKilledPlayer(killer, this, type); - + input = PlayerInput(); weapInput = WeaponInput(); this->respawnTime = world->GetTime() + respawnTime; } - + bool Player::IsAlive() { return health > 0; } - + std::string Player::GetName() { return world->GetPlayerPersistent(GetId()).name; } - + float Player::GetWalkAnimationProgress() { return moveDistance * .5f + (float)(moveSteps & 1) * .5f; } - + Player::HitBoxes Player::GetHitBoxes() { SPADES_MARK_FUNCTION_DEBUG(); Player::HitBoxes hb; - + Vector3 front = GetFront(); - + float yaw = atan2(front.y, front.x) + static_cast(M_PI) * .5f; float pitch = -atan2(front.z, sqrt(front.x * front.x + front.y * front.y)); - + // lower axis Matrix4 lower = Matrix4::Translate(GetOrigin()); lower = lower * Matrix4::Rotate(MakeVector3(0,0,1), yaw); - + Matrix4 torso; - + if(input.crouch){ lower = lower * Matrix4::Translate(0, 0, -0.4f); // lower hb.limbs[0] = AABB3(-.4f, -.15f, 0.5f, 0.3f, .3f, 0.5f); hb.limbs[0] = lower * hb.limbs[0]; - + hb.limbs[1] = AABB3(.1f, -.15f, 0.5f, 0.3f, .3f, 0.5f); hb.limbs[1] = lower * hb.limbs[1]; - + torso = lower * Matrix4::Translate(0, 0, -0.3f); - + // torso hb.torso = AABB3(-.4f, -.15f, 0.1f, .8f, .8f, .6f); hb.torso = torso * hb.torso; - + hb.limbs[2] = AABB3(-.6f, -.15f, 0.1f, 1.2f, .3f, .6f); hb.limbs[2] = torso * hb.limbs[2]; - + // head hb.head = AABB3(-.3f, -.3f, -0.45f, .6f, .6f, 0.6f); hb.head = Matrix4::Translate(0, 0, -0.15f) * hb.head; @@ -1431,19 +1431,19 @@ namespace spades { // lower hb.limbs[0] = AABB3(-.4f, -.15f, 0.f, 0.3f, .3f, 1.f); hb.limbs[0] = lower * hb.limbs[0]; - + hb.limbs[1] = AABB3(.1f, -.15f, 0.f, 0.3f, .3f, 1.f); hb.limbs[1] = lower * hb.limbs[1]; - + torso = lower * Matrix4::Translate(0, 0, -1.1f); - + // torso hb.torso = AABB3(-.4f, -.15f, 0.1f, .8f, .3f, .9f); hb.torso = torso * hb.torso; - + hb.limbs[2] = AABB3(-.6f, -.15f, 0.1f, 1.2f, .3f, .9f); hb.limbs[2] = torso * hb.limbs[2]; - + // head hb.head = AABB3(-.3f, -.3f, -0.5f, .6f, .6f, 0.6f); hb.head = Matrix4::Translate(0, 0, -0.1f) * hb.head; @@ -1451,20 +1451,20 @@ namespace spades { hb.head = Matrix4::Translate(0, 0, 0.1f) * hb.head; hb.head = torso * hb.head; } - + return hb; } IntVector3 Player::GetColor() { return world->GetTeam(teamId).color; } - + bool Player::IsCookingGrenade() { return tool == ToolGrenade && holdingGrenade; } float Player::GetGrenadeCookTime() { return world->GetTime() - grenadeTime; } - + void Player::SetWeaponType(WeaponType weap){ SPADES_MARK_FUNCTION_DEBUG(); if(this->weapon->GetWeaponType() == weap) @@ -1473,11 +1473,11 @@ namespace spades { this->weapon = Weapon::CreateWeapon(weap, this); this->weaponType = weap; } - + void Player::SetTeam(int tId){ teamId = tId; } - + bool Player::IsReadyToUseTool() { SPADES_MARK_FUNCTION_DEBUG(); switch(tool){ @@ -1493,7 +1493,7 @@ namespace spades { return weapon->IsReadyToShoot(); } } - + bool Player::IsToolSelectable(ToolType type) { SPADES_MARK_FUNCTION_DEBUG(); switch(type){ @@ -1510,7 +1510,7 @@ namespace spades { SPAssert(false); } } - + bool Player::OverlapsWith(const spades::AABB3 &aabb) { SPADES_MARK_FUNCTION_DEBUG(); float offset, m; @@ -1528,13 +1528,13 @@ namespace spades { .9f, .9f, offset + m); return aabb && playerBox; } - + bool Player::OverlapsWithOneBlock(spades::IntVector3 vec) { SPADES_MARK_FUNCTION_DEBUG(); return OverlapsWith(AABB3(vec.x, vec.y, vec.z, 1, 1, 1)); } - + #pragma mark - Block Construction bool Player::IsBlockCursorActive(){ return tool == ToolBlock && blockCursorActive; @@ -1545,7 +1545,7 @@ namespace spades { float Player::BoxDistanceToBlock(spades::IntVector3 v){ Vector3 e = {(float)v.x, (float)v.y, (float)v.z}; e += .5f; - + return (e-eye).GetChebyshevLength(); } } diff --git a/Sources/Core/ConcurrentDispatch.cpp b/Sources/Core/ConcurrentDispatch.cpp index cfe7b108..99900b7b 100644 --- a/Sources/Core/ConcurrentDispatch.cpp +++ b/Sources/Core/ConcurrentDispatch.cpp @@ -1,21 +1,21 @@ /* Copyright (c) 2013 yvt - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include @@ -50,39 +50,39 @@ DEFINE_SPADES_SETTING(core_numDispatchQueueThreads, "auto"); static int GetNumCores() { #ifdef WIN32 - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; #elif defined(__APPLE__) - int nm[2]; - size_t len = 4; - uint32_t count; - - nm[0] = CTL_HW; nm[1] = HW_AVAILCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - - if(count < 1) { - nm[1] = HW_NCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - if(count < 1) { count = 1; } - } - return count; + int nm[2]; + size_t len = 4; + uint32_t count; + + nm[0] = CTL_HW; nm[1] = HW_AVAILCPU; + sysctl(nm, 2, &count, &len, NULL, 0); + + if(count < 1) { + nm[1] = HW_NCPU; + sysctl(nm, 2, &count, &len, NULL, 0); + if(count < 1) { count = 1; } + } + return count; #elif defined(__linux__) - return get_nprocs(); + return get_nprocs(); #else - return sysconf(_SC_NPROCESSORS_ONLN); + return sysconf(_SC_NPROCESSORS_ONLN); #endif } namespace spades { - + struct SyncQueueEntry{ SDL_cond *doneCond; SDL_mutex *doneMutex; ConcurrentDispatch *dispatch; volatile bool done; volatile bool released; - + SyncQueueEntry(ConcurrentDispatch *disp): doneCond(SDL_CreateCond()), doneMutex(SDL_CreateMutex()), @@ -98,7 +98,7 @@ namespace spades { delete dispatch; } } - + void Done() { SDL_LockMutex(doneMutex); done = true; @@ -109,7 +109,7 @@ namespace spades { } SDL_UnlockMutex(doneMutex); } - + void Release() { SDL_LockMutex(doneMutex); released = true; @@ -119,7 +119,7 @@ namespace spades { } SDL_UnlockMutex(doneMutex); } - + void Join(){ SDL_LockMutex(doneMutex); while(!done){ @@ -128,10 +128,10 @@ namespace spades { SDL_UnlockMutex(doneMutex); } }; - + class SynchronizedQueue { std::list entries; - + SDL_cond *pushCond; SDL_mutex *pushMutex; public: @@ -143,7 +143,7 @@ namespace spades { SDL_DestroyMutex(pushMutex); SDL_DestroyCond(pushCond); } - + void Push(SyncQueueEntry * entry) { SDL_LockMutex(pushMutex); try{ @@ -155,20 +155,20 @@ namespace spades { SDL_CondSignal(pushCond); SDL_UnlockMutex(pushMutex); } - + SyncQueueEntry *Wait() { SDL_LockMutex(pushMutex); while(entries.empty()){ SDL_CondWait(pushCond, pushMutex); } - + SyncQueueEntry *ent = entries.front(); entries.pop_front(); SDL_UnlockMutex(pushMutex); - + return ent; } - + SyncQueueEntry *Poll(){ SDL_LockMutex(pushMutex); if(!entries.empty()){ @@ -181,11 +181,11 @@ namespace spades { return NULL; } }; - + static SynchronizedQueue globalQueue; static AutoDeletedThreadLocalStorage threadQueue("threadDispatchQueue"); static DispatchQueue *sdlQueue = NULL; - + DispatchQueue::DispatchQueue(){ SPADES_MARK_FUNCTION(); internal = new SynchronizedQueue(); @@ -194,7 +194,7 @@ namespace spades { SPADES_MARK_FUNCTION(); delete internal; } - + DispatchQueue *DispatchQueue::GetThreadQueue() { SPADES_MARK_FUNCTION(); DispatchQueue *q = threadQueue; @@ -204,7 +204,7 @@ namespace spades { } return q; } - + void DispatchQueue::ProcessQueue() { SPADES_MARK_FUNCTION(); SyncQueueEntry *ent; @@ -213,19 +213,19 @@ namespace spades { } Thread::CleanupExitedThreads(); } - + void DispatchQueue::EnterEventLoop() throw() { while(true){ SyncQueueEntry *ent = internal->Wait(); ent->dispatch->ExecuteProtected(); - + } } - + void DispatchQueue::MarkSDLVideoThread() { sdlQueue = this; } - + class DispatchThread: public Thread{ public: virtual void Run() throw() { @@ -236,9 +236,9 @@ namespace spades { } } }; - + static std::vector threads; - + ConcurrentDispatch::ConcurrentDispatch(): entry(NULL), runnable(NULL){ SPADES_MARK_FUNCTION(); @@ -247,12 +247,12 @@ namespace spades { entry(NULL),name(name), runnable(NULL){ SPADES_MARK_FUNCTION(); } - + ConcurrentDispatch::~ConcurrentDispatch(){ SPADES_MARK_FUNCTION(); Join(); } - + void ConcurrentDispatch::Execute() { SPADES_MARK_FUNCTION(); SyncQueueEntry *ent = entry; @@ -267,7 +267,7 @@ namespace spades { } ent->Done(); } - + void ConcurrentDispatch::ExecuteProtected() throw() { try{ Execute(); @@ -279,7 +279,7 @@ namespace spades { fprintf(stderr, "(no information provided)\n"); } } - + void ConcurrentDispatch::Start() { SPADES_MARK_FUNCTION(); if(entry){ @@ -302,7 +302,7 @@ namespace spades { globalQueue.Push(entry); } } - + void ConcurrentDispatch::StartOn(DispatchQueue *queue) { SPADES_MARK_FUNCTION(); if(entry){ @@ -310,7 +310,7 @@ namespace spades { }else{ entry = new SyncQueueEntry(this); queue->internal->Push(entry); - + if(queue == sdlQueue) { SDL_Event evt; memset(&evt, 0, sizeof(evt)); @@ -319,7 +319,7 @@ namespace spades { } } } - + void ConcurrentDispatch::Join() { SPADES_MARK_FUNCTION(); if(!entry){ @@ -329,7 +329,7 @@ namespace spades { entry = NULL; } } - + void ConcurrentDispatch::Release(){ SPADES_MARK_FUNCTION(); if(entry){ @@ -337,7 +337,7 @@ namespace spades { ent->Release(); } } - + void ConcurrentDispatch::Run(){ if(runnable) runnable->Run(); diff --git a/Sources/Core/FileManager.cpp b/Sources/Core/FileManager.cpp index 0940c0bb..84002ba7 100644 --- a/Sources/Core/FileManager.cpp +++ b/Sources/Core/FileManager.cpp @@ -1,21 +1,21 @@ /* Copyright (c) 2013 yvt - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "FileManager.h" @@ -32,20 +32,20 @@ namespace spades { SPADES_MARK_FUNCTION(); if(!fn) SPInvalidArgument("fn"); if(fn[0] == 0) SPFileNotFound(fn); - - // check each file systems + + // check each file systems for(auto *fs: g_fileSystems){ if(fs->FileExists(fn)) return fs->OpenForReading(fn); } - - // check weak files, too - auto weak_fn = std::string(fn) + ".weak"; - for(auto *fs: g_fileSystems){ - if(fs->FileExists(weak_fn.c_str())) - return fs->OpenForReading(weak_fn.c_str()); - } - + + // check weak files, too + auto weak_fn = std::string(fn) + ".weak"; + for(auto *fs: g_fileSystems){ + if(fs->FileExists(weak_fn.c_str())) + return fs->OpenForReading(weak_fn.c_str()); + } + SPFileNotFound(fn); } IStream *FileManager::OpenForWriting(const char *fn) { @@ -56,9 +56,9 @@ namespace spades { if(fs->FileExists(fn)) return fs->OpenForWriting(fn); } - - // FIXME: handling of weak files - + + // FIXME: handling of weak files + // create file for(auto *fs: g_fileSystems){ try{ @@ -66,50 +66,50 @@ namespace spades { }catch(...){ } } - + SPRaise("No filesystem is writable"); } bool FileManager::FileExists(const char *fn) { SPADES_MARK_FUNCTION(); if(!fn) SPInvalidArgument("fn"); - + for(auto *fs: g_fileSystems){ if(fs->FileExists(fn)) return true; - } - - // check weak files, too - auto weak_fn = std::string(fn) + ".weak"; - for(auto *fs: g_fileSystems){ - if(fs->FileExists(weak_fn.c_str())) - return true; - } - + } + + // check weak files, too + auto weak_fn = std::string(fn) + ".weak"; + for(auto *fs: g_fileSystems){ + if(fs->FileExists(weak_fn.c_str())) + return true; + } + return false; } - + void FileManager::AddFileSystem(spades::IFileSystem *fs){ SPADES_MARK_FUNCTION(); AppendFileSystem(fs); } - - + + void FileManager::AppendFileSystem(spades::IFileSystem *fs){ SPADES_MARK_FUNCTION(); if(!fs) SPInvalidArgument("fs"); - + g_fileSystems.push_back(fs); } void FileManager::PrependFileSystem(spades::IFileSystem *fs){ SPADES_MARK_FUNCTION(); if(!fs) SPInvalidArgument("fs"); - + g_fileSystems.push_front(fs); } - + std::string FileManager::ReadAllBytes(const char *fn) { SPADES_MARK_FUNCTION(); - + IStream *stream = OpenForReading(fn); try{ std::string ret = stream->ReadAllBytes(); @@ -120,23 +120,23 @@ namespace spades { throw; } } - + std::vector FileManager::EnumFiles(const char *path) { std::vector list; std::set set; if(!path) SPInvalidArgument("path"); - + for(auto *fs: g_fileSystems){ std::vector l = fs->EnumFiles(path); for(size_t i = 0; i < l.size(); i++) set.insert(l[i]); } - + for(auto& s: set) list.push_back(s); - + return list; } - + } diff --git a/Sources/ScriptBindings/Config.cpp b/Sources/ScriptBindings/Config.cpp index eb269135..196dc435 100644 --- a/Sources/ScriptBindings/Config.cpp +++ b/Sources/ScriptBindings/Config.cpp @@ -1,21 +1,21 @@ /* Copyright (c) 2013 yvt - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "ScriptManager.h" @@ -25,28 +25,28 @@ #include namespace spades { - - namespace - { - ThreadLocalStorage writeAllowed; - - // SettingItemDescriptor supplied to ItemHandle must have the static storage duration - std::unordered_map - settingItemDescriptors; - - const SettingItemDescriptor *MakeSettingItemDescriptor - (const std::string &name, const std::string &defaultValue) - { - auto it = settingItemDescriptors.find(name); - if (it != settingItemDescriptors.end()) { - return it->second; - } - auto *descriptor = new SettingItemDescriptor(defaultValue, SettingItemFlags::None); - settingItemDescriptors.insert(make_pair(name, descriptor)); - return descriptor; - } - } - + + namespace + { + ThreadLocalStorage writeAllowed; + + // SettingItemDescriptor supplied to ItemHandle must have the static storage duration + std::unordered_map + settingItemDescriptors; + + const SettingItemDescriptor *MakeSettingItemDescriptor + (const std::string &name, const std::string &defaultValue) + { + auto it = settingItemDescriptors.find(name); + if (it != settingItemDescriptors.end()) { + return it->second; + } + auto *descriptor = new SettingItemDescriptor(defaultValue, SettingItemFlags::None); + settingItemDescriptors.insert(make_pair(name, descriptor)); + return descriptor; + } + } + void MaskConfigUpdateByScript(bool disabled) { if (!writeAllowed) { @@ -54,32 +54,32 @@ namespace spades { } *writeAllowed = !disabled; } - - + + class ConfigRegistrar: public ScriptObjectRegistrar { - - + + public: ConfigRegistrar(): ScriptObjectRegistrar("Config") {} - + class ConfigItem: public RefCountedObject { Settings::ItemHandle handle; - public: - ConfigItem(const std::string& name, const std::string& defaultValue): - handle(name, MakeSettingItemDescriptor(name, defaultValue)){ - } - ConfigItem(const std::string& name): - handle(name, nullptr){ - } - + public: + ConfigItem(const std::string& name, const std::string& defaultValue): + handle(name, MakeSettingItemDescriptor(name, defaultValue)){ + } + ConfigItem(const std::string& name): + handle(name, nullptr){ + } + static ConfigItem *Construct(const std::string& name, const std::string& defaultValue) { return new ConfigItem(name, defaultValue); } static ConfigItem *Construct(const std::string& name) { return new ConfigItem(name); } - + ConfigItem *operator =(float fv) { if (!writeAllowed || !*writeAllowed) { return this; @@ -92,7 +92,7 @@ namespace spades { if (!writeAllowed || !*writeAllowed) { return this; } - + handle = v; AddRef(); return this; @@ -101,7 +101,7 @@ namespace spades { if (!writeAllowed || !*writeAllowed) { return this; } - + handle = v; AddRef(); return this; @@ -128,12 +128,12 @@ namespace spades { return (std::string)handle; } }; - + static CScriptArray *GetAllConfigNames() { auto *ctx = asGetActiveContext(); auto *engine = ctx->GetEngine(); auto *arrayType = engine->GetTypeInfoByDecl("array"); - auto *array = CScriptArray::Create(arrayType); + auto *array = CScriptArray::Create(arrayType); auto names = Settings::GetInstance()->GetAllItemNames(); array->Resize(static_cast(names.size())); for(std::size_t i = 0; i < names.size(); i++) { @@ -141,7 +141,7 @@ namespace spades { } return array; } - + virtual void Register(ScriptManager *manager, Phase phase) { asIScriptEngine *eng = manager->GetEngine(); int r; @@ -222,7 +222,7 @@ namespace spades { asMETHOD(ConfigItem, GetStringValue), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterGlobalFunction("array@ GetAllConfigNames()", asFUNCTION(GetAllConfigNames), asCALL_CDECL); @@ -233,8 +233,8 @@ namespace spades { } } }; - + static ConfigRegistrar registrar; - + } diff --git a/Sources/ScriptBindings/PrimitiveArray.cpp b/Sources/ScriptBindings/PrimitiveArray.cpp index 87a32d73..d4c75c43 100644 --- a/Sources/ScriptBindings/PrimitiveArray.cpp +++ b/Sources/ScriptBindings/PrimitiveArray.cpp @@ -1,21 +1,21 @@ /* Copyright (c) 2013 yvt - + This file is part of OpenSpades. - + 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. - + 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. - + You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . - + */ #include "ScriptManager.h" @@ -46,45 +46,45 @@ namespace spades { ArrayType *obj = new ArrayType(initialSize); asGetActiveContext()->GetEngine()->NotifyGarbageCollectorOfNewObject(obj, scrType); return obj; - } - static ArrayType *Factory3(asUINT initialSize, T initialValue) { - if(initialSize > 1024 * 1024 * 256) { - asGetActiveContext()->SetException("Too many array elements"); - return NULL; - } - ArrayType *obj = new ArrayType(initialSize, initialValue); - asGetActiveContext()->GetEngine()->NotifyGarbageCollectorOfNewObject(obj, scrType); - return obj; - } - static ArrayType *Factory4(void *initList) { - asUINT length = *reinterpret_cast(initList); - if(length > 1024 * 1024 * 256) { - asGetActiveContext()->SetException("Too many array elements"); - } - ArrayType *obj = new ArrayType(initList); - asGetActiveContext()->GetEngine()->NotifyGarbageCollectorOfNewObject(obj, scrType); - return obj; - } - + } + static ArrayType *Factory3(asUINT initialSize, T initialValue) { + if(initialSize > 1024 * 1024 * 256) { + asGetActiveContext()->SetException("Too many array elements"); + return NULL; + } + ArrayType *obj = new ArrayType(initialSize, initialValue); + asGetActiveContext()->GetEngine()->NotifyGarbageCollectorOfNewObject(obj, scrType); + return obj; + } + static ArrayType *Factory4(void *initList) { + asUINT length = *reinterpret_cast(initList); + if(length > 1024 * 1024 * 256) { + asGetActiveContext()->SetException("Too many array elements"); + } + ArrayType *obj = new ArrayType(initList); + asGetActiveContext()->GetEngine()->NotifyGarbageCollectorOfNewObject(obj, scrType); + return obj; + } + PrimitiveArray(asUINT initialSize = 0) { inner.resize(initialSize); - } - PrimitiveArray(asUINT initialSize, T initialValue) { - inner.resize(initialSize, initialValue); - } - PrimitiveArray(void *initList) { - asUINT length = *reinterpret_cast(initList); - inner.resize(length); - memcpy(inner.data(), reinterpret_cast(initList) + 1, inner.size() * sizeof(T)); - } - + } + PrimitiveArray(asUINT initialSize, T initialValue) { + inner.resize(initialSize, initialValue); + } + PrimitiveArray(void *initList) { + asUINT length = *reinterpret_cast(initList); + inner.resize(length); + memcpy(inner.data(), reinterpret_cast(initList) + 1, inner.size() * sizeof(T)); + } + void AddRef() { refCount &= 0x7fffffff; asAtomicInc(refCount); } void Release() { refCount &= 0x7fffffff; - + if(asAtomicDec(refCount) <= 0) delete this; } @@ -99,7 +99,7 @@ namespace spades { } void EnumReferences(asIScriptEngine *eng) {} void ReleaseAllReferences(asIScriptEngine *eng){} - + T& At(asUINT index) { if(index >= inner.size()){ asGetActiveContext()->SetException("Index out of bounds"); @@ -160,7 +160,7 @@ namespace spades { inner.reserve((size_t)siz); } } - + void SortAsc(asUINT index, asUINT count){ if(count <= 0) return; if(index + count > inner.size()){ @@ -186,24 +186,24 @@ namespace spades { void SortDesc() { SortDesc(0, GetSize()); } - + void Reverse() { std::reverse(inner.begin(), inner.end()); } - + int Find(const T& val) const { typename std::vector::const_iterator it = std::find(inner.begin(), inner.end(), val); if(it == inner.end()) return -1; return static_cast (it - inner.begin()); } - + int Find(asUINT ind, const T& val) const { if(ind >= GetSize()) return -1; typename std::vector::const_iterator it = std::find(inner.begin() + ind, inner.end(), val); if(it == inner.end()) return -1; return static_cast (it - inner.begin()); } - + bool operator ==(const ArrayType& array) const { if(this == &array) return true; @@ -215,13 +215,13 @@ namespace spades { return false; return true; } - + bool IsEmpty() const { return inner.empty(); } - + }; - + template class PrimitiveArrayRegistrar: public ScriptObjectRegistrar { std::string typeName; @@ -304,154 +304,154 @@ namespace spades { F("void f(int& in)"), asMETHOD(ArrayType, ReleaseAllReferences), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("%s& opIndex(uint)"), asMETHODPR(ArrayType, At, (asUINT), T&), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("const %s& opIndex(uint) const"), asMETHODPR(ArrayType, At, (asUINT) const, const T&), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("array<%s> &opAssign(const array<%s>&)"), asMETHODPR(ArrayType, operator =, (const ArrayType&), ArrayType&), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void insertAt(uint, const %s& in)"), asMETHODPR(ArrayType, InsertAt, (asUINT, const T&), void), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void removeAt(uint)"), asMETHOD(ArrayType, RemoveAt), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void insertLast(const %s& in)"), asMETHOD(ArrayType, InsertLast), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void removeLast()"), asMETHOD(ArrayType, RemoveLast), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("uint length()"), asMETHOD(ArrayType, GetSize), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void resize(uint)"), asMETHOD(ArrayType, Resize), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void reserve(uint)"), asMETHOD(ArrayType, Reserve), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void sortAsc()"), asMETHODPR(ArrayType, SortAsc, (), void), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void sortAsc(uint, uint)"), asMETHODPR(ArrayType, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void sortDesc()"), asMETHODPR(ArrayType, SortDesc, (), void), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void sortDesc(uint, uint)"), asMETHODPR(ArrayType, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("int find(const %s& in) const"), asMETHODPR(ArrayType, Find, (const T&) const, int), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("int find(uint, const %s& in) const"), asMETHODPR(ArrayType, Find, (asUINT, const T&) const, int), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("bool opEquals(const array<%s>&) const"), asMETHODPR(ArrayType, operator ==, (const ArrayType&) const, bool), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("uint get_length()"), asMETHOD(ArrayType, GetSize), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void set_length(uint)"), asMETHOD(ArrayType, Resize), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("bool isEmpty()"), asMETHOD(ArrayType, IsEmpty), asCALL_THISCALL); manager->CheckError(r); - + // STL name - + r = eng->RegisterObjectMethod(ATN(), F("uint size()"), asMETHOD(ArrayType, GetSize), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("bool empty()"), asMETHOD(ArrayType, IsEmpty), asCALL_THISCALL); manager->CheckError(r); - - + + r = eng->RegisterObjectMethod(ATN(), F("void push_back(const %s& in)"), asMETHOD(ArrayType, InsertLast), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void pop_back()"), asMETHOD(ArrayType, RemoveLast), asCALL_THISCALL); manager->CheckError(r); - + r = eng->RegisterObjectMethod(ATN(), F("void erase(uint)"), asMETHOD(ArrayType, RemoveAt), @@ -474,5 +474,5 @@ namespace spades { static PrimitiveArrayRegistrar uint64ArrayRegistrar("uint64"); static PrimitiveArrayRegistrar floatArrayRegistrar("float"); static PrimitiveArrayRegistrar doubleArrayRegistrar("double"); - + } diff --git a/Sources/Tools/BdfToOSFont.cpp b/Sources/Tools/BdfToOSFont.cpp index fcf896bd..37b7395e 100644 --- a/Sources/Tools/BdfToOSFont.cpp +++ b/Sources/Tools/BdfToOSFont.cpp @@ -55,15 +55,15 @@ typedef unsigned __int32 uint32_t; /* Targa image and header fields -------------------------------------------*/ typedef struct { - /* Note that Targa is stored in little-endian order */ - uint8_t image_id_length; - - uint8_t color_map_type; - /* color map = palette */ + /* Note that Targa is stored in little-endian order */ + uint8_t image_id_length; + + uint8_t color_map_type; + /* color map = palette */ #define TGA_COLOR_MAP_ABSENT 0 #define TGA_COLOR_MAP_PRESENT 1 - - uint8_t image_type; + + uint8_t image_type; #define TGA_IMAGE_TYPE_NONE 0 /* no image data */ #define TGA_IMAGE_TYPE_COLORMAP 1 /* uncompressed, color-mapped */ #define TGA_IMAGE_TYPE_BGR 2 /* uncompressed, true-color */ @@ -71,49 +71,49 @@ typedef struct #define TGA_IMAGE_TYPE_COLORMAP_RLE 9 /* run-length, color-mapped */ #define TGA_IMAGE_TYPE_BGR_RLE 10 /* run-length, true-color */ #define TGA_IMAGE_TYPE_MONO_RLE 11 /* run-length, black and white */ - - /* color map specification */ - uint16_t color_map_origin; /* index of first entry */ - uint16_t color_map_length; /* number of entries included */ - uint8_t color_map_depth; /* number of bits per entry */ - - /* image specification */ - uint16_t origin_x; - uint16_t origin_y; - uint16_t width; - uint16_t height; - uint8_t pixel_depth; - - uint8_t image_descriptor; - /* bits 0,1,2,3 - attribute bits per pixel - * bit 4 - set if image is stored right-to-left - * bit 5 - set if image is stored top-to-bottom - * bits 6,7 - unused (must be set to zero) - */ + + /* color map specification */ + uint16_t color_map_origin; /* index of first entry */ + uint16_t color_map_length; /* number of entries included */ + uint8_t color_map_depth; /* number of bits per entry */ + + /* image specification */ + uint16_t origin_x; + uint16_t origin_y; + uint16_t width; + uint16_t height; + uint8_t pixel_depth; + + uint8_t image_descriptor; + /* bits 0,1,2,3 - attribute bits per pixel + * bit 4 - set if image is stored right-to-left + * bit 5 - set if image is stored top-to-bottom + * bits 6,7 - unused (must be set to zero) + */ #define TGA_ATTRIB_BITS (uint8_t)(BIT(0)|BIT(1)|BIT(2)|BIT(3)) #define TGA_R_TO_L_BIT (uint8_t)BIT(4) #define TGA_T_TO_B_BIT (uint8_t)BIT(5) #define TGA_UNUSED_BITS (uint8_t)(BIT(6)|BIT(7)) - /* Note: right-to-left order is not honored by some Targa readers */ - - uint8_t *image_id; - /* The length of this field is given in image_id_length, it's read raw - * from the file so it's not not guaranteed to be zero-terminated. If - * it's not NULL, it needs to be deallocated. see: tga_free_buffers() - */ - - uint8_t *color_map_data; - /* See the "color map specification" fields above. If not NULL, this - * field needs to be deallocated. see: tga_free_buffers() - */ - - uint8_t *image_data; - /* Follows image specification fields (see above) */ - - /* Extension area and developer area are silently ignored. The Targa 2.0 - * spec says we're not required to read or write them. - */ - + /* Note: right-to-left order is not honored by some Targa readers */ + + uint8_t *image_id; + /* The length of this field is given in image_id_length, it's read raw + * from the file so it's not not guaranteed to be zero-terminated. If + * it's not NULL, it needs to be deallocated. see: tga_free_buffers() + */ + + uint8_t *color_map_data; + /* See the "color map specification" fields above. If not NULL, this + * field needs to be deallocated. see: tga_free_buffers() + */ + + uint8_t *image_data; + /* Follows image specification fields (see above) */ + + /* Extension area and developer area are silently ignored. The Targa 2.0 + * spec says we're not required to read or write them. + */ + } tga_image; @@ -130,24 +130,24 @@ int tga_is_mono(const tga_image *tga); /* Error handling ----------------------------------------------------------*/ typedef enum { - TGA_NOERR, - TGAERR_FOPEN, - TGAERR_EOF, - TGAERR_WRITE, - TGAERR_CMAP_TYPE, - TGAERR_IMG_TYPE, - TGAERR_NO_IMG, - TGAERR_CMAP_MISSING, - TGAERR_CMAP_PRESENT, - TGAERR_CMAP_LENGTH, - TGAERR_CMAP_DEPTH, - TGAERR_ZERO_SIZE, - TGAERR_PIXEL_DEPTH, - TGAERR_NO_MEM, - TGAERR_NOT_CMAP, - TGAERR_RLE, - TGAERR_INDEX_RANGE, - TGAERR_MONO + TGA_NOERR, + TGAERR_FOPEN, + TGAERR_EOF, + TGAERR_WRITE, + TGAERR_CMAP_TYPE, + TGAERR_IMG_TYPE, + TGAERR_NO_IMG, + TGAERR_CMAP_MISSING, + TGAERR_CMAP_PRESENT, + TGAERR_CMAP_LENGTH, + TGAERR_CMAP_DEPTH, + TGAERR_ZERO_SIZE, + TGAERR_PIXEL_DEPTH, + TGAERR_NO_MEM, + TGAERR_NOT_CMAP, + TGAERR_RLE, + TGAERR_INDEX_RANGE, + TGAERR_MONO } tga_result; const char *tga_error(const tga_result errcode); @@ -242,22 +242,22 @@ static uint8_t rle_packet_len(const uint8_t *row, const uint16_t pos, uint8_t tga_get_attribute_bits(const tga_image *tga) { - return tga->image_descriptor & TGA_ATTRIB_BITS; + return tga->image_descriptor & TGA_ATTRIB_BITS; } int tga_is_right_to_left(const tga_image *tga) { - return (tga->image_descriptor & TGA_R_TO_L_BIT) != 0; + return (tga->image_descriptor & TGA_R_TO_L_BIT) != 0; } int tga_is_top_to_bottom(const tga_image *tga) { - return (tga->image_descriptor & TGA_T_TO_B_BIT) != 0; + return (tga->image_descriptor & TGA_T_TO_B_BIT) != 0; } int tga_is_colormapped(const tga_image *tga) { - return ( + return ( tga->image_type == TGA_IMAGE_TYPE_COLORMAP || tga->image_type == TGA_IMAGE_TYPE_COLORMAP_RLE ); @@ -265,7 +265,7 @@ int tga_is_colormapped(const tga_image *tga) int tga_is_rle(const tga_image *tga) { - return ( + return ( tga->image_type == TGA_IMAGE_TYPE_COLORMAP_RLE || tga->image_type == TGA_IMAGE_TYPE_BGR_RLE || tga->image_type == TGA_IMAGE_TYPE_MONO_RLE @@ -274,7 +274,7 @@ int tga_is_rle(const tga_image *tga) int tga_is_mono(const tga_image *tga) { - return ( + return ( tga->image_type == TGA_IMAGE_TYPE_MONO || tga->image_type == TGA_IMAGE_TYPE_MONO_RLE ); @@ -289,8 +289,8 @@ int tga_is_mono(const tga_image *tga) */ const char *tga_error(const tga_result errcode) { - switch (errcode) - { + switch (errcode) + { case TGA_NOERR: return "no error"; case TGAERR_FOPEN: @@ -329,7 +329,7 @@ const char *tga_error(const tga_result errcode) return "image is mono"; default: return "unknown error code"; - } + } } @@ -345,111 +345,111 @@ tga_result tga_read_from_FILE(tga_image *dest, std::istream& fp) { #define BARF(errcode) \ { tga_free_buffers(dest); return errcode; } - + #define READ(destptr, size) \ if(fp.readsome(reinterpret_cast(destptr), size) < size) BARF(TGAERR_EOF) //if (fread(destptr, size, 1, fp) != 1) BARF(TGAERR_EOF) - + #define READ16(dest) \ { if (fp.readsome(reinterpret_cast(&dest), 2) != 2) BARF(TGAERR_EOF); \ dest = letoh16(dest); } //{ if (fread(&(dest), 2, 1, fp) != 1) BARF(TGAERR_EOF); \ //dest = letoh16(dest); } - - dest->image_id = NULL; - dest->color_map_data = NULL; - dest->image_data = NULL; - - READ(&dest->image_id_length,1); - READ(&dest->color_map_type,1); - if (dest->color_map_type != TGA_COLOR_MAP_ABSENT && - dest->color_map_type != TGA_COLOR_MAP_PRESENT) + + dest->image_id = NULL; + dest->color_map_data = NULL; + dest->image_data = NULL; + + READ(&dest->image_id_length,1); + READ(&dest->color_map_type,1); + if (dest->color_map_type != TGA_COLOR_MAP_ABSENT && + dest->color_map_type != TGA_COLOR_MAP_PRESENT) BARF(TGAERR_CMAP_TYPE); - - READ(&dest->image_type, 1); - if (dest->image_type == TGA_IMAGE_TYPE_NONE) + + READ(&dest->image_type, 1); + if (dest->image_type == TGA_IMAGE_TYPE_NONE) BARF(TGAERR_NO_IMG); - - if (dest->image_type != TGA_IMAGE_TYPE_COLORMAP && - dest->image_type != TGA_IMAGE_TYPE_BGR && - dest->image_type != TGA_IMAGE_TYPE_MONO && - dest->image_type != TGA_IMAGE_TYPE_COLORMAP_RLE && - dest->image_type != TGA_IMAGE_TYPE_BGR_RLE && - dest->image_type != TGA_IMAGE_TYPE_MONO_RLE) + + if (dest->image_type != TGA_IMAGE_TYPE_COLORMAP && + dest->image_type != TGA_IMAGE_TYPE_BGR && + dest->image_type != TGA_IMAGE_TYPE_MONO && + dest->image_type != TGA_IMAGE_TYPE_COLORMAP_RLE && + dest->image_type != TGA_IMAGE_TYPE_BGR_RLE && + dest->image_type != TGA_IMAGE_TYPE_MONO_RLE) BARF(TGAERR_IMG_TYPE); - - if (tga_is_colormapped(dest) && - dest->color_map_type == TGA_COLOR_MAP_ABSENT) + + if (tga_is_colormapped(dest) && + dest->color_map_type == TGA_COLOR_MAP_ABSENT) BARF(TGAERR_CMAP_MISSING); - - if (!tga_is_colormapped(dest) && - dest->color_map_type == TGA_COLOR_MAP_PRESENT) + + if (!tga_is_colormapped(dest) && + dest->color_map_type == TGA_COLOR_MAP_PRESENT) BARF(TGAERR_CMAP_PRESENT); - - READ16(dest->color_map_origin); - READ16(dest->color_map_length); - READ(&dest->color_map_depth, 1); - if (dest->color_map_type == TGA_COLOR_MAP_PRESENT) - { - if (dest->color_map_length == 0) - BARF(TGAERR_CMAP_LENGTH); - - if (!UNMAP_DEPTH(dest->color_map_depth)) - BARF(TGAERR_CMAP_DEPTH); - } - - READ16(dest->origin_x); - READ16(dest->origin_y); - READ16(dest->width); - READ16(dest->height); - - if (dest->width == 0 || dest->height == 0) + + READ16(dest->color_map_origin); + READ16(dest->color_map_length); + READ(&dest->color_map_depth, 1); + if (dest->color_map_type == TGA_COLOR_MAP_PRESENT) + { + if (dest->color_map_length == 0) + BARF(TGAERR_CMAP_LENGTH); + + if (!UNMAP_DEPTH(dest->color_map_depth)) + BARF(TGAERR_CMAP_DEPTH); + } + + READ16(dest->origin_x); + READ16(dest->origin_y); + READ16(dest->width); + READ16(dest->height); + + if (dest->width == 0 || dest->height == 0) BARF(TGAERR_ZERO_SIZE); - - READ(&dest->pixel_depth, 1); - if (!SANE_DEPTH(dest->pixel_depth) || + + READ(&dest->pixel_depth, 1); + if (!SANE_DEPTH(dest->pixel_depth) || (dest->pixel_depth != 8 && tga_is_colormapped(dest)) ) BARF(TGAERR_PIXEL_DEPTH); - - READ(&dest->image_descriptor, 1); - - if (dest->image_id_length > 0) - { - dest->image_id = (uint8_t*)malloc(dest->image_id_length); - if (dest->image_id == NULL) BARF(TGAERR_NO_MEM); - READ(dest->image_id, dest->image_id_length); - } - - if (dest->color_map_type == TGA_COLOR_MAP_PRESENT) - { - dest->color_map_data = (uint8_t*)malloc( + + READ(&dest->image_descriptor, 1); + + if (dest->image_id_length > 0) + { + dest->image_id = (uint8_t*)malloc(dest->image_id_length); + if (dest->image_id == NULL) BARF(TGAERR_NO_MEM); + READ(dest->image_id, dest->image_id_length); + } + + if (dest->color_map_type == TGA_COLOR_MAP_PRESENT) + { + dest->color_map_data = (uint8_t*)malloc( (dest->color_map_origin + dest->color_map_length) * dest->color_map_depth / 8); - if (dest->color_map_data == NULL) BARF(TGAERR_NO_MEM); - READ(dest->color_map_data + + if (dest->color_map_data == NULL) BARF(TGAERR_NO_MEM); + READ(dest->color_map_data + (dest->color_map_origin * dest->color_map_depth / 8), dest->color_map_length * dest->color_map_depth / 8); - } - - dest->image_data = (uint8_t*) malloc( + } + + dest->image_data = (uint8_t*) malloc( dest->width * dest->height * dest->pixel_depth / 8); - if (dest->image_data == NULL) + if (dest->image_data == NULL) BARF(TGAERR_NO_MEM); - - if (tga_is_rle(dest)) - { - /* read RLE */ - tga_result result = tga_read_rle(dest, fp); - if (result != TGA_NOERR) BARF(result); - } - else - { - /* uncompressed */ - READ(dest->image_data, + + if (tga_is_rle(dest)) + { + /* read RLE */ + tga_result result = tga_read_rle(dest, fp); + if (result != TGA_NOERR) BARF(result); + } + else + { + /* uncompressed */ + READ(dest->image_data, dest->width * dest->height * dest->pixel_depth / 8); - } - - return TGA_NOERR; + } + + return TGA_NOERR; #undef BARF #undef READ #undef READ16 @@ -466,47 +466,47 @@ static tga_result tga_read_rle(tga_image *dest, std::istream& fp) #define RLE_BIT BIT(7) #define READ(dest, size) \ if (fp.readsome(reinterpret_cast(dest), size) != size) return TGAERR_EOF - - uint8_t *pos; - uint32_t p_loaded = 0, + + uint8_t *pos; + uint32_t p_loaded = 0, p_expected = dest->width * dest->height; - uint8_t bpp = dest->pixel_depth/8; /* bytes per pixel */ - - pos = dest->image_data; - - while ((p_loaded < p_expected)/* && !feof(fp)*/) - { - uint8_t b; - READ(&b, 1); - if (b & RLE_BIT) - { - /* is an RLE packet */ - uint8_t count, tmp[4], i; - - count = (b & ~RLE_BIT) + 1; - READ(tmp, bpp); - - for (i=0; i p_expected) return TGAERR_RLE; - memcpy(pos, tmp, bpp); - pos += bpp; - } - } - else /* RAW packet */ - { - uint8_t count; - - count = (b & ~RLE_BIT) + 1; - if (p_loaded + count > p_expected) return TGAERR_RLE; - - p_loaded += count; - READ(pos, bpp*count); - pos += count * bpp; - } - } - return TGA_NOERR; + uint8_t bpp = dest->pixel_depth/8; /* bytes per pixel */ + + pos = dest->image_data; + + while ((p_loaded < p_expected)/* && !feof(fp)*/) + { + uint8_t b; + READ(&b, 1); + if (b & RLE_BIT) + { + /* is an RLE packet */ + uint8_t count, tmp[4], i; + + count = (b & ~RLE_BIT) + 1; + READ(tmp, bpp); + + for (i=0; i p_expected) return TGAERR_RLE; + memcpy(pos, tmp, bpp); + pos += bpp; + } + } + else /* RAW packet */ + { + uint8_t count; + + count = (b & ~RLE_BIT) + 1; + if (p_loaded + count > p_expected) return TGAERR_RLE; + + p_loaded += count; + READ(pos, bpp*count); + pos += count * bpp; + } + } + return TGA_NOERR; #undef RLE_BIT #undef READ } @@ -525,35 +525,35 @@ static tga_result tga_write_row_RLE(std::ostream& fp, { #define WRITE(src, size) \ fp.write(reinterpret_cast(src), size) - + //if (fwrite(src, size, 1, fp) != 1) return TGAERR_WRITE - - uint16_t pos = 0; - uint16_t bpp = src->pixel_depth / 8; - - while (pos < src->width) - { - packet_type type = rle_packet_type(row, pos, src->width, bpp); - uint8_t len = rle_packet_len(row, pos, src->width, bpp, type); - uint8_t packet_header; - - packet_header = len - 1; - if (type == RLE) packet_header |= BIT(7); - - WRITE(&packet_header, 1); - if (type == RLE) - { - WRITE(PIXEL(pos), bpp); - } - else /* type == RAW */ - { - WRITE(PIXEL(pos), bpp*len); - } - - pos += len; - } - - return TGA_NOERR; + + uint16_t pos = 0; + uint16_t bpp = src->pixel_depth / 8; + + while (pos < src->width) + { + packet_type type = rle_packet_type(row, pos, src->width, bpp); + uint8_t len = rle_packet_len(row, pos, src->width, bpp, type); + uint8_t packet_header; + + packet_header = len - 1; + if (type == RLE) packet_header |= BIT(7); + + WRITE(&packet_header, 1); + if (type == RLE) + { + WRITE(PIXEL(pos), bpp); + } + else /* type == RAW */ + { + WRITE(PIXEL(pos), bpp*len); + } + + pos += len; + } + + return TGA_NOERR; #undef WRITE } @@ -569,15 +569,15 @@ fp.write(reinterpret_cast(src), size) static packet_type rle_packet_type(const uint8_t *row, const uint16_t pos, const uint16_t width, const uint16_t bpp) { - if (pos == width - 1) return RAW; /* one pixel */ - if (SAME(pos,pos+1)) /* dupe pixel */ - { - if (bpp > 1) return RLE; /* inefficient for bpp=1 */ - - /* three repeats makes the bpp=1 case efficient enough */ - if ((pos < width - 2) && SAME(pos+1,pos+2)) return RLE; - } - return RAW; + if (pos == width - 1) return RAW; /* one pixel */ + if (SAME(pos,pos+1)) /* dupe pixel */ + { + if (bpp > 1) return RLE; /* inefficient for bpp=1 */ + + /* three repeats makes the bpp=1 case efficient enough */ + if ((pos < width - 2) && SAME(pos+1,pos+2)) return RLE; + } + return RAW; } @@ -589,35 +589,35 @@ static packet_type rle_packet_type(const uint8_t *row, const uint16_t pos, static uint8_t rle_packet_len(const uint8_t *row, const uint16_t pos, const uint16_t width, const uint16_t bpp, const packet_type type) { - uint8_t len = 2; - - if (pos == width - 1) return 1; - if (pos == width - 2) return 2; - - if (type == RLE) - { - while (pos + len < width) - { - if (SAME(pos, pos+len)) - len++; - else - return len; - - if (len == 128) return 128; - } - } - else /* type == RAW */ - { - while (pos + len < width) - { - if (rle_packet_type(row, pos+len, width, bpp) == RAW) - len++; - else - return len; - if (len == 128) return 128; - } - } - return len; /* hit end of row (width) */ + uint8_t len = 2; + + if (pos == width - 1) return 1; + if (pos == width - 2) return 2; + + if (type == RLE) + { + while (pos + len < width) + { + if (SAME(pos, pos+len)) + len++; + else + return len; + + if (len == 128) return 128; + } + } + else /* type == RAW */ + { + while (pos + len < width) + { + if (rle_packet_type(row, pos+len, width, bpp) == RAW) + len++; + else + return len; + if (len == 128) return 128; + } + } + return len; /* hit end of row (width) */ } #undef SAME #undef PIXEL @@ -637,92 +637,92 @@ tga_result tga_write_to_FILE(std::ostream& fp, const tga_image *src) fp.write(reinterpret_cast(srcptr), size) //fp->Write(srcptr, size) //if (fwrite(srcptr, size, 1, fp) != 1) return TGAERR_WRITE - + #define WRITE16(src) \ { uint16_t _temp = htole16(src); \ fp.write(reinterpret_cast(&_temp), 2); } - + //if (fwrite(&_temp, 2, 1, fp) != 1) return TGAERR_WRITE; } - - WRITE(&src->image_id_length, 1); - - if (src->color_map_type != TGA_COLOR_MAP_ABSENT && - src->color_map_type != TGA_COLOR_MAP_PRESENT) + + WRITE(&src->image_id_length, 1); + + if (src->color_map_type != TGA_COLOR_MAP_ABSENT && + src->color_map_type != TGA_COLOR_MAP_PRESENT) return TGAERR_CMAP_TYPE; - WRITE(&src->color_map_type, 1); - - if (src->image_type == TGA_IMAGE_TYPE_NONE) + WRITE(&src->color_map_type, 1); + + if (src->image_type == TGA_IMAGE_TYPE_NONE) return TGAERR_NO_IMG; - if (src->image_type != TGA_IMAGE_TYPE_COLORMAP && - src->image_type != TGA_IMAGE_TYPE_BGR && - src->image_type != TGA_IMAGE_TYPE_MONO && - src->image_type != TGA_IMAGE_TYPE_COLORMAP_RLE && - src->image_type != TGA_IMAGE_TYPE_BGR_RLE && - src->image_type != TGA_IMAGE_TYPE_MONO_RLE) + if (src->image_type != TGA_IMAGE_TYPE_COLORMAP && + src->image_type != TGA_IMAGE_TYPE_BGR && + src->image_type != TGA_IMAGE_TYPE_MONO && + src->image_type != TGA_IMAGE_TYPE_COLORMAP_RLE && + src->image_type != TGA_IMAGE_TYPE_BGR_RLE && + src->image_type != TGA_IMAGE_TYPE_MONO_RLE) return TGAERR_IMG_TYPE; - WRITE(&src->image_type, 1); - - if (tga_is_colormapped(src) && - src->color_map_type == TGA_COLOR_MAP_ABSENT) + WRITE(&src->image_type, 1); + + if (tga_is_colormapped(src) && + src->color_map_type == TGA_COLOR_MAP_ABSENT) return TGAERR_CMAP_MISSING; - if (!tga_is_colormapped(src) && - src->color_map_type == TGA_COLOR_MAP_PRESENT) + if (!tga_is_colormapped(src) && + src->color_map_type == TGA_COLOR_MAP_PRESENT) return TGAERR_CMAP_PRESENT; - if (src->color_map_type == TGA_COLOR_MAP_PRESENT) - { - if (src->color_map_length == 0) - return TGAERR_CMAP_LENGTH; - - if (!UNMAP_DEPTH(src->color_map_depth)) - return TGAERR_CMAP_DEPTH; - } - WRITE16(src->color_map_origin); - WRITE16(src->color_map_length); - WRITE(&src->color_map_depth, 1); - - WRITE16(src->origin_x); - WRITE16(src->origin_y); - - if (src->width == 0 || src->height == 0) + if (src->color_map_type == TGA_COLOR_MAP_PRESENT) + { + if (src->color_map_length == 0) + return TGAERR_CMAP_LENGTH; + + if (!UNMAP_DEPTH(src->color_map_depth)) + return TGAERR_CMAP_DEPTH; + } + WRITE16(src->color_map_origin); + WRITE16(src->color_map_length); + WRITE(&src->color_map_depth, 1); + + WRITE16(src->origin_x); + WRITE16(src->origin_y); + + if (src->width == 0 || src->height == 0) return TGAERR_ZERO_SIZE; - WRITE16(src->width); - WRITE16(src->height); - - if (!SANE_DEPTH(src->pixel_depth) || + WRITE16(src->width); + WRITE16(src->height); + + if (!SANE_DEPTH(src->pixel_depth) || (src->pixel_depth != 8 && tga_is_colormapped(src)) ) return TGAERR_PIXEL_DEPTH; - WRITE(&src->pixel_depth, 1); - - WRITE(&src->image_descriptor, 1); - - if (src->image_id_length > 0) - WRITE(&src->image_id, src->image_id_length); - - if (src->color_map_type == TGA_COLOR_MAP_PRESENT) - WRITE(src->color_map_data + + WRITE(&src->pixel_depth, 1); + + WRITE(&src->image_descriptor, 1); + + if (src->image_id_length > 0) + WRITE(&src->image_id, src->image_id_length); + + if (src->color_map_type == TGA_COLOR_MAP_PRESENT) + WRITE(src->color_map_data + (src->color_map_origin * src->color_map_depth / 8), - src->color_map_length * src->color_map_depth / 8); - - if (tga_is_rle(src)) - { - uint16_t row; - for (row=0; rowheight; row++) - { - tga_result result = tga_write_row_RLE(fp, src, + src->color_map_length * src->color_map_depth / 8); + + if (tga_is_rle(src)) + { + uint16_t row; + for (row=0; rowheight; row++) + { + tga_result result = tga_write_row_RLE(fp, src, src->image_data + row*src->width*src->pixel_depth/8); - if (result != TGA_NOERR) return result; - } - } - else - { - /* uncompressed */ - WRITE(src->image_data, - src->width * src->height * src->pixel_depth / 8); - } - - WRITE(tga_id, tga_id_length); - - return TGA_NOERR; + if (result != TGA_NOERR) return result; + } + } + else + { + /* uncompressed */ + WRITE(src->image_data, + src->width * src->height * src->pixel_depth / 8); + } + + WRITE(tga_id, tga_id_length); + + return TGA_NOERR; #undef WRITE #undef WRITE16 } @@ -738,25 +738,25 @@ fp.write(reinterpret_cast(&_temp), 2); } static void init_tga_image(tga_image *img, uint8_t *image, const uint16_t width, const uint16_t height, const uint8_t depth) { - img->image_id_length = 0; - img->color_map_type = TGA_COLOR_MAP_ABSENT; - img->image_type = TGA_IMAGE_TYPE_NONE; /* override this below! */ - img->color_map_origin = 0; - img->color_map_length = 0; - img->color_map_depth = 0; - img->origin_x = 0; - img->origin_y = 0; - img->width = width; - img->height = height; - img->pixel_depth = depth; - img->image_descriptor = TGA_T_TO_B_BIT; - img->image_id = NULL; - img->color_map_data = NULL; - img->image_data = image; + img->image_id_length = 0; + img->color_map_type = TGA_COLOR_MAP_ABSENT; + img->image_type = TGA_IMAGE_TYPE_NONE; /* override this below! */ + img->color_map_origin = 0; + img->color_map_length = 0; + img->color_map_depth = 0; + img->origin_x = 0; + img->origin_y = 0; + img->width = width; + img->height = height; + img->pixel_depth = depth; + img->image_descriptor = TGA_T_TO_B_BIT; + img->image_id = NULL; + img->color_map_data = NULL; + img->image_data = image; } /* - - + + tga_result tga_write_mono(const char *filename, uint8_t *image, const uint16_t width, const uint16_t height) { @@ -765,9 +765,9 @@ static void init_tga_image(tga_image *img, uint8_t *image, img.image_type = TGA_IMAGE_TYPE_MONO; return tga_write(filename, &img); } - - - + + + tga_result tga_write_mono_rle(const char *filename, uint8_t *image, const uint16_t width, const uint16_t height) { @@ -776,9 +776,9 @@ static void init_tga_image(tga_image *img, uint8_t *image, img.image_type = TGA_IMAGE_TYPE_MONO_RLE; return tga_write(filename, &img); } - - - + + + tga_result tga_write_bgr(const char *filename, uint8_t *image, const uint16_t width, const uint16_t height, const uint8_t depth) { @@ -787,9 +787,9 @@ static void init_tga_image(tga_image *img, uint8_t *image, img.image_type = TGA_IMAGE_TYPE_BGR; return tga_write(filename, &img); } - - - + + + tga_result tga_write_bgr_rle(const char *filename, uint8_t *image, const uint16_t width, const uint16_t height, const uint8_t depth) { @@ -835,43 +835,43 @@ static void init_tga_image(tga_image *img, uint8_t *image, */ tga_result tga_flip_horiz(tga_image *img) { - uint16_t row; - size_t bpp; - uint8_t *left, *right; - int r_to_l; - - if (!SANE_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; - bpp = (size_t)(img->pixel_depth / 8); /* bytes per pixel */ - - for (row=0; rowheight; row++) - { - left = img->image_data + row * img->width * bpp; - right = left + (img->width - 1) * bpp; - - /* reverse from left to right */ - while (left < right) - { - uint8_t buffer[4]; - - /* swap */ - memcpy(buffer, left, bpp); - memcpy(left, right, bpp); - memcpy(right, buffer, bpp); - - left += bpp; - right -= bpp; - } - } - - /* Correct image_descriptor's left-to-right-ness. */ - r_to_l = tga_is_right_to_left(img); - img->image_descriptor &= ~TGA_R_TO_L_BIT; /* mask out r-to-l bit */ - if (!r_to_l) + uint16_t row; + size_t bpp; + uint8_t *left, *right; + int r_to_l; + + if (!SANE_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; + bpp = (size_t)(img->pixel_depth / 8); /* bytes per pixel */ + + for (row=0; rowheight; row++) + { + left = img->image_data + row * img->width * bpp; + right = left + (img->width - 1) * bpp; + + /* reverse from left to right */ + while (left < right) + { + uint8_t buffer[4]; + + /* swap */ + memcpy(buffer, left, bpp); + memcpy(left, right, bpp); + memcpy(right, buffer, bpp); + + left += bpp; + right -= bpp; + } + } + + /* Correct image_descriptor's left-to-right-ness. */ + r_to_l = tga_is_right_to_left(img); + img->image_descriptor &= ~TGA_R_TO_L_BIT; /* mask out r-to-l bit */ + if (!r_to_l) /* was l-to-r, need to set r_to_l */ - img->image_descriptor |= TGA_R_TO_L_BIT; - /* else bit is already rubbed out */ - - return TGA_NOERR; + img->image_descriptor |= TGA_R_TO_L_BIT; + /* else bit is already rubbed out */ + + return TGA_NOERR; } @@ -882,44 +882,44 @@ tga_result tga_flip_horiz(tga_image *img) */ tga_result tga_flip_vert(tga_image *img) { - uint16_t col; - size_t bpp, line; - uint8_t *top, *bottom; - int t_to_b; - - if (!SANE_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; - bpp = (size_t)(img->pixel_depth / 8); /* bytes per pixel */ - line = bpp * img->width; /* bytes per line */ - - for (col=0; colwidth; col++) - { - top = img->image_data + col * bpp; - bottom = top + (img->height - 1) * line; - - /* reverse from top to bottom */ - while (top < bottom) - { - uint8_t buffer[4]; - - /* swap */ - memcpy(buffer, top, bpp); - memcpy(top, bottom, bpp); - memcpy(bottom, buffer, bpp); - - top += line; - bottom -= line; - } - } - - /* Correct image_descriptor's top-to-bottom-ness. */ - t_to_b = tga_is_top_to_bottom(img); - img->image_descriptor &= ~TGA_T_TO_B_BIT; /* mask out t-to-b bit */ - if (!t_to_b) + uint16_t col; + size_t bpp, line; + uint8_t *top, *bottom; + int t_to_b; + + if (!SANE_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; + bpp = (size_t)(img->pixel_depth / 8); /* bytes per pixel */ + line = bpp * img->width; /* bytes per line */ + + for (col=0; colwidth; col++) + { + top = img->image_data + col * bpp; + bottom = top + (img->height - 1) * line; + + /* reverse from top to bottom */ + while (top < bottom) + { + uint8_t buffer[4]; + + /* swap */ + memcpy(buffer, top, bpp); + memcpy(top, bottom, bpp); + memcpy(bottom, buffer, bpp); + + top += line; + bottom -= line; + } + } + + /* Correct image_descriptor's top-to-bottom-ness. */ + t_to_b = tga_is_top_to_bottom(img); + img->image_descriptor &= ~TGA_T_TO_B_BIT; /* mask out t-to-b bit */ + if (!t_to_b) /* was b-to-t, need to set t_to_b */ - img->image_descriptor |= TGA_T_TO_B_BIT; - /* else bit is already rubbed out */ - - return TGA_NOERR; + img->image_descriptor |= TGA_T_TO_B_BIT; + /* else bit is already rubbed out */ + + return TGA_NOERR; } @@ -931,41 +931,41 @@ tga_result tga_flip_vert(tga_image *img) */ tga_result tga_color_unmap(tga_image *img) { - uint8_t bpp = img->color_map_depth / 8; /* bytes per pixel */ - int pos; - void *tmp; - - if (!tga_is_colormapped(img)) return TGAERR_NOT_CMAP; - if (img->pixel_depth != 8) return TGAERR_PIXEL_DEPTH; - if (!SANE_DEPTH(img->color_map_depth)) return TGAERR_CMAP_DEPTH; - - tmp = realloc(img->image_data, img->width * img->height * bpp); - if (tmp == NULL) return TGAERR_NO_MEM; - img->image_data = (uint8_t*) tmp; - - for (pos = img->width * img->height - 1; pos >= 0; pos--) - { - uint8_t c_index = img->image_data[pos]; - uint8_t *c_bgr = img->color_map_data + (c_index * bpp); - - if (c_index >= img->color_map_origin + img->color_map_length) - return TGAERR_INDEX_RANGE; - - memcpy(img->image_data + (pos*bpp), c_bgr, (size_t)bpp); - } - - /* clean up */ - img->image_type = TGA_IMAGE_TYPE_BGR; - img->pixel_depth = img->color_map_depth; - - free(img->color_map_data); - img->color_map_data = NULL; - img->color_map_type = TGA_COLOR_MAP_ABSENT; - img->color_map_origin = 0; - img->color_map_length = 0; - img->color_map_depth = 0; - - return TGA_NOERR; + uint8_t bpp = img->color_map_depth / 8; /* bytes per pixel */ + int pos; + void *tmp; + + if (!tga_is_colormapped(img)) return TGAERR_NOT_CMAP; + if (img->pixel_depth != 8) return TGAERR_PIXEL_DEPTH; + if (!SANE_DEPTH(img->color_map_depth)) return TGAERR_CMAP_DEPTH; + + tmp = realloc(img->image_data, img->width * img->height * bpp); + if (tmp == NULL) return TGAERR_NO_MEM; + img->image_data = (uint8_t*) tmp; + + for (pos = img->width * img->height - 1; pos >= 0; pos--) + { + uint8_t c_index = img->image_data[pos]; + uint8_t *c_bgr = img->color_map_data + (c_index * bpp); + + if (c_index >= img->color_map_origin + img->color_map_length) + return TGAERR_INDEX_RANGE; + + memcpy(img->image_data + (pos*bpp), c_bgr, (size_t)bpp); + } + + /* clean up */ + img->image_type = TGA_IMAGE_TYPE_BGR; + img->pixel_depth = img->color_map_depth; + + free(img->color_map_data); + img->color_map_data = NULL; + img->color_map_type = TGA_COLOR_MAP_ABSENT; + img->color_map_origin = 0; + img->color_map_length = 0; + img->color_map_depth = 0; + + return TGA_NOERR; } @@ -976,12 +976,12 @@ tga_result tga_color_unmap(tga_image *img) */ uint8_t *tga_find_pixel(const tga_image *img, uint16_t x, uint16_t y) { - if (x >= img->width || y >= img->height) - return NULL; - - if (!tga_is_top_to_bottom(img)) y = img->height - 1 - y; - if (tga_is_right_to_left(img)) x = img->width - 1 - x; - return img->image_data + (x + y * img->width) * img->pixel_depth/8; + if (x >= img->width || y >= img->height) + return NULL; + + if (!tga_is_top_to_bottom(img)) y = img->height - 1 - y; + if (tga_is_right_to_left(img)) x = img->width - 1 - x; + return img->image_data + (x + y * img->width) * img->pixel_depth/8; } @@ -994,46 +994,46 @@ uint8_t *tga_find_pixel(const tga_image *img, uint16_t x, uint16_t y) tga_result tga_unpack_pixel(const uint8_t *src, const uint8_t bits, uint8_t *b, uint8_t *g, uint8_t *r, uint8_t *a) { - switch (bits) - { + switch (bits) + { case 32: if (b) *b = src[0]; if (g) *g = src[1]; if (r) *r = src[2]; if (a) *a = src[3]; break; - + case 24: if (b) *b = src[0]; if (g) *g = src[1]; if (r) *r = src[2]; if (a) *a = 0; break; - + case 16: - { - uint16_t src16 = (uint16_t)(src[1] << 8) | (uint16_t)src[0]; - + { + uint16_t src16 = (uint16_t)(src[1] << 8) | (uint16_t)src[0]; + #define FIVE_BITS (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)) - if (b) *b = ((src16 ) & FIVE_BITS) << 3; - if (g) *g = ((src16 >> 5) & FIVE_BITS) << 3; - if (r) *r = ((src16 >> 10) & FIVE_BITS) << 3; - if (a) *a = (uint8_t)( (src16 & BIT(15)) ? 255 : 0 ); + if (b) *b = ((src16 ) & FIVE_BITS) << 3; + if (g) *g = ((src16 >> 5) & FIVE_BITS) << 3; + if (r) *r = ((src16 >> 10) & FIVE_BITS) << 3; + if (a) *a = (uint8_t)( (src16 & BIT(15)) ? 255 : 0 ); #undef FIVE_BITS - break; - } - + break; + } + case 8: if (b) *b = *src; if (g) *g = *src; if (r) *r = *src; if (a) *a = 0; break; - + default: return TGAERR_PIXEL_DEPTH; - } - return TGA_NOERR; + } + return TGA_NOERR; } @@ -1045,41 +1045,41 @@ tga_result tga_unpack_pixel(const uint8_t *src, const uint8_t bits, tga_result tga_pack_pixel(uint8_t *dest, const uint8_t bits, const uint8_t b, const uint8_t g, const uint8_t r, const uint8_t a) { - switch (bits) - { + switch (bits) + { case 32: dest[0] = b; dest[1] = g; dest[2] = r; dest[3] = a; break; - + case 24: dest[0] = b; dest[1] = g; dest[2] = r; break; - + case 16: - { - uint16_t tmp; - + { + uint16_t tmp; + #define FIVE_BITS (BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)) - tmp = (b >> 3) & FIVE_BITS; - tmp |= ((g >> 3) & FIVE_BITS) << 5; - tmp |= ((r >> 3) & FIVE_BITS) << 10; - if (a > 127) tmp |= BIT(15); + tmp = (b >> 3) & FIVE_BITS; + tmp |= ((g >> 3) & FIVE_BITS) << 5; + tmp |= ((r >> 3) & FIVE_BITS) << 10; + if (a > 127) tmp |= BIT(15); #undef FIVE_BITS - - dest[0] = (uint8_t) (tmp & 0x00FF); - dest[1] = (uint8_t)((tmp & 0xFF00) >> 8); - break; - } - + + dest[0] = (uint8_t) (tmp & 0x00FF); + dest[1] = (uint8_t)((tmp & 0xFF00) >> 8); + break; + } + default: return TGAERR_PIXEL_DEPTH; - } - return TGA_NOERR; + } + return TGA_NOERR; } @@ -1091,59 +1091,59 @@ tga_result tga_pack_pixel(uint8_t *dest, const uint8_t bits, tga_result tga_desaturate(tga_image *img, const int cr, const int cg, const int cb, const int dv) { - uint8_t bpp = img->pixel_depth / 8; /* bytes per pixel */ - uint8_t *dest, *src, *tmp; - - if (tga_is_mono(img)) return TGAERR_MONO; - if (tga_is_colormapped(img)) - { - tga_result result = tga_color_unmap(img); - if (result != TGA_NOERR) return result; - } - if (!UNMAP_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; - - dest = img->image_data; - for (src = img->image_data; - src < img->image_data + img->width*img->height*bpp; - src += bpp) - { - uint8_t b, g, r; - (void)tga_unpack_pixel(src, img->pixel_depth, &b, &g, &r, NULL); - - *dest = (uint8_t)( ( (int)b * cb + + uint8_t bpp = img->pixel_depth / 8; /* bytes per pixel */ + uint8_t *dest, *src, *tmp; + + if (tga_is_mono(img)) return TGAERR_MONO; + if (tga_is_colormapped(img)) + { + tga_result result = tga_color_unmap(img); + if (result != TGA_NOERR) return result; + } + if (!UNMAP_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; + + dest = img->image_data; + for (src = img->image_data; + src < img->image_data + img->width*img->height*bpp; + src += bpp) + { + uint8_t b, g, r; + (void)tga_unpack_pixel(src, img->pixel_depth, &b, &g, &r, NULL); + + *dest = (uint8_t)( ( (int)b * cb + (int)g * cg + (int)r * cr ) / dv ); - dest++; - } - - /* shrink */ - tmp = (uint8_t *)realloc(img->image_data, img->width * img->height); - if (tmp == NULL) return TGAERR_NO_MEM; - img->image_data = tmp; - - img->pixel_depth = 8; - img->image_type = TGA_IMAGE_TYPE_MONO; - return TGA_NOERR; + dest++; + } + + /* shrink */ + tmp = (uint8_t *)realloc(img->image_data, img->width * img->height); + if (tmp == NULL) return TGAERR_NO_MEM; + img->image_data = tmp; + + img->pixel_depth = 8; + img->image_type = TGA_IMAGE_TYPE_MONO; + return TGA_NOERR; } tga_result tga_desaturate_rec_601_1(tga_image *img) { - return tga_desaturate(img, 2989, 5866, 1145, 10000); + return tga_desaturate(img, 2989, 5866, 1145, 10000); } tga_result tga_desaturate_rec_709(tga_image *img) { - return tga_desaturate(img, 2126, 7152, 722, 10000); + return tga_desaturate(img, 2126, 7152, 722, 10000); } tga_result tga_desaturate_itu(tga_image *img) { - return tga_desaturate(img, 2220, 7067, 713, 10000); + return tga_desaturate(img, 2220, 7067, 713, 10000); } tga_result tga_desaturate_avg(tga_image *img) { - return tga_desaturate(img, 1,1,1, 3); + return tga_desaturate(img, 1,1,1, 3); } @@ -1154,72 +1154,72 @@ tga_result tga_desaturate_avg(tga_image *img) */ tga_result tga_convert_depth(tga_image *img, const uint8_t bits) { - size_t src_size, dest_size; - uint8_t src_bpp, dest_bpp; - uint8_t *src, *dest; - - if (!UNMAP_DEPTH(bits) || - !SANE_DEPTH(img->pixel_depth) + size_t src_size, dest_size; + uint8_t src_bpp, dest_bpp; + uint8_t *src, *dest; + + if (!UNMAP_DEPTH(bits) || + !SANE_DEPTH(img->pixel_depth) ) return TGAERR_PIXEL_DEPTH; - - if (tga_is_colormapped(img)) - { - tga_result result = tga_color_unmap(img); - if (result != TGA_NOERR) return result; - } - - if (img->pixel_depth == bits) return TGA_NOERR; /* no op, no err */ - - src_bpp = img->pixel_depth / 8; - dest_bpp = bits / 8; - - src_size = (size_t)( img->width * img->height * src_bpp ); - dest_size = (size_t)( img->width * img->height * dest_bpp ); - - if (src_size > dest_size) - { - void *tmp; - - /* convert forwards */ - dest = img->image_data; - for (src = img->image_data; - src < img->image_data + img->width * img->height * src_bpp; - src += src_bpp) - { - uint8_t r,g,b,a; - (void)tga_unpack_pixel(src, img->pixel_depth, &r, &g, &b, &a); - (void)tga_pack_pixel(dest, bits, r, g, b, a); - dest += dest_bpp; - } - - /* shrink */ - tmp = realloc(img->image_data, img->width * img->height * dest_bpp); - if (tmp == NULL) return TGAERR_NO_MEM; - img->image_data = (unsigned char *)tmp; - } - else - { - /* expand */ - void *tmp = realloc(img->image_data, + + if (tga_is_colormapped(img)) + { + tga_result result = tga_color_unmap(img); + if (result != TGA_NOERR) return result; + } + + if (img->pixel_depth == bits) return TGA_NOERR; /* no op, no err */ + + src_bpp = img->pixel_depth / 8; + dest_bpp = bits / 8; + + src_size = (size_t)( img->width * img->height * src_bpp ); + dest_size = (size_t)( img->width * img->height * dest_bpp ); + + if (src_size > dest_size) + { + void *tmp; + + /* convert forwards */ + dest = img->image_data; + for (src = img->image_data; + src < img->image_data + img->width * img->height * src_bpp; + src += src_bpp) + { + uint8_t r,g,b,a; + (void)tga_unpack_pixel(src, img->pixel_depth, &r, &g, &b, &a); + (void)tga_pack_pixel(dest, bits, r, g, b, a); + dest += dest_bpp; + } + + /* shrink */ + tmp = realloc(img->image_data, img->width * img->height * dest_bpp); + if (tmp == NULL) return TGAERR_NO_MEM; + img->image_data = (unsigned char *)tmp; + } + else + { + /* expand */ + void *tmp = realloc(img->image_data, img->width * img->height * dest_bpp); - if (tmp == NULL) return TGAERR_NO_MEM; - img->image_data = (uint8_t*) tmp; - - /* convert backwards */ - dest = img->image_data + (img->width*img->height - 1) * dest_bpp; - for (src = img->image_data + (img->width*img->height - 1) * src_bpp; - src >= img->image_data; - src -= src_bpp) - { - uint8_t r,g,b,a; - (void)tga_unpack_pixel(src, img->pixel_depth, &r, &g, &b, &a); - (void)tga_pack_pixel(dest, bits, r, g, b, a); - dest -= dest_bpp; - } - } - - img->pixel_depth = bits; - return TGA_NOERR; + if (tmp == NULL) return TGAERR_NO_MEM; + img->image_data = (uint8_t*) tmp; + + /* convert backwards */ + dest = img->image_data + (img->width*img->height - 1) * dest_bpp; + for (src = img->image_data + (img->width*img->height - 1) * src_bpp; + src >= img->image_data; + src -= src_bpp) + { + uint8_t r,g,b,a; + (void)tga_unpack_pixel(src, img->pixel_depth, &r, &g, &b, &a); + (void)tga_pack_pixel(dest, bits, r, g, b, a); + dest -= dest_bpp; + } + } + + img->pixel_depth = bits; + return TGA_NOERR; } @@ -1229,20 +1229,20 @@ tga_result tga_convert_depth(tga_image *img, const uint8_t bits) */ tga_result tga_swap_red_blue(tga_image *img) { - uint8_t *ptr; - uint8_t bpp = img->pixel_depth / 8; - - if (!UNMAP_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; - - for (ptr = img->image_data; - ptr < img->image_data + (img->width * img->height - 1) * bpp; - ptr += bpp) - { - uint8_t r,g,b,a; - (void)tga_unpack_pixel(ptr, img->pixel_depth, &b,&g,&r,&a); - (void)tga_pack_pixel(ptr, img->pixel_depth, r,g,b,a); - } - return TGA_NOERR; + uint8_t *ptr; + uint8_t bpp = img->pixel_depth / 8; + + if (!UNMAP_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH; + + for (ptr = img->image_data; + ptr < img->image_data + (img->width * img->height - 1) * bpp; + ptr += bpp) + { + uint8_t r,g,b,a; + (void)tga_unpack_pixel(ptr, img->pixel_depth, &b,&g,&r,&a); + (void)tga_pack_pixel(ptr, img->pixel_depth, r,g,b,a); + } + return TGA_NOERR; } @@ -1253,21 +1253,21 @@ tga_result tga_swap_red_blue(tga_image *img) */ void tga_free_buffers(tga_image *img) { - if (img->image_id != NULL) - { - free(img->image_id); - img->image_id = NULL; - } - if (img->color_map_data != NULL) - { - free(img->color_map_data); - img->color_map_data = NULL; - } - if (img->image_data != NULL) - { - free(img->image_data); - img->image_data = NULL; - } + if (img->image_id != NULL) + { + free(img->image_id); + img->image_id = NULL; + } + if (img->color_map_data != NULL) + { + free(img->color_map_data); + img->color_map_data = NULL; + } + if (img->image_data != NULL) + { + free(img->image_data); + img->image_data = NULL; + } } /* @@ -1283,24 +1283,24 @@ namespace spades { virtual bool CanSave(){ return true; } - + virtual bool CheckExtension(const std::string& filename){ return EndsWith(filename, ".tga"); } - + virtual std::string GetName(){ static std::string name("dmr.ath.cx Targa Exporter"); return name; } - + virtual Bitmap *Load(IStream *str){ SPADES_MARK_FUNCTION(); - + SPNotImplemented(); } virtual void Save(IStream *stream, Bitmap *bmp){ SPADES_MARK_FUNCTION(); - + tga_image img; std::vector data; data.resize(bmp->GetWidth() * bmp->GetHeight() * 4); @@ -1313,18 +1313,18 @@ namespace spades { (void)tga_swap_red_blue(&img); //(void)tga_flip_vert(&img); img.image_descriptor ^= TGA_T_TO_B_BIT; - + tga_result result; result = tga_write_to_FILE(stream, &img); - + if(result != TGA_NOERR){ SPRaise("Targa exporter library failure: %s", tga_error(result)); } } }; - + static TargaWriter sharedCodec; - + } */ @@ -1333,7 +1333,7 @@ class Bitmap { std::vector pixels; int w, h; public: - + Bitmap(int w=0, int h=0): w(w), h(h){ pixels.resize(w * h); @@ -1422,7 +1422,7 @@ public: } assert(maxY >= 0); outBitmap.Resize(maxX - minX + 1, maxY - minY + 1); - + int nw = maxX - minX + 1; int nh = maxY - minY + 1; for(int x = 0; x < nw; x++) { @@ -1430,7 +1430,7 @@ public: outBitmap(x, y) = (*this)(x + minX, y + minY); } } - + srcX = minX; srcY = minY; } @@ -1445,21 +1445,21 @@ public: Item() = default; Item(const IndexType& idx, int w, int h): index(idx), w(w), h(h) { - + } }; private: std::unordered_map items; - + public: AtlasBuilder() { - + } - + ~AtlasBuilder() {} AtlasBuilder(const AtlasBuilder&) = delete; AtlasBuilder& operator =(const AtlasBuilder&) = delete; - + bool TryPack(int binWidth, int binHeight) { int shelfTop = 0, shelfHeight = 0; int shelfRight = 0; @@ -1486,11 +1486,11 @@ public: } return true; } - + void AddItem(const IndexType& index, int w, int h) { items[index] = Item(index, w, h); } - + const Item& GetItem(const IndexType& index) const { return items.find(index)->second; } @@ -1505,7 +1505,7 @@ public: #include class JISDecoder: public CharsetDecoder { - + iconv_t cd; public: JISDecoder() { @@ -1516,7 +1516,7 @@ public: } virtual char32_t Decode(const std::string& str) { int index = std::stoi(str.substr(2), 0, 16); - + // non-standard JIS chars (called "機種依存文字") // iconv won't convert them... switch(index) { @@ -1615,7 +1615,7 @@ public: case 0x2d7d: break; case 0x2d7e: break; } - + char inBuf[2] = {(char)(index+0x00), (char)((index >> 8)+0x00)}; std::swap(inBuf[0], inBuf[1]); size_t inBufLen = 2; @@ -1628,12 +1628,12 @@ public: std::cerr << "failed to convert " << str << " (" << index << ") to Unicode (ignored)" << std::endl; return 0; } - + int idx = outBuf[0]; idx += static_cast(outBuf[1]) << 8; idx += static_cast(outBuf[2]) << 16; idx += static_cast(outBuf[3]) << 24; - + return static_cast(idx); } }; @@ -1825,18 +1825,18 @@ static std::vector Split(const std::string& str, const std::string& } int main(int argc, char **argv) { - + if(argc <= 1){ std::cout << "BDF (JIS Code) to OpenSpades font converter" << std::endl; std::cout << "USAGE: BdfToOSFont OUTFILE [FILTERS...] < BDFFONT.bdf" << std::endl; return 0; } - + AtlasBuilder builder; std::unordered_map glyphs; - + std::unique_ptr decoder(static_cast(new JISDecoder)); - + bool applySoftFilter = false; bool applyThickenFilter = false; bool applyDoubleFilter = false; @@ -1852,23 +1852,23 @@ int main(int argc, char **argv) { applyDilationFilter = true; } } - + char32_t currentChar = 0; int dwidth; int size = 16; int bbxX = 0, bbxY = 0, bbxW = 16, bbxH = 16; int scaling = applyDoubleFilter ? 2 : 1; - + std::string lineBuffer; while(!std::cin.eof()) { std::getline(std::cin, lineBuffer); - + auto firstPartIndex = lineBuffer.find(' '); if(firstPartIndex == std::string::npos) firstPartIndex = lineBuffer.size(); - + auto cmd = lineBuffer.substr(0, firstPartIndex); - + if(cmd == "STARTCHAR") { auto hexCode = lineBuffer.substr(firstPartIndex + 1); if(hexCode.find("U+") == 0){ @@ -1902,11 +1902,11 @@ int main(int argc, char **argv) { return 1; } std::getline(std::cin, lineBuffer); - + if(lineBuffer == "ENDCHAR") { break; } - + int len = lineBuffer.size(); int y = bmp2.GetHeight(); bmp2.Resize(std::max(bmp2.GetWidth(), len * 4), y + 1); @@ -1920,12 +1920,12 @@ int main(int argc, char **argv) { x += 4; } } - + if(currentChar == 0) { // no char code. continue; } - + if(applyDoubleFilter){ ApplyDoubleFilter(bmp2); dwidth *= 2; @@ -1936,24 +1936,24 @@ int main(int argc, char **argv) { ApplyDilationFilter(bmp2); if(applySoftFilter) ApplySoftFilter(bmp2); - + int origHeight = bmp2.GetHeight(); - + int srcX, srcY; bmp2.Trim(*bmp, srcX, srcY); - + srcX += bbxX * scaling; srcY += size - origHeight - bbxY; - + Glyph g; g.index = currentChar; g.bitmap = bmp; g.advance = dwidth; g.x = srcX; g.y = srcY; - + glyphs[currentChar] = g; - + if(bmp->GetWidth() == 0){ // empty continue; @@ -1961,9 +1961,9 @@ int main(int argc, char **argv) { builder.AddItem(currentChar, bmp->GetWidth() + 2, bmp->GetHeight() + 2); } } - + std::cerr << "packing" << std::endl; - + int binWidth = 1, binHeight = 1; while(!builder.TryPack(binWidth, binHeight)) { if(binWidth == binHeight) { @@ -1972,36 +1972,36 @@ int main(int argc, char **argv) { binHeight <<= 1; } } - + std::cerr << "Bin Size = " << binWidth << " x " << binHeight << std::endl; - + { Bitmap bin(binWidth, binHeight); - + for(auto& it: glyphs) { auto& item = it.second; if(item.bitmap->GetWidth() == 0) continue; // empty glyph - + const auto& info = builder.GetItem(item.index); //std::cerr <GetWidth()<<"x"<GetHeight()< rgba; rgba.resize(binWidth * binHeight); - + for(int x = 0; x < binWidth; x++) for(int y = 0; y < binHeight; y++){ int alpha = bin(x, y); rgba[x + y * binWidth] = (alpha << 24) | 0xffffff; } - + std::cerr << "saving" << std::endl; - + tga_image img; init_tga_image(&img, reinterpret_cast(rgba.data()), binWidth, binHeight, @@ -2010,32 +2010,32 @@ int main(int argc, char **argv) { (void)tga_swap_red_blue(&img); (void)tga_flip_vert(&img); img.image_descriptor ^= TGA_T_TO_B_BIT; - + tga_result result; std::string tifPath = argv[1]; tifPath += ".tga"; std::ofstream ofs(tifPath); result = tga_write_to_FILE(ofs, &img); - + } - + { std::cerr << "writing descriptor" << std::endl; std::string binPath = argv[1]; binPath += ".ospfont"; std::ofstream ofs(binPath); - + ofs.write("OpenSpadesFontFl", 16); - + uint32_t count = static_cast(glyphs.size()); static_assert(sizeof(count) == 4, "Oh no"); - + // write num of glyphs ofs.write(reinterpret_cast(&count), 4); - + // write font size ofs.write(reinterpret_cast(&size), 4); - + struct GlyphInfo { uint32_t unicode; uint16_t x, y; @@ -2043,31 +2043,31 @@ int main(int argc, char **argv) { uint16_t advance; int16_t offX, offY; }; - + std::vector infos; - + for(auto& it: glyphs) { auto& item = it.second; - + if(item.bitmap->GetWidth() == 0) { // empty glyph GlyphInfo inf; - + inf.unicode = static_cast(item.index); inf.x = static_cast(0xffff); inf.y = static_cast(0xffff); inf.w = 0; inf.h = 0; inf.offX = 0; inf.offY = 0; inf.advance = static_cast(item.advance); - + infos.push_back(inf); continue; } - + const auto& info = builder.GetItem(item.index); - + GlyphInfo inf; - + inf.unicode = static_cast(item.index); inf.x = static_cast(info.x); inf.y = static_cast(info.y); @@ -2076,10 +2076,10 @@ int main(int argc, char **argv) { inf.offX = static_cast(item.x); inf.offY = static_cast(item.y); inf.advance = static_cast(item.advance); - + infos.push_back(inf); } - + ofs.write(reinterpret_cast(infos.data()), sizeof(GlyphInfo) * infos.size()); }