2013-08-29 11:45:22 +09:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 yvt
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-29 11:45:22 +09:00
|
|
|
This file is part of OpenSpades.
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-29 11:45:22 +09:00
|
|
|
OpenSpades is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-29 11:45:22 +09:00
|
|
|
OpenSpades is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-29 11:45:22 +09:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-29 11:45:22 +09:00
|
|
|
*/
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
#include "FallingBlock.h"
|
2016-12-03 18:49:07 +09:00
|
|
|
#include <Core/Debug.h>
|
|
|
|
#include <Core/Exception.h>
|
2016-12-03 18:23:47 +09:00
|
|
|
#include "Client.h"
|
2013-08-18 16:18:06 +09:00
|
|
|
#include "GameMap.h"
|
2016-12-03 18:23:47 +09:00
|
|
|
#include "IModel.h"
|
|
|
|
#include "IRenderer.h"
|
2013-08-18 16:18:06 +09:00
|
|
|
#include "ParticleSpriteEntity.h"
|
2016-12-03 18:23:47 +09:00
|
|
|
#include "SmokeSpriteEntity.h"
|
|
|
|
#include "World.h"
|
|
|
|
#include <limits.h>
|
2013-08-18 16:18:06 +09:00
|
|
|
|
|
|
|
namespace spades {
|
|
|
|
namespace client {
|
2016-12-03 18:23:47 +09:00
|
|
|
FallingBlock::FallingBlock(Client *client, std::vector<IntVector3> blocks)
|
|
|
|
: client(client) {
|
|
|
|
if (blocks.empty())
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("No block given");
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// find min/max
|
|
|
|
int maxX = -1, maxY = -1, maxZ = -1;
|
2016-12-03 18:23:47 +09:00
|
|
|
int minX = INT_MAX, minY = INT_MAX, minZ = INT_MAX;
|
2013-08-18 16:18:06 +09:00
|
|
|
uint64_t xSum = 0, ySum = 0, zSum = 0;
|
|
|
|
numBlocks = (int)blocks.size();
|
2016-12-03 18:23:47 +09:00
|
|
|
for (size_t i = 0; i < blocks.size(); i++) {
|
2013-08-18 16:18:06 +09:00
|
|
|
IntVector3 v = blocks[i];
|
2016-12-03 18:23:47 +09:00
|
|
|
if (v.x < minX)
|
|
|
|
minX = v.x;
|
|
|
|
if (v.y < minY)
|
|
|
|
minY = v.y;
|
|
|
|
if (v.z < minZ)
|
|
|
|
minZ = v.z;
|
|
|
|
if (v.x > maxX)
|
|
|
|
maxX = v.x;
|
|
|
|
if (v.y > maxY)
|
|
|
|
maxY = v.y;
|
|
|
|
if (v.z > maxZ)
|
|
|
|
maxZ = v.z;
|
2013-08-18 16:18:06 +09:00
|
|
|
xSum += v.x;
|
|
|
|
ySum += v.y;
|
|
|
|
zSum += v.z;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
GameMap *map = client->GetWorld()->GetMap();
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// build voxel model
|
2016-12-03 18:23:47 +09:00
|
|
|
vmodel = new VoxelModel(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1);
|
|
|
|
for (size_t i = 0; i < blocks.size(); i++) {
|
2013-08-18 16:18:06 +09:00
|
|
|
IntVector3 v = blocks[i];
|
|
|
|
uint32_t col = map->GetColor(v.x, v.y, v.z);
|
2016-12-03 18:23:47 +09:00
|
|
|
vmodel->SetSolid(v.x - minX, v.y - minY, v.z - minZ, col);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// center of gravity
|
|
|
|
Vector3 origin;
|
|
|
|
origin.x = (float)minX - (float)xSum / (float)blocks.size();
|
|
|
|
origin.y = (float)minY - (float)ySum / (float)blocks.size();
|
|
|
|
origin.z = (float)minZ - (float)zSum / (float)blocks.size();
|
|
|
|
vmodel->SetOrigin(origin);
|
2016-12-03 18:23:47 +09:00
|
|
|
|
|
|
|
Vector3 matTrans = MakeVector3((float)minX, (float)minY, (float)minZ);
|
|
|
|
matTrans += .5f; // voxelmodel's (0,0,0) origins on block center
|
2013-08-18 16:18:06 +09:00
|
|
|
matTrans -= origin; // cancel origin
|
|
|
|
matrix = Matrix4::Translate(matTrans);
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// build renderer model
|
|
|
|
model = client->GetRenderer()->CreateModel(vmodel);
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
time = 0.f;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
|
|
|
FallingBlock::~FallingBlock() {
|
2013-09-14 13:28:19 +09:00
|
|
|
model->Release();
|
|
|
|
vmodel->Release();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
bool FallingBlock::Update(float dt) {
|
|
|
|
time += dt;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
GameMap *map = client->GetWorld()->GetMap();
|
|
|
|
Vector3 orig = matrix.GetOrigin();
|
2016-12-03 18:23:47 +09:00
|
|
|
|
|
|
|
if (time > 1.f || map->ClipBox(orig.x, orig.y, orig.z)) {
|
2013-08-18 16:18:06 +09:00
|
|
|
// destroy
|
|
|
|
int w = vmodel->GetWidth();
|
|
|
|
int h = vmodel->GetHeight();
|
|
|
|
int d = vmodel->GetDepth();
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
Matrix4 vmat = lastMatrix;
|
|
|
|
vmat = vmat * Matrix4::Translate(vmodel->GetOrigin());
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// block center
|
|
|
|
Vector3 vmOrigin = vmat.GetOrigin();
|
|
|
|
Vector3 vmAxis1 = vmat.GetAxis(0);
|
|
|
|
Vector3 vmAxis2 = vmat.GetAxis(1);
|
|
|
|
Vector3 vmAxis3 = vmat.GetAxis(2);
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-09-14 13:28:19 +09:00
|
|
|
Handle<IImage> img = client->GetRenderer()->RegisterImage("Gfx/White.tga");
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
bool usePrecisePhysics = false;
|
2016-12-03 18:23:47 +09:00
|
|
|
float dist =
|
|
|
|
(client->GetLastSceneDef().viewOrigin - matrix.GetOrigin()).GetLength();
|
|
|
|
if (dist < 16.f) {
|
|
|
|
if (numBlocks < 1000) {
|
2013-08-18 16:18:06 +09:00
|
|
|
usePrecisePhysics = true;
|
|
|
|
}
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
float impact;
|
2016-12-03 18:23:47 +09:00
|
|
|
if (dist > 170.f)
|
2013-08-18 16:18:06 +09:00
|
|
|
return false;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
impact = (float)numBlocks / 100.f;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
client->grenadeVibration += impact / (dist + 5.f);
|
2016-12-03 18:23:47 +09:00
|
|
|
if (client->grenadeVibration > 1.f)
|
2013-08-18 16:18:06 +09:00
|
|
|
client->grenadeVibration = 1.f;
|
2018-09-18 22:18:54 +09:00
|
|
|
|
|
|
|
auto *getRandom = SampleRandomFloat;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
|
|
|
for (int x = 0; x < w; x++) {
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector3 p1 = vmOrigin + vmAxis1 * (float)x;
|
2016-12-03 18:23:47 +09:00
|
|
|
for (int y = 0; y < h; y++) {
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector3 p2 = p1 + vmAxis2 * (float)y;
|
2016-12-03 18:23:47 +09:00
|
|
|
for (int z = 0; z < d; z++) {
|
|
|
|
if (!vmodel->IsSolid(x, y, z))
|
2013-08-18 16:18:06 +09:00
|
|
|
continue;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// inner voxel?
|
2016-12-03 18:23:47 +09:00
|
|
|
if (x > 0 && y > 0 && z > 0 && x < w - 1 && y < h - 1 && z < d - 1 &&
|
|
|
|
vmodel->IsSolid(x - 1, y, z) && vmodel->IsSolid(x + 1, y, z) &&
|
|
|
|
vmodel->IsSolid(x, y - 1, z) && vmodel->IsSolid(x, y + 1, z) &&
|
|
|
|
vmodel->IsSolid(x, y, z - 1) && vmodel->IsSolid(x, y, z + 1))
|
2013-08-18 16:18:06 +09:00
|
|
|
continue;
|
|
|
|
uint32_t c = vmodel->GetColor(x, y, z);
|
|
|
|
Vector4 col;
|
|
|
|
col.x = (float)((uint8_t)(c)) / 255.f;
|
2016-12-03 18:23:47 +09:00
|
|
|
col.y = (float)((uint8_t)(c >> 8)) / 255.f;
|
|
|
|
col.z = (float)((uint8_t)(c >> 16)) / 255.f;
|
2013-08-18 16:18:06 +09:00
|
|
|
col.w = 1.;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
Vector3 p3 = p2 + vmAxis3 * (float)z;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
{
|
|
|
|
ParticleSpriteEntity *ent =
|
2016-12-03 18:23:47 +09:00
|
|
|
new SmokeSpriteEntity(client, col, 70.f);
|
2018-09-17 23:37:11 +09:00
|
|
|
ent->SetTrajectory(p3, (MakeVector3(getRandom() - getRandom(),
|
|
|
|
getRandom() - getRandom(),
|
|
|
|
getRandom() - getRandom())) *
|
2016-12-03 18:23:47 +09:00
|
|
|
0.2f,
|
|
|
|
1.f, 0.f);
|
2018-09-17 23:37:11 +09:00
|
|
|
ent->SetRotation(getRandom() * (float)M_PI * 2.f);
|
2016-12-03 18:23:47 +09:00
|
|
|
ent->SetRadius(1.0f, 0.5f);
|
2013-08-18 16:18:06 +09:00
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
|
2018-09-17 23:37:11 +09:00
|
|
|
ent->SetLifeTime(1.0f + getRandom() * 0.5f, 0.f, 1.0f);
|
2013-08-18 16:18:06 +09:00
|
|
|
client->AddLocalEntity(ent);
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
col.w = 1.f;
|
2016-12-03 18:23:47 +09:00
|
|
|
for (int i = 0; i < 6; i++) {
|
2013-08-18 16:18:06 +09:00
|
|
|
ParticleSpriteEntity *ent =
|
2016-12-03 18:23:47 +09:00
|
|
|
new ParticleSpriteEntity(client, img, col);
|
2018-09-17 23:37:11 +09:00
|
|
|
ent->SetTrajectory(p3, MakeVector3(getRandom() - getRandom(),
|
|
|
|
getRandom() - getRandom(),
|
|
|
|
getRandom() - getRandom()) *
|
2016-12-03 18:23:47 +09:00
|
|
|
13.f,
|
|
|
|
1.f, .6f);
|
2018-09-17 23:37:11 +09:00
|
|
|
ent->SetRotation(getRandom() * (float)M_PI * 2.f);
|
|
|
|
ent->SetRadius(0.35f + getRandom() * getRandom() * 0.1f);
|
2013-08-18 16:18:06 +09:00
|
|
|
ent->SetLifeTime(2.f, 0.f, 1.f);
|
2016-12-03 18:23:47 +09:00
|
|
|
if (usePrecisePhysics)
|
2013-08-18 16:18:06 +09:00
|
|
|
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
|
|
|
|
client->AddLocalEntity(ent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
lastMatrix = matrix;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
Matrix4 rot;
|
2016-12-03 18:23:47 +09:00
|
|
|
rot = Matrix4::Rotate(MakeVector3(1.f, 1.f, 0.f), time * 1.4f * dt);
|
2013-08-18 16:18:06 +09:00
|
|
|
matrix = matrix * rot;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
Matrix4 trans;
|
|
|
|
trans = Matrix4::Translate(0, 0, time * dt * 4.f);
|
|
|
|
matrix = trans * matrix;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
return true;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
void FallingBlock::Render3D() {
|
|
|
|
ModelRenderParam param;
|
|
|
|
param.matrix = matrix;
|
|
|
|
client->GetRenderer()->RenderModel(model, param);
|
|
|
|
}
|
|
|
|
}
|
2018-09-17 23:37:11 +09:00
|
|
|
}
|