ParticleSpriteEntity::ParticleSpriteEntity(Client *cli, IImage *image, Vector4 color): image(image), color(color) { position = MakeVector3(0,0,0); velocity = MakeVector3(0, 0, 0); radius = 1.f; radiusVelocity = 0.f; angle = 0.f; rotationVelocity = 0.f; velocityDamp = 1; gravityScale = 1.f; lifetime = 1.f; radiusDamp = 1.f; time = 0.f; fadeInDuration = .1f; fadeOutDuration = .5f; additive = false; blockHitAction = Delete; renderer = cli->GetRenderer(); if(cli->GetWorld()) map = cli->GetWorld()->GetMap(); else map = NULL; }
GunCasing::GunCasing(Client *client, IModel *model, IAudioChunk *dropSound, IAudioChunk *waterSound, Vector3 pos, Vector3 dir, Vector3 flyDir): client(client), renderer(client->GetRenderer()), model(model), dropSound(dropSound), waterSound(waterSound){ if(dropSound) dropSound->AddRef(); if(waterSound) waterSound->AddRef(); Vector3 up = MakeVector3(0, 0, 1); Vector3 right = Vector3::Cross(dir, up).Normalize(); up = Vector3::Cross(right, dir); matrix = Matrix4::FromAxis(right, dir, up, pos); up = MakeVector3(0, 0, -1); rotAxis=Vector3::Cross(up, flyDir.Normalize()); groundTime = 0.f; onGround = false; vel = flyDir * 10.f; rotSpeed = 40.f; }
Vector3 Matrix4::GetAxis(int axis) const { switch (axis) { case 0: return MakeVector3(m[0], m[1], m[2]); case 1: return MakeVector3(m[4], m[5], m[6]); default: SPAssert(false); case 2: return MakeVector3(m[8], m[9], m[10]); } }
void Corpse::SetNode(NodeType n, spades::Vector3 v){ SPAssert(n >= 0); SPAssert(n < NodeCount); nodes[n].pos = v; nodes[n].vel = MakeVector3(VelNoise(), VelNoise(), 0.f); nodes[n].lastPos = v; nodes[n].lastForce = MakeVector3(0, 0,0); }
void Client::PlayerHitBlockWithSpade(spades::client::Player *p, Vector3 hitPos, IntVector3 blockPos, IntVector3 normal) { SPADES_MARK_FUNCTION(); uint32_t col = map->GetColor(blockPos.x, blockPos.y, blockPos.z); IntVector3 colV = {(uint8_t)col, (uint8_t)(col >> 8), (uint8_t)(col >> 16)}; Vector3 shiftedHitPos = hitPos; shiftedHitPos.x += normal.x * .05f; shiftedHitPos.y += normal.y * .05f; shiftedHitPos.z += normal.z * .05f; EmitBlockFragments(shiftedHitPos, colV); if (p == world->GetLocalPlayer()) { localFireVibrationTime = time; } if (!IsMuted()) { bool isLocal = p == world->GetLocalPlayer(); Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Spade/HitBlock.opus"); if (isLocal) audioDevice->PlayLocal(c, MakeVector3(.1f, -.1f, 1.2f), AudioParam()); else audioDevice->Play(c, p->GetOrigin() + p->GetFront() * 0.5f - p->GetUp() * .2f, AudioParam()); } }
void Client::LocalPlayerPulledGrenadePin() { SPADES_MARK_FUNCTION(); if (!IsMuted()) { Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Fire.opus"); audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f), AudioParam()); } }
bool PlaneCullTest(const Plane3& plane, const AABB3& box){ Vector3 testVertex; // find the vertex with the greatest distance value if(plane.n.x >= 0.f){ if(plane.n.y >= 0.f){ if(plane.n.z >= 0.f){ testVertex = box.max; }else{ testVertex = MakeVector3(box.max.x, box.max.y, box.min.z); } }else{ if(plane.n.z >= 0.f){ testVertex = MakeVector3(box.max.x, box.min.y, box.max.z); }else{ testVertex = MakeVector3(box.max.x, box.min.y, box.min.z); } } }else{ if(plane.n.y >= 0.f){ if(plane.n.z >= 0.f){ testVertex = MakeVector3(box.min.x, box.max.y, box.max.z); }else{ testVertex = MakeVector3(box.min.x, box.max.y, box.min.z); } }else{ if(plane.n.z >= 0.f){ testVertex = MakeVector3(box.min.x, box.min.y, box.max.z); }else{ testVertex = box.min; } } } return plane.GetDistanceTo(testVertex) >= 0.f; }
void Client::PlayerMissedSpade(spades::client::Player *p) { SPADES_MARK_FUNCTION(); if (!IsMuted()) { bool isLocal = p == world->GetLocalPlayer(); Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Spade/Miss.opus"); if (isLocal) audioDevice->PlayLocal(c, MakeVector3(.2f, -.1f, 0.7f), AudioParam()); else audioDevice->Play(c, p->GetOrigin() + p->GetFront() * 0.8f - p->GetUp() * .2f, AudioParam()); } }
void Client::PlayerRestocked(spades::client::Player *p) { if (!IsMuted()) { bool isLocal = p == world->GetLocalPlayer(); Handle<IAudioChunk> c = isLocal ? audioDevice->RegisterSound("Sounds/Weapons/RestockLocal.opus") : audioDevice->RegisterSound("Sounds/Weapons/Restock.opus"); if (isLocal) audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f), AudioParam()); else audioDevice->Play(c, p->GetEye() + p->GetFront() * 0.5f - p->GetUp() * .3f + p->GetRight() * .4f, AudioParam()); } }
void Client::PlayerDryFiredWeapon(spades::client::Player *p) { SPADES_MARK_FUNCTION(); if (!IsMuted()) { bool isLocal = p == world->GetLocalPlayer(); Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/DryFire.opus"); if (isLocal) audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f), AudioParam()); else audioDevice->Play(c, p->GetEye() + p->GetFront() * 0.5f - p->GetUp() * .3f + p->GetRight() * .4f, AudioParam()); } }
void Client::PlayerThrownGrenade(spades::client::Player *p, Grenade *g) { SPADES_MARK_FUNCTION(); if (!IsMuted()) { bool isLocal = p == world->GetLocalPlayer(); Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Throw.opus"); if (g && isLocal) { net->SendGrenade(g); } if (isLocal) audioDevice->PlayLocal(c, MakeVector3(.4f, 0.1f, .3f), AudioParam()); else audioDevice->Play(c, p->GetEye() + p->GetFront() * 0.5f - p->GetUp() * .2f + p->GetRight() * .3f, AudioParam()); } }
void Client::PlayerChangedTool(spades::client::Player *p) { SPADES_MARK_FUNCTION(); if (!IsMuted()) { bool isLocal = p == world->GetLocalPlayer(); Handle<IAudioChunk> c; if (isLocal) { // played by ClientPlayer::Update return; } else { c = audioDevice->RegisterSound("Sounds/Weapons/Switch.opus"); } if (isLocal) audioDevice->PlayLocal(c, MakeVector3(.4f, -.3f, .5f), AudioParam()); else audioDevice->Play(c, p->GetEye() + p->GetFront() * 0.5f - p->GetUp() * .3f + p->GetRight() * .4f, AudioParam()); } }
void GLBasicShadowMapRenderer::BuildMatrix(float near, float far){ // TODO: variable light direction? Vector3 lightDir = MakeVector3(0, -1, -1).Normalize(); // set better up dir? Vector3 up = MakeVector3(0, 0, 1); Vector3 side = Vector3::Cross(up, lightDir).Normalize(); up = Vector3::Cross(lightDir, side).Normalize(); // build frustrum client::SceneDefinition def = GetRenderer()->GetSceneDef(); Vector3 frustrum[8]; float tanX = tanf(def.fovX * .5f); float tanY = tanf(def.fovY * .5f); frustrum[0] = FrustrumCoord(def, tanX, tanY, near); frustrum[1] = FrustrumCoord(def, tanX, -tanY, near); frustrum[2] = FrustrumCoord(def, -tanX, tanY, near); frustrum[3] = FrustrumCoord(def, -tanX, -tanY, near); frustrum[4] = FrustrumCoord(def, tanX, tanY, far); frustrum[5] = FrustrumCoord(def, tanX, -tanY, far); frustrum[6] = FrustrumCoord(def, -tanX, tanY, far); frustrum[7] = FrustrumCoord(def, -tanX, -tanY, far); // compute frustrum's x,y boundary float minX, maxX, minY, maxY; minX = maxX = Vector3::Dot(frustrum[0], side); minY = maxY = Vector3::Dot(frustrum[0], up); for(int i = 1; i < 8; i++){ float x = Vector3::Dot(frustrum[i], side); float y = Vector3::Dot(frustrum[i], up); if(x < minX) minX = x; if(x > maxX) maxX = x; if(y < minY) minY = y; if(y > maxY) maxY = y; } // compute frustrum's z boundary Segment seg; Plane3 plane1(0,0,1,-4.f); Plane3 plane2(0,0,1,64.f); seg += ZRange(side * minX + up * minY, lightDir, plane1, plane2); seg += ZRange(side * minX + up * maxY, lightDir, plane1, plane2); seg += ZRange(side * maxX + up * minY, lightDir, plane1, plane2); seg += ZRange(side * maxX + up * maxY, lightDir, plane1, plane2); for(int i = 1; i < 8; i++){ seg += Vector3::Dot(frustrum[i], lightDir); } // build frustrum obb Vector3 origin = side * minX + up * minY + lightDir * seg.low; Vector3 axis1 = side * (maxX - minX); Vector3 axis2 = up * (maxY - minY); Vector3 axis3 = lightDir * (seg.high - seg.low); obb = OBB3(Matrix4::FromAxis(axis1, axis2, axis3, origin)); vpWidth = 2.f / axis1.GetLength(); vpHeight = 2.f / axis2.GetLength(); // convert to projectionview matrix matrix = obb.m.InversedFast(); matrix = Matrix4::Scale(2.f) * matrix; matrix = Matrix4::Translate(-1, -1, -1) * matrix; // scale a little big for padding matrix = Matrix4::Scale(.98f) * matrix; // matrix = Matrix4::Scale(1,1,-1) * matrix; // make sure frustrums in range #ifndef NDEBUG for(int i = 0; i < 8; i++){ Vector4 v = matrix * frustrum[i]; SPAssert(v.x >= -1.f); SPAssert(v.y >= -1.f); //SPAssert(v.z >= -1.f); SPAssert(v.x < 1.f); SPAssert(v.y < 1.f); //SPAssert(v.z < 1.f); } #endif }
void SWModelRenderer::RenderInner(spades::draw::SWModel *model, const client::ModelRenderParam ¶m) { auto& mat = param.matrix; auto origin = mat.GetOrigin(); auto axis1 = mat.GetAxis(0); auto axis2 = mat.GetAxis(1); auto axis3 = mat.GetAxis(2); auto *rawModel = model->GetRawModel(); auto rawModelOrigin = rawModel->GetOrigin(); rawModelOrigin += 0.1f; origin += axis1 * rawModelOrigin.x; origin += axis2 * rawModelOrigin.y; origin += axis3 * rawModelOrigin.z; int w = rawModel->GetWidth(); int h = rawModel->GetHeight(); //int d = rawModel->GetDepth(); // evaluate brightness for each normals uint8_t brights[3*3*3]; { auto lightVec = MakeVector3(0.f, -0.707f, -0.707f); float dot1 = Vector3::Dot(axis1, lightVec) * fastRSqrt(axis1.GetPoweredLength()); float dot2 = Vector3::Dot(axis2, lightVec) * fastRSqrt(axis2.GetPoweredLength()); float dot3 = Vector3::Dot(axis3, lightVec) * fastRSqrt(axis3.GetPoweredLength()); for(int x = 0; x < 3; x++){ float d; int cnt; switch(x){ case 0: d = -dot1; cnt = 1; break; case 1: d = 0.f; cnt = 0; break; case 2: d = dot1; cnt = 1; break; } for(int y = 0; y < 3; y++){ auto d2 = d; auto cnt2 = cnt; switch(y){ case 0: d2 -= dot2; cnt2++; break; case 1: break; case 2: d2 += dot2; cnt2++; break; } for(int z = 0; z < 3; z++) { auto d3 = d; auto cnt3 = cnt2; switch(y){ case 0: d3 -= dot3; cnt3++; break; case 1: break; case 2: d3 += dot3; cnt3++; break; } switch(cnt3){ case 2: d3 *= 0.707f; break; case 3: d3 *= 0.57735f; break; } d3 = 192.f + d3 * 62.f; brights[x + y * 3 + z * 9] = static_cast<uint8_t>(d3); } } } } // compute center coord. for culling { auto center = origin; auto localCenter = model->GetCenter(); center += axis1 * localCenter.x; center += axis2 * localCenter.y; center += axis3 * localCenter.z; float largestAxis = axis1.GetPoweredLength(); largestAxis = std::max(largestAxis, axis2.GetPoweredLength()); largestAxis = std::max(largestAxis, axis3.GetPoweredLength()); if(!r->SphereFrustrumCull(center, model->GetRadius() * sqrtf(largestAxis))) return; } Bitmap *fbmp = r->fb; auto *fb = fbmp->GetPixels(); int fw = fbmp->GetWidth(); int fh = fbmp->GetHeight(); auto *db = r->depthBuffer.data(); Matrix4 viewproj = r->GetProjectionViewMatrix(); Vector4 ndc2scrscale = {fw * 0.5f, -fh * 0.5f, 1.f, 1.f}; //Vector4 ndc2scroff = {fw * 0.5f, fh * 0.5f, 0.f, 0.f}; int ndc2scroffX = fw >> 1; int ndc2scroffY = fh >> 1; // render each points auto tOrigin = viewproj * MakeVector4(origin.x, origin.y, origin.z, 1.f); auto tAxis1 = viewproj * MakeVector4(axis1.x, axis1.y, axis1.z, 0.f); auto tAxis2 = viewproj * MakeVector4(axis2.x, axis2.y, axis2.z, 0.f); auto tAxis3 = viewproj * MakeVector4(axis3.x, axis3.y, axis3.z, 0.f); tOrigin *= ndc2scrscale; tAxis1 *= ndc2scrscale; tAxis2 *= ndc2scrscale; tAxis3 *= ndc2scrscale; float pointDiameter;// = largestAxis * 0.55f * fh * 0.5f; { float largestAxis = tAxis1.GetPoweredLength(); largestAxis = std::max(largestAxis, tAxis2.GetPoweredLength()); largestAxis = std::max(largestAxis, tAxis3.GetPoweredLength()); pointDiameter = sqrtf(largestAxis); } uint32_t customColor; customColor = ToFixed8(param.customColor.z) | (ToFixed8(param.customColor.y) << 8) | (ToFixed8(param.customColor.x) << 16); auto v1 = tOrigin; float zNear = r->sceneDef.zNear; for(int x = 0; x < w; x++) { auto v2 = v1; for(int y = 0; y < h; y++) { auto *mp = &model->renderData [model->renderDataAddr[x + y * w]]; while(*mp != -1) { uint32_t data = *(mp++); uint32_t normal = *(mp++); int z = static_cast<int>(data >> 24); //SPAssert(z < d); SPAssert(z >= 0); auto vv = v2 + tAxis3 * zvals[z]; if(vv.z < zNear) continue; // save Z value (don't divide this by W!) float zval = vv.z; // use vv.z for point radius to be divided by W vv.z = pointDiameter; // perspective division float scl = fastRcp(vv.w); vv *= scl; int ix = static_cast<int>(vv.x) + ndc2scroffX; int iy = static_cast<int>(vv.y) + ndc2scroffY; int idm = static_cast<int>(vv.z + .99f); idm = std::max(1, idm); int minX = ix - (idm >> 1); int minY = iy - (idm >> 1); if(minX >= fw || minY >= fh) continue; int maxX = ix + idm; int maxY = iy + idm; if(maxX <= 0 || maxY <= 0) continue; minX = std::max(minX, 0); minY = std::max(minY, 0); maxX = std::min(maxX, fw); maxY = std::min(maxY, fh); auto *fb2 = fb + (minX + minY * fw); auto *db2 = db + (minX + minY * fw); int w = maxX - minX; uint32_t color = data & 0xffffff; if(color == 0) color = customColor; SPAssert(normal < 27); int bright = brights[normal]; #if ENABLE_SSE2 if(lvl == SWFeatureLevel::SSE2) { auto m = _mm_setr_epi32(color, 0, 0, 0); auto f = _mm_set1_epi16(bright << 8); m = _mm_unpacklo_epi8(m, _mm_setzero_si128()); m = _mm_mulhi_epu16(m, f); m = _mm_packus_epi16(m, m); _mm_store_ss(reinterpret_cast<float*>(&color), _mm_castsi128_ps(m)); }else #endif { uint32_t c1 = color & 0xff00; uint32_t c2 = color & 0xff00ff; c1 *= bright; c2 *= bright; color = ((c1&0xff0000) | (c2&0xff00ff00)) >> 8; } for(int yy = minY; yy < maxY; yy++){ auto *fb3 = fb2; auto *db3 = db2; for(int xx = w; xx > 0; xx--) { if(zval < *db3) { *db3 = zval; *fb3 = color; } fb3++; db3++; } fb2 += fw; db2 += fw; } } v2 += tAxis2; } v1 += tAxis1; } }
VoxelModel *VoxelModel::LoadKV6(spades::IStream *stream) { SPADES_MARK_FUNCTION(); if(stream->Read(4) != "Kvxl"){ SPRaise("Invalid magic"); } KV6Header header; if(stream->Read(&header, sizeof(header)) < sizeof(header)){ SPRaise("File truncated: failed to read header"); } std::vector<KV6Block> blkdata; blkdata.resize(header.blklen); if(stream->Read(blkdata.data(), sizeof(KV6Block) * header.blklen) < sizeof(KV6Block) * header.blklen){ SPRaise("File truncated: failed to read blocks"); } std::vector<uint32_t> xoffset; xoffset.resize(header.xsiz); if(stream->Read(xoffset.data(), sizeof(uint32_t) * header.xsiz) < sizeof(uint32_t) * header.xsiz){ SPRaise("File truncated: failed to read xoffset"); } std::vector<uint16_t> xyoffset; xyoffset.resize(header.xsiz * header.ysiz); if(stream->Read(xyoffset.data(), sizeof(uint16_t) * header.xsiz * header.ysiz) < sizeof(uint16_t) * header.xsiz * header.ysiz){ SPRaise("File truncated: failed to read xyoffset"); } // validate: zpos < depth for(size_t i = 0; i < blkdata.size(); i++) if(blkdata[i].zPos >= header.zsiz) SPRaise("File corrupted: blkData[i].zPos >= header.zsiz"); // validate sum(xyoffset) = blkLen { uint64_t ttl = 0; for(size_t i = 0; i < xyoffset.size(); i++){ ttl += (uint32_t)xyoffset[i]; } if(ttl != (uint64_t)blkdata.size()) SPRaise("File corrupted: sum(xyoffset) != blkdata.size()"); } VoxelModel *model = new VoxelModel(header.xsiz, header.ysiz, header.zsiz); model->SetOrigin(MakeVector3(-header.xpivot, -header.ypivot, -header.zpivot)); try{ int pos = 0; for(int x = 0; x < (int)header.xsiz; x++) for(int y = 0; y < (int)header.ysiz; y++){ int spanBlocks = (int)xyoffset[x *header.ysiz + y]; int lastZ = -1; //printf("pos: %d, (%d, %d): %d\n", // pos, x, y, spanBlocks); while(spanBlocks--){ const KV6Block& b = blkdata[pos]; //printf("%d, %d, %d: %d, %d\n", x, y, b.zPos, // b.visFaces, b.lighting); if(model->IsSolid(x, y, b.zPos)){ SPRaise("Duplicate voxel (%d, %d, %d)", x, y, b.zPos); } if(b.zPos <= lastZ){ SPRaise("Not Z-sorted"); } lastZ = b.zPos; model->SetSolid(x, y, b.zPos, swapColor(b.color)); pos++; } } SPAssert(pos == blkdata.size()); return model; }catch(...){ delete model; throw; } }
virtual Vector3 GetRecoil() { return MakeVector3(0.05f, 0.1f, 0.f); // measured }
void Client::GrenadeExploded(spades::client::Grenade *g) { SPADES_MARK_FUNCTION(); bool inWater = g->GetPosition().z > 63.f; if (inWater) { if (!IsMuted()) { Handle<IAudioChunk> c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplode.opus"); AudioParam param; param.volume = 10.f; audioDevice->Play(c, g->GetPosition(), param); c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplodeFar.opus"); param.volume = 6.f; param.referenceDistance = 10.f; audioDevice->Play(c, g->GetPosition(), param); c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/WaterExplodeStereo.opus"); param.volume = 2.f; audioDevice->Play(c, g->GetPosition(), param); } GrenadeExplosionUnderwater(g->GetPosition()); } else { GrenadeExplosion(g->GetPosition()); if (!IsMuted()) { Handle<IAudioChunk> c, cs; switch (SampleRandomInt(0, 1)) { case 0: c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Explode1.opus"); cs = audioDevice->RegisterSound( "Sounds/Weapons/Grenade/ExplodeStereo1.opus"); break; case 1: c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Explode2.opus"); cs = audioDevice->RegisterSound( "Sounds/Weapons/Grenade/ExplodeStereo2.opus"); break; } AudioParam param; param.volume = 30.f; param.referenceDistance = 5.f; audioDevice->Play(c, g->GetPosition(), param); param.referenceDistance = 1.f; audioDevice->Play(cs, g->GetPosition(), param); c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/ExplodeFar.opus"); param.volume = 6.f; param.referenceDistance = 40.f; audioDevice->Play(c, g->GetPosition(), param); c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/ExplodeFarStereo.opus"); param.referenceDistance = 10.f; audioDevice->Play(c, g->GetPosition(), param); // debri sound c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Debris.opus"); param.volume = 5.f; param.referenceDistance = 3.f; IntVector3 outPos; Vector3 soundPos = g->GetPosition(); if (world->GetMap()->CastRay(soundPos, MakeVector3(0, 0, 1), 8.f, outPos)) { soundPos.z = (float)outPos.z - .2f; } audioDevice->Play(c, soundPos, param); } } }
Client::Client(IRenderer *r, IAudioDevice *audioDev, const ServerAddress& host, std::string playerName) : playerName(playerName) , logStream(nullptr) , hostname(host) , renderer(r) , audioDevice(audioDev) , time(0.f) , readyToClose(false) , worldSubFrame(0.f) , frameToRendererInit(5) , timeSinceInit(0.f) , hasLastTool(false) , lastPosSentTime(0.f) , lastAliveTime(0.f) , lastKills(0) , hasDelayedReload(false) , localFireVibrationTime(-1.f) , grenadeVibration(0.f) , scoreboardVisible(false) , flashlightOn(false) , focalLength(20.f) , targetFocalLength(20.f) , autoFocusEnabled(true) , hitFeedbackFriendly(false) , lastMyCorpse(nullptr) , nextScreenShotIndex(0) , nextMapShotIndex(0) , alertDisappearTime(-10000.f) // FIXME: preferences? , corpseSoftTimeLimit(30.f) // FIXME: this is not used , corpseSoftLimit(6) , corpseHardLimit(16) , followYaw(0.f) , followPitch(0.f) { SPADES_MARK_FUNCTION(); SPLog("Initializing..."); designFont.Set(CreateSquareDesignFont(renderer), false); textFont.Set(CreateGuiFont(renderer), false); bigTextFont.Set(CreateLargeFont(renderer), false); renderer->SetFogDistance(128.f); renderer->SetFogColor(MakeVector3(.8f, 1.f, 1.f)); chatWindow.reset(new ChatWindow(this, GetRenderer(), textFont, false)); killfeedWindow.reset(new ChatWindow(this, GetRenderer(), textFont, true)); hurtRingView.reset(new HurtRingView(this)); centerMessageView.reset(new CenterMessageView(this, bigTextFont)); mapView.reset(new MapView(this, false)); largeMapView.reset(new MapView(this, true)); scoreboard.reset(new ScoreboardView(this)); limbo.reset(new LimboView(this)); paletteView.reset(new PaletteView(this)); tcView.reset(new TCProgressView(this)); scriptedUI.Set(new ClientUI(renderer, audioDev, textFont, this), false); renderer->SetGameMap(nullptr); }
bool GunCasing::Update(float dt) { if(onGround){ groundTime += dt; if(groundTime > 2.f){ return false; } GameMap *map = client->GetWorld()->GetMap(); if(!map->ClipWorld(groundPos.x, groundPos.y, groundPos.z)){ return false; } }else{ Matrix4 lastMat = matrix; matrix = matrix * Matrix4::Rotate(rotAxis, dt * rotSpeed); matrix = Matrix4::Translate(vel * dt) * matrix; vel.z += dt * 32.f; IntVector3 lp = matrix.GetOrigin().Floor(); GameMap *m = client->GetWorld()->GetMap(); if(lp.z >= 63){ // dropped into water float dist = (client->GetLastSceneDef().viewOrigin - matrix.GetOrigin()).GetPoweredLength(); if(waterSound){ if(dist < 40.f * 40.f && !client->IsMuted()){ IAudioDevice *dev = client->GetAudioDevice(); AudioParam param; param.referenceDistance = .6f; param.pitch = .9f + GetRandom() * .2f; dev->Play(waterSound, lastMat.GetOrigin(), param); } waterSound = NULL; } if(dist < 40.f * 40.f){ int splats = rand() % 3; Handle<IImage> img = client->GetRenderer()->RegisterImage("Gfx/White.tga"); Vector4 col = {1, 1, 1, 0.8f}; Vector3 pt = matrix.GetOrigin(); pt.z = 62.99f; for(int i = 0; i < splats; i++){ ParticleSpriteEntity *ent = new ParticleSpriteEntity(client, img, col); ent->SetTrajectory(pt, MakeVector3(GetRandom()-GetRandom(), GetRandom()-GetRandom(), -GetRandom()) * 2.f, 1.f, .4f); ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRadius(0.1f + GetRandom()*GetRandom()*0.1f); ent->SetLifeTime(2.f, 0.f, 1.f); client->AddLocalEntity(ent); } } return false; } if(m->ClipWorld(lp.x,lp.y,lp.z)){ // hit a wall IntVector3 lp2 = lastMat.GetOrigin().Floor(); if (lp.z != lp2.z && ((lp.x == lp2.x && lp.y == lp2.y) || !m->ClipWorld(lp.x, lp.y, lp2.z))){ vel.z = -vel.z; if(lp2.z < lp.z){ // ground hit if(vel.GetLength() < .5f + dt * 100.f && !dropSound){ // stick to ground onGround = true; groundPos = lp; // move to surface float z = matrix.GetOrigin().z; float shift = z - floorf(z); matrix = Matrix4::Translate(0,0,-shift) * matrix; // lie Vector3 v1 = matrix.GetAxis(0); Vector3 v2 = matrix.GetAxis(1); v1.z = 0; v2.z = 0; v1 = v1.Normalize(); v2 = v2.Normalize(); Vector3 v3 = Vector3::Cross(v1, v2).Normalize(); v1 = Vector3::Cross(v2, v3).Normalize(); matrix = Matrix4::FromAxis(v1, v2, v3, matrix.GetOrigin()); }else{ if(dropSound){ float dist = (client->GetLastSceneDef().viewOrigin - matrix.GetOrigin()).GetPoweredLength(); if(dist < 40.f * 40.f && !client->IsMuted()){ IAudioDevice *dev = client->GetAudioDevice(); AudioParam param; param.referenceDistance = .6f; dev->Play(dropSound, lastMat.GetOrigin(), param); } dropSound = NULL; } } } }else if(lp.x != lp2.x && ((lp.y == lp2.y && lp.z == lp2.z) || !m->ClipWorld(lp2.x, lp.y, lp.z))) vel.x = -vel.x; else if(lp.y != lp2.y && ((lp.x == lp2.x && lp.z == lp2.z) || !m->ClipWorld(lp.x, lp2.y, lp.z))) vel.y = -vel.y; else return false; if(!onGround){ matrix = lastMat; vel *= .2f; rotAxis = RandomAxis(); Vector3 r; r.x = GetRandom() - GetRandom(); r.y = GetRandom() - GetRandom(); r.z = GetRandom() - GetRandom(); vel += r * 0.1f; rotSpeed *= .2f; } } } return true; }
virtual Vector3 GetRecoil () { return MakeVector3(0.0002f, -0.1f, 0.f); }
void Client::RunFrame(float dt) { SPADES_MARK_FUNCTION(); fpsCounter.MarkFrame(); if(frameToRendererInit > 0){ // waiting for renderer initialization DrawStartupScreen(); frameToRendererInit--; if(frameToRendererInit == 0){ DoInit(); }else{ return; } } timeSinceInit += std::min(dt, .03f); // update network try{ if(net->GetStatus() == NetClientStatusConnected) net->DoEvents(0); else net->DoEvents(10); }catch(const std::exception& ex){ if(net->GetStatus() == NetClientStatusNotConnected){ SPLog("Disconnected because of error:\n%s", ex.what()); NetLog("Disconnected because of error:\n%s", ex.what()); throw; }else{ SPLog("Exception while processing network packets (ignored):\n%s", ex.what()); } } hurtRingView->Update(dt); centerMessageView->Update(dt); mapView->Update(dt); largeMapView->Update(dt); UpdateAutoFocus(dt); if(world){ UpdateWorld(dt); }else{ renderer->SetFogColor(MakeVector3(0.f, 0.f, 0.f)); } chatWindow->Update(dt); killfeedWindow->Update(dt); limbo->Update(dt); // CreateSceneDefinition also can be used for sounds SceneDefinition sceneDef = CreateSceneDefinition(); lastSceneDef = sceneDef; // Update sounds try{ audioDevice->Respatialize(sceneDef.viewOrigin, sceneDef.viewAxis[2], sceneDef.viewAxis[1]); }catch(const std::exception& ex){ SPLog("Audio subsystem returned error (ignored):\n%s", ex.what()); } // render scene DrawScene(); // draw 2d Draw2D(); // draw scripted GUI scriptedUI->RunFrame(dt); if(scriptedUI->WantsClientToBeClosed()) readyToClose = true; // Well done! renderer->FrameDone(); renderer->Flip(); // reset all "delayed actions" (in case we forget to reset these) hasDelayedReload = false; time += dt; }
void GLVoxelModel::RenderSunlightPass(std::vector<client::ModelRenderParam> params) { SPADES_MARK_FUNCTION(); device->ActiveTexture(0); aoImage->Bind(IGLDevice::Texture2D); device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter, IGLDevice::Linear); device->Enable(IGLDevice::CullFace, true); device->Enable(IGLDevice::DepthTest, true); program->Use(); static GLShadowShader shadowShader; shadowShader(renderer, program, 1); static GLProgramUniform fogDistance("fogDistance"); fogDistance(program); fogDistance.SetValue(renderer->GetFogDistance()); static GLProgramUniform fogColor("fogColor"); fogColor(program); Vector3 fogCol = renderer->GetFogColorForSolidPass(); fogCol *= fogCol; fogColor.SetValue(fogCol.x, fogCol.y, fogCol.z); static GLProgramUniform aoUniform("ambientOcclusionTexture"); aoUniform(program); aoUniform.SetValue(0); static GLProgramUniform modelOrigin("modelOrigin"); modelOrigin(program); modelOrigin.SetValue(origin.x, origin.y, origin.z); static GLProgramUniform sunLightDirection("sunLightDirection"); sunLightDirection(program); Vector3 sunPos = MakeVector3(0, -1, -1); sunPos = sunPos.Normalize(); sunLightDirection.SetValue(sunPos.x, sunPos.y, sunPos.z); static GLProgramUniform viewOriginVector("viewOriginVector"); viewOriginVector(program); const auto &viewOrigin = renderer->GetSceneDef().viewOrigin; viewOriginVector.SetValue(viewOrigin.x, viewOrigin.y, viewOrigin.z); // setup attributes static GLProgramAttribute positionAttribute("positionAttribute"); static GLProgramAttribute textureCoordAttribute("textureCoordAttribute"); static GLProgramAttribute colorAttribute("colorAttribute"); static GLProgramAttribute normalAttribute("normalAttribute"); positionAttribute(program); textureCoordAttribute(program); colorAttribute(program); normalAttribute(program); device->BindBuffer(IGLDevice::ArrayBuffer, buffer); device->VertexAttribPointer(positionAttribute(), 4, IGLDevice::UnsignedByte, false, sizeof(Vertex), (void *)0); device->VertexAttribPointer(textureCoordAttribute(), 2, IGLDevice::UnsignedShort, false, sizeof(Vertex), (void *)4); device->VertexAttribPointer(colorAttribute(), 4, IGLDevice::UnsignedByte, true, sizeof(Vertex), (void *)8); device->VertexAttribPointer(normalAttribute(), 3, IGLDevice::Byte, false, sizeof(Vertex), (void *)12); device->BindBuffer(IGLDevice::ArrayBuffer, 0); device->EnableVertexAttribArray(positionAttribute(), true); device->EnableVertexAttribArray(textureCoordAttribute(), true); device->EnableVertexAttribArray(colorAttribute(), true); device->EnableVertexAttribArray(normalAttribute(), true); device->BindBuffer(IGLDevice::ElementArrayBuffer, idxBuffer); for (size_t i = 0; i < params.size(); i++) { const client::ModelRenderParam ¶m = params[i]; // frustrum cull float rad = radius; rad *= param.matrix.GetAxis(0).GetLength(); if (!renderer->SphereFrustrumCull(param.matrix.GetOrigin(), rad)) { continue; } static GLProgramUniform customColor("customColor"); customColor(program); customColor.SetValue(param.customColor.x, param.customColor.y, param.customColor.z); Matrix4 modelMatrix = param.matrix; static GLProgramUniform projectionViewModelMatrix("projectionViewModelMatrix"); projectionViewModelMatrix(program); projectionViewModelMatrix.SetValue(renderer->GetProjectionViewMatrix() * modelMatrix); static GLProgramUniform viewModelMatrix("viewModelMatrix"); viewModelMatrix(program); viewModelMatrix.SetValue(renderer->GetViewMatrix() * modelMatrix); static GLProgramUniform modelMatrixU("modelMatrix"); modelMatrixU(program); modelMatrixU.SetValue(modelMatrix); modelMatrix.m[12] = 0.f; modelMatrix.m[13] = 0.f; modelMatrix.m[14] = 0.f; static GLProgramUniform modelNormalMatrix("modelNormalMatrix"); modelNormalMatrix(program); modelNormalMatrix.SetValue(modelMatrix); if (param.depthHack) { device->DepthRange(0.f, 0.1f); } device->DrawElements(IGLDevice::Triangles, numIndices, IGLDevice::UnsignedInt, (void *)0); if (param.depthHack) { device->DepthRange(0.f, 1.f); } } device->BindBuffer(IGLDevice::ElementArrayBuffer, 0); device->EnableVertexAttribArray(positionAttribute(), false); device->EnableVertexAttribArray(textureCoordAttribute(), false); device->EnableVertexAttribArray(colorAttribute(), false); device->EnableVertexAttribArray(normalAttribute(), false); device->ActiveTexture(0); device->BindTexture(IGLDevice::Texture2D, 0); }
Vector3 Matrix4::GetOrigin() const { return MakeVector3(m[12], m[13], m[14]); }
void Corpse::AddToScene() { if(false){ // debug line only Vector4 col = {1, 1, 0, 0}; renderer->AddDebugLine(nodes[Torso1].pos, nodes[Torso2].pos, col); renderer->AddDebugLine(nodes[Torso2].pos, nodes[Torso3].pos, col); renderer->AddDebugLine(nodes[Torso3].pos, nodes[Torso4].pos, col); renderer->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; { Vector3 tX1 = nodes[Torso1].pos - nodes[Torso2].pos; Vector3 tX2 = nodes[Torso4].pos - nodes[Torso3].pos; Vector3 tY1 = nodes[Torso1].pos + nodes[Torso2].pos; Vector3 tY2 = nodes[Torso4].pos + nodes[Torso3].pos; tX = ((tX1 + tX2) * .5f).Normalize(); tY = ((tY2 - tY1) * .5f).Normalize(); Vector3 tZ = Vector3::Cross(tX, tY).Normalize(); 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); } // draw Head { 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(); 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, 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); } }
virtual Vector3 GetRecoil () { return MakeVector3(0.00005f, -0.0125f, 0.f); }
virtual Vector3 GetRecoil() { // FIXME: needs to measured return MakeVector3(0.0002f, 0.075f, 0.f); }
void GLSoftLitSpriteRenderer::Render() { SPADES_MARK_FUNCTION(); if(sprites.empty()) return; // light every sprite const std::vector<GLDynamicLight>& lights = renderer->lights; for(size_t i = 0; i < sprites.size(); i++){ Sprite& spr = sprites[i]; if(spr.color.w < .0001f) { // maybe emissive sprite... spr.emission = spr.color.GetXYZ(); spr.color = MakeVector4(0.f, 0.f, 0.f, 0.f); }else{ spr.emission = MakeVector3(0.f, 0.f, 0.f); } spr.dlR = MakeVector4(0, 0, 0, 0); spr.dlG = MakeVector4(0, 0, 0, 0); spr.dlB = MakeVector4(0, 0, 0, 0); } for(size_t j = 0; j < lights.size(); j++) { const GLDynamicLight& l = lights[j]; const client::DynamicLightParam& dl = l.GetParam(); float spotTan = dl.type == client::DynamicLightTypeSpotlight ? tanf(dl.spotAngle * .5f) : 0.; for(size_t i = 0; i < sprites.size(); i++){ Sprite& spr = sprites[i]; Vector3 v = dl.origin - spr.center; float effectiveRadius = spr.radius + dl.radius; if(v.GetChebyshevLength() > effectiveRadius) continue; float powdist = v.GetPoweredLength(); if(powdist > effectiveRadius * effectiveRadius) continue; float att = 1.f - powdist / (effectiveRadius * effectiveRadius); float unif; float directionalFactor = 1.f; unif = 1.f - powdist / (spr.radius * spr.radius); unif = std::max(.2f, unif); if(dl.type == client::DynamicLightTypeSpotlight) { float forward = Vector3::Dot(v, dl.spotAxis[2]); if(forward > spr.radius) { continue; }else if(forward >= -spr.radius){ att *= .5f - (forward / spr.radius) * .5f; directionalFactor = 1.f; }else{ float cx = Vector3::Dot(spr.center - dl.origin, dl.spotAxis[0]); float cy = Vector3::Dot(spr.center - dl.origin, dl.spotAxis[1]); float sq = sqrtf(cx * cx + cy * cy); float sprTan = spr.radius / (-spr.radius - forward); float eff = sprTan + spotTan; sq /= -forward; if(sq > eff){ continue; } if(sq > eff - spotTan){ att *= (eff - sq) / spotTan; } } } Vector4 final; if(unif < .9999f) { Vector3 directional = v; directional *= att * directionalFactor * (1.f - unif) / sqrtf(powdist); final.x = directional.x; final.y = directional.y; final.z = directional.z;
void Client::PlayerKilledPlayer(spades::client::Player *killer, spades::client::Player *victim, KillType kt) { // play hit sound if (kt == KillTypeWeapon || kt == KillTypeHeadshot) { // don't play on local: see BullethitPlayer if (victim != world->GetLocalPlayer()) { if (!IsMuted()) { Handle<IAudioChunk> c; switch (SampleRandomInt(0, 2)) { case 0: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh1.opus"); break; case 1: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh2.opus"); break; case 2: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh3.opus"); break; } AudioParam param; param.volume = 4.f; audioDevice->Play(c, victim->GetEye(), param); } } } // The local player is dead; initialize the look-you-are-dead cam if (victim == world->GetLocalPlayer()) { followCameraState.enabled = false; Vector3 v = -victim->GetFront(); followAndFreeCameraState.yaw = atan2(v.y, v.x); followAndFreeCameraState.pitch = 30.f * M_PI / 180.f; } // emit blood (also for local player) // FIXME: emiting blood for either // client-side or server-side hit? switch (kt) { case KillTypeGrenade: case KillTypeHeadshot: case KillTypeMelee: case KillTypeWeapon: Bleed(victim->GetEye()); break; default: break; } // create ragdoll corpse if (cg_ragdoll && victim->GetTeamId() < 2) { Corpse *corp; corp = new Corpse(renderer, map, victim); if (victim == world->GetLocalPlayer()) lastMyCorpse = corp; if (killer != victim && kt != KillTypeGrenade) { Vector3 dir = victim->GetPosition() - killer->GetPosition(); dir = dir.Normalize(); if (kt == KillTypeMelee) { dir *= 6.f; } else { if (killer->GetWeapon()->GetWeaponType() == SMG_WEAPON) { dir *= 2.8f; } else if (killer->GetWeapon()->GetWeaponType() == SHOTGUN_WEAPON) { dir *= 4.5f; } else { dir *= 3.5f; } } corp->AddImpulse(dir); } else if (kt == KillTypeGrenade) { corp->AddImpulse(MakeVector3(0, 0, -4.f - SampleRandomFloat() * 4.f)); } corp->AddImpulse(victim->GetVelocty() * 32.f); corpses.emplace_back(corp); if (corpses.size() > corpseHardLimit) { corpses.pop_front(); } else if (corpses.size() > corpseSoftLimit) { RemoveInvisibleCorpses(); } } // add chat message std::string s; s = ChatWindow::TeamColorMessage(killer->GetName(), killer->GetTeamId()); std::string cause; bool isFriendlyFire = killer->GetTeamId() == victim->GetTeamId(); if (killer == victim) isFriendlyFire = false; Weapon *w = killer ? killer->GetWeapon() : nullptr; // only used in case of KillTypeWeapon switch (kt) { case KillTypeWeapon: switch (w ? w->GetWeaponType() : RIFLE_WEAPON) { case RIFLE_WEAPON: cause += _Tr("Client", "Rifle"); break; case SMG_WEAPON: cause += _Tr("Client", "SMG"); break; case SHOTGUN_WEAPON: cause += _Tr("Client", "Shotgun"); break; } break; case KillTypeFall: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Fall"); break; case KillTypeMelee: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Melee"); break; case KillTypeGrenade: cause += _Tr("Client", "Grenade"); break; case KillTypeHeadshot: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Headshot"); break; case KillTypeTeamChange: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Team Change"); break; case KillTypeClassChange: //! A cause of death shown in the kill feed. cause += _Tr("Client", "Weapon Change"); break; default: cause += "???"; break; } s += " ["; if (isFriendlyFire) s += ChatWindow::ColoredMessage(cause, MsgColorFriendlyFire); else if (killer == world->GetLocalPlayer() || victim == world->GetLocalPlayer()) s += ChatWindow::ColoredMessage(cause, MsgColorGray); else s += cause; s += "] "; if (killer != victim) { s += ChatWindow::TeamColorMessage(victim->GetName(), victim->GetTeamId()); } killfeedWindow->AddMessage(s); // log to netlog if (killer != victim) { NetLog("%s (%s) [%s] %s (%s)", killer->GetName().c_str(), world->GetTeam(killer->GetTeamId()).name.c_str(), cause.c_str(), victim->GetName().c_str(), world->GetTeam(victim->GetTeamId()).name.c_str()); } else { NetLog("%s (%s) [%s]", killer->GetName().c_str(), world->GetTeam(killer->GetTeamId()).name.c_str(), cause.c_str()); } // show big message if player is involved if (victim != killer) { Player *local = world->GetLocalPlayer(); if (killer == local || victim == local) { std::string msg; if (killer == local) { if ((int)cg_centerMessage == 2) msg = _Tr("Client", "You have killed {0}", victim->GetName()); } else { msg = _Tr("Client", "You were killed by {0}", killer->GetName()); } centerMessageView->AddMessage(msg); } } }
void GLVoxelModel::RenderDynamicLightPass(std::vector<client::ModelRenderParam> params, std::vector<GLDynamicLight> lights) { SPADES_MARK_FUNCTION(); device->ActiveTexture(0); device->Enable(IGLDevice::CullFace, true); device->Enable(IGLDevice::DepthTest, true); dlightProgram->Use(); static GLDynamicLightShader dlightShader; static GLProgramUniform fogDistance("fogDistance"); fogDistance(dlightProgram); fogDistance.SetValue(renderer->GetFogDistance()); static GLProgramUniform modelOrigin("modelOrigin"); modelOrigin(dlightProgram); modelOrigin.SetValue(origin.x, origin.y, origin.z); static GLProgramUniform sunLightDirection("sunLightDirection"); sunLightDirection(dlightProgram); Vector3 sunPos = MakeVector3(0, -1, -1); sunPos = sunPos.Normalize(); sunLightDirection.SetValue(sunPos.x, sunPos.y, sunPos.z); static GLProgramUniform viewOriginVector("viewOriginVector"); viewOriginVector(dlightProgram); const auto &viewOrigin = renderer->GetSceneDef().viewOrigin; viewOriginVector.SetValue(viewOrigin.x, viewOrigin.y, viewOrigin.z); // setup attributes static GLProgramAttribute positionAttribute("positionAttribute"); static GLProgramAttribute colorAttribute("colorAttribute"); static GLProgramAttribute normalAttribute("normalAttribute"); positionAttribute(dlightProgram); colorAttribute(dlightProgram); normalAttribute(dlightProgram); device->BindBuffer(IGLDevice::ArrayBuffer, buffer); device->VertexAttribPointer(positionAttribute(), 4, IGLDevice::UnsignedByte, false, sizeof(Vertex), (void *)0); device->VertexAttribPointer(colorAttribute(), 4, IGLDevice::UnsignedByte, true, sizeof(Vertex), (void *)8); device->VertexAttribPointer(normalAttribute(), 3, IGLDevice::Byte, false, sizeof(Vertex), (void *)12); device->BindBuffer(IGLDevice::ArrayBuffer, 0); device->EnableVertexAttribArray(positionAttribute(), true); device->EnableVertexAttribArray(colorAttribute(), true); device->EnableVertexAttribArray(normalAttribute(), true); device->BindBuffer(IGLDevice::ElementArrayBuffer, idxBuffer); for (size_t i = 0; i < params.size(); i++) { const client::ModelRenderParam ¶m = params[i]; // frustrum cull float rad = radius; rad *= param.matrix.GetAxis(0).GetLength(); if (!renderer->SphereFrustrumCull(param.matrix.GetOrigin(), rad)) { continue; } static GLProgramUniform customColor("customColor"); customColor(dlightProgram); customColor.SetValue(param.customColor.x, param.customColor.y, param.customColor.z); Matrix4 modelMatrix = param.matrix; static GLProgramUniform projectionViewModelMatrix("projectionViewModelMatrix"); projectionViewModelMatrix(dlightProgram); projectionViewModelMatrix.SetValue(renderer->GetProjectionViewMatrix() * modelMatrix); static GLProgramUniform viewModelMatrix("viewModelMatrix"); viewModelMatrix(dlightProgram); viewModelMatrix.SetValue(renderer->GetViewMatrix() * modelMatrix); static GLProgramUniform modelMatrixU("modelMatrix"); modelMatrixU(dlightProgram); modelMatrixU.SetValue(modelMatrix); modelMatrix.m[12] = 0.f; modelMatrix.m[13] = 0.f; modelMatrix.m[14] = 0.f; static GLProgramUniform modelNormalMatrix("modelNormalMatrix"); modelNormalMatrix(dlightProgram); modelNormalMatrix.SetValue(modelMatrix); if (param.depthHack) { device->DepthRange(0.f, 0.1f); } for (size_t i = 0; i < lights.size(); i++) { if (!GLDynamicLightShader::SphereCull(lights[i], param.matrix.GetOrigin(), rad)) continue; dlightShader(renderer, dlightProgram, lights[i], 0); device->DrawElements(IGLDevice::Triangles, numIndices, IGLDevice::UnsignedInt, (void *)0); } if (param.depthHack) { device->DepthRange(0.f, 1.f); } } device->BindBuffer(IGLDevice::ElementArrayBuffer, 0); device->EnableVertexAttribArray(positionAttribute(), false); device->EnableVertexAttribArray(colorAttribute(), false); device->EnableVertexAttribArray(normalAttribute(), false); device->ActiveTexture(0); }
Tracer::Tracer(Client *client, Player *player, IModel *model, Vector3 p1, Vector3 p2, float bulletVel, IntVector3 team) : client(client), player(player), model(model), startPos(p1), velocity(bulletVel), teamCol(team) { dir = (p2 - p1).Normalize(); length = (p2 - p1).GetLength()-2; startPos += dir*8; const float maxTimeSpread = 1.f / 60.f; const float shutterTime = 0.3f / 60.f; visibleLength = shutterTime * bulletVel; curDistance = -visibleLength + 8; curDistance += maxTimeSpread; //* GetRandom(); firstUpdate = true; image = client->GetRenderer()->RegisterImage("Gfx/WhitePixel.tga"); //image2 = client->GetRenderer()->RegisterImage("Gfx/WhiteDisk.tga"); //Chameleon: .wav sounds for tracers int x = GetRandom()*4; switch (x % 4) { case 0: snd = bulletVel > 350 ? client->GetAudioDevice()->RegisterSound("Sounds/Weapons/Objects/TracerSUP1.wav") : client->GetAudioDevice()->RegisterSound("Sounds/Weapons/Objects/TracerSUB1.wav"); break; case 1: snd = bulletVel > 350 ? client->GetAudioDevice()->RegisterSound("Sounds/Weapons/Objects/TracerSUP2.wav") : client->GetAudioDevice()->RegisterSound("Sounds/Weapons/Objects/TracerSUB2.wav"); break; case 2: snd = bulletVel > 350 ? client->GetAudioDevice()->RegisterSound("Sounds/Weapons/Objects/TracerSUP3.wav") : client->GetAudioDevice()->RegisterSound("Sounds/Weapons/Objects/TracerSUB3.wav"); break; case 3: snd = bulletVel > 350 ? client->GetAudioDevice()->RegisterSound("Sounds/Weapons/Objects/TracerSUP4.wav") : client->GetAudioDevice()->RegisterSound("Sounds/Weapons/Objects/TracerSUB4.wav"); break; default: break; } if (player) { if (player->IsLocalPlayer() || (p1 - player->GetPosition()).GetPoweredLength() < 64) flyByDist = -1; } else { flyByDist = 0; } //soundPlayed = false; //Chameleon: .kv6 tracers Vector3 up = MakeVector3(0, 0, 1); Vector3 right = Vector3::Cross(dir, up).Normalize(); up = Vector3::Cross(right, dir); matrix = Matrix4::FromAxis(right, dir, up, startPos); //Chameleon: teamCol tracers //int colFac = (int)opt_tracers; colour = Vector3(teamCol.x / 255.f, teamCol.y / 255.f, teamCol.z / 255.f); colour = Vector3(colour.x / colour.GetLength(), colour.y / colour.GetLength(), colour.z / colour.GetLength()); colour = (colour + Vector3(1, 1, 1)) / 1.9f; dlight = r_dlights && opt_tracersDLight; }