GLColorBuffer GLDepthOfFieldFilter::UnderSample(GLColorBuffer tex) { SPADES_MARK_FUNCTION(); // do gaussian blur GLProgram *program = passthrough; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); int w = tex.GetWidth(); int h = tex.GetHeight(); static GLProgramAttribute blur_positionAttribute("positionAttribute"); static GLProgramUniform blur_textureUniform("texture"); static GLProgramUniform blur_colorUniform("colorUniform"); static GLProgramUniform blur_texCoordRangeUniform("texCoordRange"); program->Use(); blur_positionAttribute(program); blur_textureUniform(program); blur_textureUniform.SetValue(0); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, tex.GetTexture()); blur_colorUniform(program); blur_colorUniform.SetValue(1.f,1.f,1.f,1.f); blur_texCoordRangeUniform(program); blur_texCoordRangeUniform.SetValue(0.f, 0.f, 1.f, 1.f); qr.SetCoordAttributeIndex(blur_positionAttribute()); dev->Enable(IGLDevice::Blend, false); GLColorBuffer buf2 = renderer->GetFramebufferManager()->CreateBufferHandle(w/2, h/2, false); dev->Viewport(0, 0, w/2, h/2); dev->BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer()); qr.Draw(); return buf2; }
void GLModelRenderer::RenderDynamicLightPass(std::vector<GLDynamicLight> lights) { SPADES_MARK_FUNCTION(); GLProfiler profiler(device, "Model [%d model(s), %d unique model type(s)]", modelCount, (int)models.size()); if(!lights.empty()){ for(size_t i = 0; i < models.size(); i++){ RenderModel& m = models[i]; GLModel *model = m.model; model->RenderDynamicLightPass(m.params, lights); } } // last phase: clear scene for(size_t i = 0; i < models.size(); i++){ models[i].model->renderId = -1; } models.clear(); modelCount = 0; }
GLShader *GLProgramManager::CreateShader(const std::string &name) { SPADES_MARK_FUNCTION(); SPLog("Loading GLSL shader '%s'", name.c_str()); std::string text = FileManager::ReadAllBytes(name.c_str()); GLShader::Type type; if(name.find(".fs") != std::string::npos) type = GLShader::FragmentShader; else if(name.find(".vs") != std::string::npos) type = GLShader::VertexShader; else SPRaise("Failed to determine the type of a shader: %s", name.c_str()); GLShader *s = new GLShader(device, type); s->AddSource(text); Stopwatch sw; s->Compile(); SPLog("Successfully compiled GLSL program '%s' in %.3fms", name.c_str(), sw.GetTime() * 1000.); return s; }
StdStream::~StdStream() { SPADES_MARK_FUNCTION(); if (autoClose) fclose(handle); }
GLColorBuffer GLBloomFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); std::vector<Level> levels; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute thruPosition("positionAttribute"); static GLProgramUniform thruColor("colorUniform"); static GLProgramUniform thruTexture("texture"); static GLProgramUniform thruTexCoordRange("texCoordRange"); thruPosition(thru); thruColor(thru); thruTexture(thru); thruTexCoordRange(thru); GLProgram *gammaMix = renderer->RegisterProgram("Shaders/PostFilters/GammaMix.program"); static GLProgramAttribute gammaMixPosition("positionAttribute"); static GLProgramUniform gammaMixTexture1("texture1"); static GLProgramUniform gammaMixTexture2("texture2"); static GLProgramUniform gammaMixMix1("mix1"); static GLProgramUniform gammaMixMix2("mix2"); gammaMixPosition(gammaMix); gammaMixTexture1(gammaMix); gammaMixTexture2(gammaMix); gammaMixMix1(gammaMix); gammaMixMix2(gammaMix); thru->Use(); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexture.SetValue(0); dev->Enable(IGLDevice::Blend, false); // create downsample levels for(int i = 0; i < 6; i++){ GLColorBuffer prevLevel; if(i == 0){ prevLevel = input; }else{ prevLevel = levels.back().buffer; } int prevW = prevLevel.GetWidth(); int prevH = prevLevel.GetHeight(); int newW = (prevW + 1) / 2; int newH = (prevH + 1) / 2; GLColorBuffer newLevel = input.GetManager()->CreateBufferHandle(newW, newH); thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); dev->BindTexture(IGLDevice::Texture2D, prevLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, newLevel.GetFramebuffer()); dev->Viewport(0, 0, newLevel.GetWidth(), newLevel.GetHeight()); thruTexCoordRange.SetValue(0.f, 0.f, (float)newLevel.GetWidth() * 2.f / (float)prevW, (float)newLevel.GetHeight() * 2.f / (float)prevH); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); Level lv; lv.w = newW; lv.h = newH; lv.buffer = newLevel; levels.push_back(lv); } dev->Enable(IGLDevice::Blend, true); dev->BlendFunc(IGLDevice::SrcAlpha, IGLDevice::OneMinusSrcAlpha); // composite levels in the opposite direction thruTexCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); for(int i = (int)levels.size() - 1; i >= 1; i--){ int cnt = (int)levels.size() - i; float alpha = (float)cnt / (float)(cnt + 1); alpha = sqrtf(alpha); GLColorBuffer curLevel = levels[i].buffer; GLColorBuffer targLevel = levels[i - 1].buffer; thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); dev->BindTexture(IGLDevice::Texture2D, curLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, targLevel.GetFramebuffer()); dev->Viewport(0, 0, targLevel.GetWidth(), targLevel.GetHeight()); thruColor.SetValue(1.f, 1.f, 1.f, alpha); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); } // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); GLColorBuffer topLevel = levels[0].buffer; gammaMix->Use(); qr.SetCoordAttributeIndex(gammaMixPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, topLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); gammaMixTexture1.SetValue(0); gammaMixTexture2.SetValue(1); gammaMixMix1.SetValue(.8f, .8f, .8f); gammaMixMix2.SetValue(.2f, .2f, .2f); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return output; }
virtual void Save(IStream *, Bitmap *) { SPADES_MARK_FUNCTION(); SPNotImplemented(); }
GLVoxelModel::~GLVoxelModel() { SPADES_MARK_FUNCTION(); device->DeleteBuffer(idxBuffer); device->DeleteBuffer(buffer); }
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); }
void GLVoxelModel::Prerender(std::vector<client::ModelRenderParam> params) { SPADES_MARK_FUNCTION(); RenderSunlightPass(params); }
/** Handles movement of joined local player. */ void Client::UpdateLocalPlayer(float dt) { SPADES_MARK_FUNCTION(); auto *player = world->GetLocalPlayer(); PlayerInput inp = playerInput; WeaponInput winp = weapInput; // weapon/tools are disabled while/soon after sprinting if(GetSprintState() > 0.001f) { winp.primary = false; winp.secondary = false; } // don't allow to stand up when ceilings are too low if(inp.crouch == false){ if(player->GetInput().crouch){ if(!player->TryUncrouch(false)){ inp.crouch = true; } } } // don't allow jumping in the air if(inp.jump){ if(!player->IsOnGroundOrWade()) inp.jump = false; } // weapon/tools are disabled while changing tools if(clientPlayers[world->GetLocalPlayerIndex()]->IsChangingTool()) { winp.primary = false; winp.secondary = false; } // disable weapon while reloading (except shotgun) if(player->GetTool() == Player::ToolWeapon && player->IsAwaitingReloadCompletion() && !player->GetWeapon()->IsReloadSlow()) { winp.primary = false; } player->SetInput(inp); player->SetWeaponInput(winp); //send player input // FIXME: send only there are any changed? net->SendPlayerInput(inp); net->SendWeaponInput(winp); if(hasDelayedReload) { world->GetLocalPlayer()->Reload(); net->SendReload(); hasDelayedReload = false; } //PlayerInput actualInput = player->GetInput(); WeaponInput actualWeapInput = player->GetWeaponInput(); if(actualWeapInput.secondary && player->IsToolWeapon() && player->IsAlive()){ }else{ if(player->IsToolWeapon()){ // there is a possibility that player has respawned or something. // stop aiming down weapInput.secondary = false; } } // is the selected tool no longer usable (ex. out of ammo)? if(!player->IsToolSelectable(player->GetTool())) { // release mouse button before auto-switching tools winp.primary = false; winp.secondary = false; weapInput = winp; net->SendWeaponInput(weapInput); actualWeapInput = winp = player->GetWeaponInput(); // select another tool Player::ToolType t = player->GetTool(); do{ switch(t){ case Player::ToolSpade: t = Player::ToolGrenade; break; case Player::ToolBlock: t = Player::ToolSpade; break; case Player::ToolWeapon: t = Player::ToolBlock; break; case Player::ToolGrenade: t = Player::ToolWeapon; break; } }while(!world->GetLocalPlayer()->IsToolSelectable(t)); SetSelectedTool(t); } // send orientation Vector3 curFront = player->GetFront(); if(curFront.x != lastFront.x || curFront.y != lastFront.y || curFront.z != lastFront.z) { lastFront = curFront; net->SendOrientation(curFront); } lastKills = world->GetPlayerPersistent(player->GetId()).kills; // show block count when building block lines. if(player->IsAlive() && player->GetTool() == Player::ToolBlock && player->GetWeaponInput().secondary && player->IsBlockCursorDragging()) { if(player->IsBlockCursorActive()) { auto blocks = std::move (world->CubeLine(player->GetBlockCursorDragPos(), player->GetBlockCursorPos(), 256)); auto msg = _TrN("Client", "{0} block", "{0} blocks", blocks.size()); AlertType type = static_cast<int>(blocks.size()) > player->GetNumBlocks() ? AlertType::Warning : AlertType::Notice; ShowAlert(msg, type, 0.f, true); }else{ // invalid auto msg = _Tr("Client", "-- blocks"); AlertType type = AlertType::Warning; ShowAlert(msg, type, 0.f, true); } } if(player->IsAlive()) lastAliveTime = time; if(player->GetHealth() < lastHealth){ // ouch! lastHealth = player->GetHealth(); lastHurtTime = world->GetTime(); Handle<IAudioChunk> c; switch((rand() >> 3) & 3){ case 0: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal1.wav"); break; case 1: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal2.wav"); break; case 2: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal3.wav"); break; case 3: c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal4.wav"); break; } audioDevice->PlayLocal(c, AudioParam()); float hpper = player->GetHealth() / 100.f; int cnt = 18 - (int)(player->GetHealth() / 100.f * 8.f); hurtSprites.resize(std::max(cnt, 6)); for(size_t i = 0; i < hurtSprites.size(); i++) { HurtSprite& spr = hurtSprites[i]; spr.angle = GetRandom() * (2.f * static_cast<float>(M_PI)); spr.scale = .2f + GetRandom() * GetRandom() * .7f; spr.horzShift = GetRandom(); spr.strength = .3f + GetRandom() * .7f; if(hpper > .5f) { spr.strength *= 1.5f - hpper; } } }else{
Weapon::~Weapon(){ SPADES_MARK_FUNCTION(); }
virtual Bitmap *Load(IStream *stream) { SPADES_MARK_FUNCTION(); // read all std::string data = stream->ReadAllBytes(); // copy to buffer Fl_Image *img = LoadFltkImage(data); SPAssert(img); SPAssert(img->count() >= 1); const unsigned char* inPixels = (const unsigned char *)img->data()[0]; int depth = img->d(); int width = img->w(); int height = img->h(); int pitch = width * depth + img->ld(); Handle<Bitmap> bmp; try { bmp = new Bitmap(width, height); } catch(...) { delete img; throw; } try { unsigned char *outPixels = (unsigned char *)bmp->GetPixels(); if(pitch == width * 4 && depth == 4) { // if the format matches the requirement of Bitmap, // just use it memcpy(outPixels, inPixels, pitch * height); } else { // convert const unsigned char* line; for(int y = 0; y < height; y++) { line = inPixels; for(int x = 0; x < width; x++) { uint8_t r, g, b, a; switch(depth) { case 1: r = g = b = *(line++); a = 255; break; case 2: r = g = b = *(line++); a = *(line++); break; case 3: r = *(line++); g = *(line++); b = *(line++); a = 255; break; case 4: r = *(line++); g = *(line++); b = *(line++); a = *(line++); break; default: SPAssert(false); } *(outPixels++) = r; *(outPixels++) = g; *(outPixels++) = b; *(outPixels++) = a; } inPixels += pitch; } } delete img; return bmp.Unmanage(); } catch(...) { delete img; throw; } }
void GLSpriteRenderer::Render() { SPADES_MARK_FUNCTION(); lastImage = NULL; program->Use(); projectionViewMatrix(program); rightVector(program); upVector(program); texture(program); viewMatrix(program); fogDistance(program); fogColor(program); positionAttribute(program); spritePosAttribute(program); colorAttribute(program); projectionViewMatrix.SetValue(renderer->GetProjectionViewMatrix()); viewMatrix.SetValue(renderer->GetViewMatrix()); fogDistance.SetValue(renderer->GetFogDistance()); Vector3 fogCol = renderer->GetFogColor(); fogColor.SetValue(fogCol.x,fogCol.y,fogCol.z); const client::SceneDefinition& def = renderer->GetSceneDef(); rightVector.SetValue(def.viewAxis[0].x, def.viewAxis[0].y, def.viewAxis[0].z); upVector.SetValue(def.viewAxis[1].x, def.viewAxis[1].y, def.viewAxis[1].z); texture.SetValue(0); device->ActiveTexture(0); device->EnableVertexAttribArray(positionAttribute(), true); device->EnableVertexAttribArray(spritePosAttribute(), true); device->EnableVertexAttribArray(colorAttribute(), true); for(size_t i = 0; i < sprites.size(); i++){ Sprite& spr = sprites[i]; if(spr.image != lastImage){ Flush(); lastImage = spr.image; SPAssert(vertices.empty()); } Vertex v; v.x = spr.center.x; v.y = spr.center.y; v.z = spr.center.z; v.radius = spr.radius; v.angle = spr.angle; v.r = spr.color.x; v.g = spr.color.y; v.b = spr.color.z; v.a = spr.color.w; uint32_t idx = (uint32_t)vertices.size(); v.sx = -1; v.sy = -1; vertices.push_back(v); v.sx = 1; v.sy = -1; vertices.push_back(v); v.sx = -1; v.sy = 1; vertices.push_back(v); v.sx = 1; v.sy = 1; vertices.push_back(v); indices.push_back(idx); indices.push_back(idx + 1); indices.push_back(idx + 2); indices.push_back(idx + 1); indices.push_back(idx + 3); indices.push_back(idx + 2); } Flush(); device->EnableVertexAttribArray(positionAttribute(), false); device->EnableVertexAttribArray(spritePosAttribute(), false); device->EnableVertexAttribArray(colorAttribute(), false); }
void GLSpriteRenderer::Clear(){ SPADES_MARK_FUNCTION(); sprites.clear(); }
GLSpriteRenderer::~GLSpriteRenderer(){ SPADES_MARK_FUNCTION(); }
StartupScreen::~StartupScreen() { SPADES_MARK_FUNCTION(); helper->StartupScreenDestroyed(); }
bool StartupScreen::NeedsAbsoluteMouseCoordinate() { SPADES_MARK_FUNCTION(); return true; }
GLColorBuffer GLColorCorrectionFilter::Filter(GLColorBuffer input, Vector3 tintVal) { SPADES_MARK_FUNCTION(); IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute lensPosition("positionAttribute"); static GLProgramUniform lensTexture("mainTexture"); static GLProgramUniform saturation("saturation"); static GLProgramUniform enhancement("enhancement"); static GLProgramUniform tint("tint"); saturation(lens); enhancement(lens); tint(lens); dev->Enable(IGLDevice::Blend, false); lensPosition(lens); lensTexture(lens); lens->Use(); tint.SetValue(tintVal.x, tintVal.y, tintVal.z); const client::SceneDefinition &def = renderer->GetSceneDef(); if (settings.r_hdr) { // when HDR is enabled ACES tone mapping is applied first, so // lower enhancement value is required if (settings.r_bloom) { saturation.SetValue(0.8f * def.saturation * settings.r_saturation); enhancement.SetValue(0.1f); } else { saturation.SetValue(0.9f * def.saturation * settings.r_saturation); enhancement.SetValue(0.0f); } } else { if (settings.r_bloom) { // make image sharper saturation.SetValue(.85f * def.saturation * settings.r_saturation); enhancement.SetValue(0.7f); } else { saturation.SetValue(1.f * def.saturation * settings.r_saturation); enhancement.SetValue(0.3f); } } lensTexture.SetValue(0); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); qr.SetCoordAttributeIndex(lensPosition()); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); return output; }
void GLVoxelModel::RenderShadowMapPass(std::vector<client::ModelRenderParam> params) { SPADES_MARK_FUNCTION(); device->Enable(IGLDevice::CullFace, true); device->Enable(IGLDevice::DepthTest, true); shadowMapProgram->Use(); static GLShadowMapShader shadowMapShader; shadowMapShader(renderer, shadowMapProgram, 0); static GLProgramUniform modelOrigin("modelOrigin"); modelOrigin(shadowMapProgram); modelOrigin.SetValue(origin.x, origin.y, origin.z); // setup attributes static GLProgramAttribute positionAttribute("positionAttribute"); static GLProgramAttribute normalAttribute("normalAttribute"); positionAttribute(shadowMapProgram); normalAttribute(shadowMapProgram); device->BindBuffer(IGLDevice::ArrayBuffer, buffer); device->VertexAttribPointer(positionAttribute(), 4, IGLDevice::UnsignedByte, false, sizeof(Vertex), (void *)0); if (normalAttribute() != -1) { device->VertexAttribPointer(normalAttribute(), 3, IGLDevice::Byte, false, sizeof(Vertex), (void *)12); } device->BindBuffer(IGLDevice::ArrayBuffer, 0); device->EnableVertexAttribArray(positionAttribute(), true); if (normalAttribute() != -1) 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 (param.depthHack) continue; if (!renderer->GetShadowMapRenderer()->SphereCull(param.matrix.GetOrigin(), rad)) { continue; } Matrix4 modelMatrix = param.matrix; static GLProgramUniform modelMatrixU("modelMatrix"); modelMatrixU(shadowMapProgram); modelMatrixU.SetValue(modelMatrix); modelMatrix.m[12] = 0.f; modelMatrix.m[13] = 0.f; modelMatrix.m[14] = 0.f; static GLProgramUniform modelNormalMatrix("modelNormalMatrix"); modelNormalMatrix(shadowMapProgram); modelNormalMatrix.SetValue(modelMatrix); device->DrawElements(IGLDevice::Triangles, numIndices, IGLDevice::UnsignedInt, (void *)0); } device->BindBuffer(IGLDevice::ElementArrayBuffer, 0); device->EnableVertexAttribArray(positionAttribute(), false); if (normalAttribute() != -1) device->EnableVertexAttribArray(normalAttribute(), false); device->ActiveTexture(0); device->BindTexture(IGLDevice::Texture2D, 0); }
void Player::SetVelocity(const spades::Vector3 &v) { SPADES_MARK_FUNCTION(); velocity = v; }
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); }
void Player::SetOrientation(const spades::Vector3 &v) { SPADES_MARK_FUNCTION(); orientation = v; }
int main(int argc, char ** argv) { #ifdef WIN32 SetUnhandledExceptionFilter( UnhandledExceptionProc ); #endif for(int i = 1; i < argc;) { int ret = argsHandler(argc, argv, i); if(!ret) { // ignore unknown arg i++; } } if ( cg_printVersion ) { printf( "%s\n", PACKAGE_STRING ); return 0; } if ( cg_printHelp ) { printHelp( argv[0] ); return 0; } std::unique_ptr<SplashWindow> splashWindow; try{ // start recording backtrace spades::reflection::Backtrace::StartBacktrace(); SPADES_MARK_FUNCTION(); // show splash window // NOTE: splash window uses image loader, which assumes backtrace is already initialized. splashWindow.reset(new SplashWindow()); auto showSplashWindowTime = SDL_GetTicks(); auto pumpEvents = [&splashWindow] { splashWindow->PumpEvents(); }; // initialize threads spades::Thread::InitThreadSystem(); spades::DispatchQueue::GetThreadQueue()->MarkSDLVideoThread(); SPLog("Package: " PACKAGE_STRING); // setup user-specific default resource directories #ifdef WIN32 static wchar_t buf[4096]; GetModuleFileNameW(NULL, buf, 4096); std::wstring appdir = buf; appdir = appdir.substr(0, appdir.find_last_of(L'\\')+1); if(SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, buf))){ std::wstring datadir = buf; datadir += L"\\OpenSpades\\Resources"; spades::FileManager::AddFileSystem(new spades::DirectoryFileSystem(Utf8FromWString(datadir.c_str()), true)); } spades::FileManager::AddFileSystem(new spades::DirectoryFileSystem(Utf8FromWString((appdir + L"Resources").c_str()), false)); //fltk has a console window on windows (can disable while building, maybe use a builtin console for a later release?) HWND hCon = GetConsoleWindow(); if( NULL != hCon ) { setIcon( hCon ); } #elif defined(__APPLE__) std::string home = getenv("HOME"); spades::FileManager::AddFileSystem (new spades::DirectoryFileSystem("./Resources", false)); // OS X application is made of Bundle, which contains its own Resources directory. { char *baseDir = SDL_GetBasePath(); if(baseDir) { spades::FileManager::AddFileSystem (new spades::DirectoryFileSystem(baseDir, false)); SDL_free(baseDir); } } spades::FileManager::AddFileSystem (new spades::DirectoryFileSystem(home+"/Library/Application Support/OpenSpades/Resources", true)); #else std::string home = getenv("HOME"); spades::FileManager::AddFileSystem (new spades::DirectoryFileSystem("./Resources", false)); spades::FileManager::AddFileSystem(new spades::DirectoryFileSystem(CMAKE_INSTALL_PREFIX "/" OPENSPADES_INSTALL_RESOURCES, false)); std::string xdg_data_home = home+"/.local/share"; if (getenv("XDG_DATA_HOME") == NULL) { SPLog("XDG_DATA_HOME not defined. Assuming that XDG_DATA_HOME is ~/.local/share"); } else { std::string xdg_data_home = getenv("XDG_DATA_HOME"); SPLog("XDG_DATA_HOME is %s", xdg_data_home.c_str()); } struct stat info; if ( stat((xdg_data_home+"/openspades").c_str(), &info ) != 0 ) { if ( stat((home+"/.openspades").c_str(), &info ) != 0) { } else if( info.st_mode & S_IFDIR ) { SPLog("Openspades directory in XDG_DATA_HOME not found, though old directory exists. Trying to resolve compatibility problem."); if (rename( (home+"/.openspades").c_str() , (xdg_data_home+"/openspades").c_str() ) != 0) { SPLog("Failed to move old directory to new."); } else { SPLog("Successfully moved old directory."); if (mkdir((home+"/.openspades").c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0) { SDL_RWops *io = SDL_RWFromFile((home+"/.openspades/CONTENT_MOVED_TO_NEW_DIR").c_str(), "wb"); if (io != NULL) { const char* text = ("Content of this directory moved to "+xdg_data_home+"/openspades").c_str(); io->write(io, text, strlen(text), 1); io->close(io); } } } } } spades::FileManager::AddFileSystem (new spades::DirectoryFileSystem(xdg_data_home+"/openspades/Resources", true)); #endif // start log output to SystemMessages.log try{ spades::StartLog(); }catch(const std::exception& ex){ SDL_InitSubSystem(SDL_INIT_VIDEO); auto msg = spades::Format("Failed to start recording log because of the following error:\n{0}\n\n" "OpenSpades will continue to run, but any critical events are not logged.", ex.what()); if(SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "OpenSpades Log System Failure", msg.c_str(), splashWindow->GetWindow())) { // showing dialog failed. } } SPLog("Log Started."); // load preferences. spades::Settings::GetInstance()->Load(); pumpEvents(); // dump CPU info (for debugging?) { spades::CpuID cpuid; SPLog("---- CPU Information ----"); SPLog("Vendor ID: %s", cpuid.GetVendorId().c_str()); SPLog("Brand ID: %s", cpuid.GetBrand().c_str()); SPLog("Supports MMX: %s", cpuid.Supports(spades::CpuFeature::MMX)?"YES":"NO"); SPLog("Supports SSE: %s", cpuid.Supports(spades::CpuFeature::SSE)?"YES":"NO"); SPLog("Supports SSE2: %s", cpuid.Supports(spades::CpuFeature::SSE2)?"YES":"NO"); SPLog("Supports SSE3: %s", cpuid.Supports(spades::CpuFeature::SSE3)?"YES":"NO"); SPLog("Supports SSSE3: %s", cpuid.Supports(spades::CpuFeature::SSSE3)?"YES":"NO"); SPLog("Supports FMA: %s", cpuid.Supports(spades::CpuFeature::FMA)?"YES":"NO"); SPLog("Supports AVX: %s", cpuid.Supports(spades::CpuFeature::AVX)?"YES":"NO"); SPLog("Supports AVX2: %s", cpuid.Supports(spades::CpuFeature::AVX2)?"YES":"NO"); SPLog("Supports AVX512F: %s", cpuid.Supports(spades::CpuFeature::AVX512F)?"YES":"NO"); SPLog("Supports AVX512CD: %s", cpuid.Supports(spades::CpuFeature::AVX512CD)?"YES":"NO"); SPLog("Supports AVX512ER: %s", cpuid.Supports(spades::CpuFeature::AVX512ER)?"YES":"NO"); SPLog("Supports AVX512PF: %s", cpuid.Supports(spades::CpuFeature::AVX512PF)?"YES":"NO"); SPLog("Simultaneous Multithreading: %s", cpuid.Supports(spades::CpuFeature::SimultaneousMT)?"YES":"NO"); SPLog("Misc:"); SPLog("%s", cpuid.GetMiscInfo().c_str()); SPLog("-------------------------"); } // register resource directory specified by Makefile (or something) #if defined(RESDIR_DEFINED) spades::FileManager::AddFileSystem(new spades::DirectoryFileSystem(RESDIR, false)); #endif // search current file system for .pak files { std::vector<spades::IFileSystem*> fss; std::vector<spades::IFileSystem*> fssImportant; std::vector<std::string> files = spades::FileManager::EnumFiles(""); struct Comparator { static int GetPakId(const std::string& str) { if(str.size() >= 4 && str[0] == 'p' && str[1] == 'a' && str[2] == 'k' && (str[3] >= '0' && str[3] <= '9')){ return atoi(str.c_str() + 3); }else{ return 32767; } } static bool Compare(const std::string& a, const std::string& b) { int pa = GetPakId(a); int pb = GetPakId(b); if(pa == pb){ return a < b; }else{ return pa < pb; } } }; std::sort(files.begin(), files.end(), Comparator::Compare); for(size_t i = 0; i < files.size(); i++){ std::string name = files[i]; // check extension if(name.size() < 4 || name.rfind(".pak") != name.size() - 4){ continue; } if(spades::FileManager::FileExists(name.c_str())) { spades::IStream *stream = spades::FileManager::OpenForReading(name.c_str()); spades::ZipFileSystem *fs = new spades::ZipFileSystem(stream); if(name[0] == '_' && false) { // last resort for #198 SPLog("Pak Registered: %s (marked as 'important')\n", name.c_str()); fssImportant.push_back(fs); }else{ SPLog("Pak Registered: %s\n", name.c_str()); fss.push_back(fs); } } } for(size_t i = fss.size(); i > 0; i--){ spades::FileManager::AppendFileSystem(fss[i - 1]); } for(size_t i = 0; i < fssImportant.size(); i++){ spades::FileManager::PrependFileSystem(fssImportant[i]); } } pumpEvents(); // initialize localization system SPLog("Initializing localization system"); spades::LoadCurrentLocale(); _Tr("Main", "Localization System Loaded"); pumpEvents(); // parse args // initialize AngelScript SPLog("Initializing script engine"); spades::ScriptManager::GetInstance(); pumpEvents(); ThreadQuantumSetter quantumSetter; (void)quantumSetter; // suppress "unused variable" warning SDL_InitSubSystem(SDL_INIT_VIDEO); // we want to show splash window at least for some time... pumpEvents(); auto ticks = SDL_GetTicks(); if(ticks < showSplashWindowTime + 1500) { SDL_Delay(showSplashWindowTime + 1500 - ticks); } pumpEvents(); // everything is now ready! if( !cg_autoConnect ) { if(!((int)cl_showStartupWindow != 0 || splashWindow->IsStartupScreenRequested())) { splashWindow.reset(); SPLog("Starting main screen"); spades::StartMainScreen(); }else{ splashWindow.reset(); SPLog("Starting startup window"); ::spades::gui::StartupScreen::Run(); } } else { splashWindow.reset(); spades::ServerAddress host(cg_lastQuickConnectHost.CString(), (int)cg_protocolVersion == 3 ? spades::ProtocolVersion::v075 : spades::ProtocolVersion::v076 ); spades::StartClient(host, cg_playerName); } spades::Settings::GetInstance()->Flush(); }catch(const ExitRequestException&){ // user changed his mind. }catch(const std::exception& ex) { try { splashWindow.reset(nullptr); }catch(...){ } std::string msg = ex.what(); msg = _Tr("Main", "A serious error caused OpenSpades to stop working:\n\n{0}\n\nSee SystemMessages.log for more details.", msg); SPLog("[!] Terminating due to the fatal error: %s", ex.what()); SDL_InitSubSystem(SDL_INIT_VIDEO); if(SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, _Tr("Main", "OpenSpades Fatal Error").c_str(), msg.c_str(), nullptr)) { // showing dialog failed. // TODO: do appropriate action } } return 0; }
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){ UseSpade(); nextSpadeTime = world->GetTime() + GetToolPrimaryDelay(); } }else if(weapInput.secondary){ if(world->GetTime() > nextDigTime){ DigWithSpade(); nextDigTime = world->GetTime() + GetToolSecondaryDelay(); firstDig = false; } } }else if(tool == ToolBlock && IsLocalPlayer()){ GameMap::RayCastResult result; auto *map = GetWorld()->GetMap(); result = map->CastRay2(GetEye(), GetFront(), 12); canPending = false; if(blockCursorDragging) { // check the starting point is not floating auto start = blockCursorDragPos; if(map->IsSolidWrapped(start.x-1, start.y, start.z) || map->IsSolidWrapped(start.x, start.y-1, start.z) || map->IsSolidWrapped(start.x, start.y, start.z-1) || map->IsSolidWrapped(start.x+1, start.y, start.z) || map->IsSolidWrapped(start.x, start.y+1, start.z) || map->IsSolidWrapped(start.x, start.y, start.z+1)) { // still okay }else{ // cannot build; floating if(listener && this == world->GetLocalPlayer()) { listener-> LocalPlayerBuildError(BuildFailureReason::InvalidPosition); } 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. if(airborne == false || blockStocks <= 0){ // player is no longer airborne, or doesn't have a block to place. pendingPlaceBlock = false; lastSingleBlockBuildSeqDone = true; if(blockStocks > 0) { // cannot build; invalid position. } }else if((!OverlapsWithOneBlock(pendingPlaceBlockPos)) && 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 && BoxDistanceToBlock(result.hitBlock + result.normal) > 3.f ; dist--) { result = GetWorld()->GetMap()->CastRay2(GetEye(), GetFront(), dist); } for(; dist < 12 && BoxDistanceToBlock(result.hitBlock + result.normal) < 3.f ; dist++) { result = GetWorld()->GetMap()->CastRay2(GetEye(), GetFront(), dist); } blockCursorPos = result.hitBlock + result.normal; } }else if(tool == ToolWeapon){ }else if(tool == ToolGrenade){ if(holdingGrenade){ if(world->GetTime() - grenadeTime > 2.9f){ ThrowGrenade(); } } } if(tool != ToolWeapon) weapon->SetShooting(false); if(weapon->FrameNext(dt)){ FireWeapon(); } if(weapon->IsReloading()) { lastReloadingTime = world->GetTime(); }else if(reloadingServerSide) { // for some reason a server didn't return // WeaponReload packet. if(world->GetTime() + lastReloadingTime + .8f) { reloadingServerSide = false; weapon->ForceReloadDone(); } } }
Bitmap::~Bitmap() { SPADES_MARK_FUNCTION(); if(autoDelete) delete[] pixels; }
void Player::FireWeapon() { SPADES_MARK_FUNCTION(); Vector3 muzzle = GetEye(); muzzle += GetFront() * 0.01f; // for hit-test debugging std::map<int, HitTestDebugger::PlayerHit> playerHits; std::vector<Vector3> 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) continue; if(other == this || !other->IsAlive() || other->GetTeamId() >= 2) continue; // 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 = (hitPos - muzzle).GetLength(); if(hitPlayer == NULL || dist < hitPlayerDistance){ hitPlayer = other; hitPlayerDistance = dist; hitPart = HitBodyPart::Head; } } if(hb.torso.RayCast(muzzle, dir, &hitPos)) { float dist = (hitPos - muzzle).GetLength(); if(hitPlayer == NULL || dist < hitPlayerDistance){ hitPlayer = other; hitPlayerDistance = dist; hitPart = HitBodyPart::Torso; } } for(int j = 0; j < 3 ;j++){ if(hb.limbs[j].RayCast(muzzle, dir, &hitPos)) { float dist = (hitPos - muzzle).GetLength(); if(hitPlayer == NULL || dist < hitPlayerDistance){ hitPlayer = other; hitPlayerDistance = dist; switch(j) { case 0: hitPart = HitBodyPart::Limb1; break; case 1: hitPart = HitBodyPart::Limb2; break; case 2: hitPart = HitBodyPart::Arms; break; } } } } } Vector3 finalHitPos; finalHitPos = muzzle + dir * 128.f; if(hitPlayer == nullptr && !mapResult.hit) { // might hit water surface. } if(mapResult.hit && (mapResult.hitPos - muzzle).GetLength() < 128.f && (hitPlayer == NULL || (mapResult.hitPos - muzzle).GetLength() < 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()){ if(outBlockCoord.z == 63) { if(world->GetListener()) world->GetListener()->BulletHitBlock(mapResult.hitPos, mapResult.hitBlock, mapResult.normal); }else if(outBlockCoord.z == 62) { // blocks at this level cannot be damaged if(world->GetListener()) world->GetListener()->BulletHitBlock(mapResult.hitPos, mapResult.hitBlock, mapResult.normal); }else{ int x = outBlockCoord.x; int y = outBlockCoord.y; int z = outBlockCoord.z; SPAssert(map->IsSolid(x, y, z)); Vector3 blockF = {x + .5f, y + .5f, z + .5f}; float distance = (blockF - muzzle).GetLength(); uint32_t color = map->GetColor(x, y, z); int health = color >> 24; health -= weapon->GetDamage(HitTypeBlock, distance); if(health <= 0 && !blockDestroyed){ health = 0; blockDestroyed = true; //send destroy cmd if(world->GetListener() && 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){
StdStream::StdStream(FILE *f, bool ac) : handle(f), autoClose(ac) { SPADES_MARK_FUNCTION(); if (!f) SPInvalidArgument("f"); }
GLProgramManager::GLProgramManager(IGLDevice *d, IGLShadowMapRenderer *smr, GLSettings &settings): device(d), shadowMapRenderer(smr), settings(settings) { SPADES_MARK_FUNCTION(); }
GLColorBuffer GLLensDustFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); UpdateNoise(); std::vector<Level> levels; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute thruPosition("positionAttribute"); static GLProgramUniform thruColor("colorUniform"); static GLProgramUniform thruTexture("mainTexture"); static GLProgramUniform thruTexCoordRange("texCoordRange"); thruPosition(thru); thruColor(thru); thruTexture(thru); thruTexCoordRange(thru); GLColorBuffer downSampled = DownSample(input, r_hdr ? false : true); downSampled = GaussianBlur(downSampled, false); downSampled = GaussianBlur(downSampled, true); thru->Use(); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexture.SetValue(0); dev->Enable(IGLDevice::Blend, false); levels.reserve(10); // create downsample levels for(int i = 0; i < 10; i++){ GLColorBuffer prevLevel; if(i == 0){ prevLevel = downSampled; }else{ prevLevel = levels.back().buffer; } int prevW = prevLevel.GetWidth(); int prevH = prevLevel.GetHeight(); int newW = (prevW + 1) / 2; int newH = (prevH + 1) / 2; if(newW <= 1 || newH <= 1) break; GLColorBuffer newLevel = DownSample(prevLevel); newLevel = GaussianBlur(newLevel, false); newLevel = GaussianBlur(newLevel, true); Level lv; lv.w = newW; lv.h = newH; lv.buffer = newLevel; levels.push_back(lv); } dev->Enable(IGLDevice::Blend, true); dev->BlendFunc(IGLDevice::SrcAlpha, IGLDevice::OneMinusSrcAlpha); // composite levels in the opposite direction thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); for(int i = (int)levels.size() - 1; i >= 1; i--){ int cnt = (int)levels.size() - i; float alpha = (float)cnt / (float)(cnt + 1); alpha = alpha; GLColorBuffer curLevel = levels[i].buffer; float sx = .25f / curLevel.GetWidth(); float sy = .25f / curLevel.GetHeight(); for(int j = 0; j < 4; j++) { if(i < (int)levels.size() - 1) { curLevel = levels[i].retBuf[j]; } GLColorBuffer targLevel = levels[i - 1].buffer; GLColorBuffer targRet = input.GetManager()->CreateBufferHandle(targLevel.GetWidth(), targLevel.GetHeight(), false); levels[i - 1].retBuf[j] = targRet; dev->BindFramebuffer(IGLDevice::Framebuffer, targRet.GetFramebuffer()); dev->Viewport(0, 0, targRet.GetWidth(), targRet.GetHeight()); dev->BindTexture(IGLDevice::Texture2D, targLevel.GetTexture()); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); dev->Enable(IGLDevice::Blend, false); qr.Draw(); float cx = 0.f, cy = 0.f; switch(j){ case 0: cx = sx; break; case 1: cx = -sx; break; case 2: cy = sy; break; case 3: cy = -sy; break; } dev->BindTexture(IGLDevice::Texture2D, curLevel.GetTexture()); thruColor.SetValue(1.f, 1.f, 1.f, alpha); thruTexCoordRange.SetValue(cx, cy, 1.f, 1.f); dev->Enable(IGLDevice::Blend, true); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); } } static GLProgramAttribute dustPosition("positionAttribute"); static GLProgramUniform dustDustTexture("dustTexture"); static GLProgramUniform dustBlurTexture1("blurTexture1"); static GLProgramUniform dustBlurTexture2("blurTexture2"); static GLProgramUniform dustBlurTexture3("blurTexture3"); static GLProgramUniform dustBlurTexture4("blurTexture4"); static GLProgramUniform dustInputTexture("inputTexture"); static GLProgramUniform dustNoiseTexture("noiseTexture"); static GLProgramUniform dustNoiseTexCoordFactor("noiseTexCoordFactor"); dustPosition(dust); dustDustTexture(dust); dustBlurTexture1(dust); dustBlurTexture2(dust); dustBlurTexture3(dust); dustBlurTexture4(dust); dustInputTexture(dust); dustNoiseTexture(dust); dustNoiseTexCoordFactor(dust); dust->Use(); float facX = renderer->ScreenWidth() / 128.f; float facY = renderer->ScreenHeight() / 128.f; dustNoiseTexCoordFactor.SetValue(facX, facY, facX / 128.f, facY / 128.f); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); GLColorBuffer topLevel1 = levels[0].retBuf[0]; GLColorBuffer topLevel2 = levels[0].retBuf[1]; GLColorBuffer topLevel3 = levels[0].retBuf[2]; GLColorBuffer topLevel4 = levels[0].retBuf[3]; qr.SetCoordAttributeIndex(dustPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, topLevel1.GetTexture()); dev->ActiveTexture(2); dev->BindTexture(IGLDevice::Texture2D, topLevel2.GetTexture()); dev->ActiveTexture(3); dev->BindTexture(IGLDevice::Texture2D, topLevel3.GetTexture()); dev->ActiveTexture(4); dev->BindTexture(IGLDevice::Texture2D, topLevel4.GetTexture()); dev->ActiveTexture(5); dustImg->Bind(IGLDevice::Texture2D); dev->ActiveTexture(6); dev->BindTexture(IGLDevice::Texture2D, noiseTex); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); dustBlurTexture1.SetValue(2); dustBlurTexture2.SetValue(1); dustBlurTexture3.SetValue(3); dustBlurTexture4.SetValue(4); dustDustTexture.SetValue(5); dustNoiseTexture.SetValue(6); dustInputTexture.SetValue(0); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return output; }
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;