void Model::SetMesh(Mesh* mesh) { #if NAZARA_GRAPHICS_SAFE if (mesh && !mesh->IsValid()) { NazaraError("Invalid mesh"); return; } #endif m_mesh = mesh; if (m_mesh) { m_matCount = mesh->GetMaterialCount(); m_materials.clear(); m_materials.resize(m_matCount, Material::GetDefault()); m_skinCount = 1; } else { m_matCount = 0; m_materials.clear(); m_skinCount = 0; } InvalidateBoundingVolume(); }
void GraphicsComponent::OnNodeInvalidated(const Nz::Node* node) { NazaraUnused(node); // Our view matrix depends on NodeComponent position/rotation InvalidateBoundingVolume(); InvalidateTransformMatrix(); for (VolumeCullingEntry& entry : m_volumeCullingEntries) entry.listEntry.ForceInvalidation(); //< Force invalidation on movement }
/*! * \brief Attaches a renderable to the entity with a specific matrix * * \param renderable Reference to a renderable element * \param localMatrix Local matrix that will be applied to the instanced renderable * \param renderOrder Render order of the element */ void GraphicsComponent::Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder) { m_renderables.emplace_back(m_transformMatrix); Renderable& r = m_renderables.back(); r.data.localMatrix = localMatrix; r.data.renderOrder = renderOrder; r.renderable = std::move(renderable); r.renderableBoundingVolumeInvalidationSlot.Connect(r.renderable->OnInstancedRenderableInvalidateBoundingVolume, [this] (const Nz::InstancedRenderable*) { InvalidateBoundingVolume(); }); r.renderableDataInvalidationSlot.Connect(r.renderable->OnInstancedRenderableInvalidateData, std::bind(&GraphicsComponent::InvalidateRenderableData, this, std::placeholders::_1, std::placeholders::_2, m_renderables.size() - 1)); r.renderableReleaseSlot.Connect(r.renderable->OnInstancedRenderableRelease, this, &GraphicsComponent::Detach); InvalidateBoundingVolume(); }
void NzSkeletalModel::AdvanceAnimation(float elapsedTime) { #if NAZARA_GRAPHICS_SAFE if (!m_animation) { NazaraError("Model has no animation"); return; } #endif m_interpolation += m_currentSequence->frameRate * elapsedTime; while (m_interpolation > 1.f) { m_interpolation -= 1.f; unsigned lastFrame = m_currentSequence->firstFrame + m_currentSequence->frameCount - 1; if (m_nextFrame+1 > lastFrame) { if (m_animation->IsLoopPointInterpolationEnabled()) { m_currentFrame = m_nextFrame; m_nextFrame = m_currentSequence->firstFrame; } else { m_currentFrame = m_currentSequence->firstFrame; m_nextFrame = m_currentFrame+1; } } else { m_currentFrame = m_nextFrame; m_nextFrame++; } } m_animation->AnimateSkeleton(&m_skeleton, m_currentFrame, m_nextFrame, m_interpolation); InvalidateBoundingVolume(); }
NzSkeleton* NzSkeletalModel::GetSkeleton() { InvalidateBoundingVolume(); return &m_skeleton; }
void TextSprite::Update(const AbstractTextDrawer& drawer) { CallOnExit clearOnFail([this]() { Clear(); }); // Mark every atlas as unused... for (auto& pair : m_atlases) pair.second.used = false; // ... until they are marked as used by the drawer std::size_t fontCount = drawer.GetFontCount(); for (std::size_t i = 0; i < fontCount; ++i) { Font* font = drawer.GetFont(i); const AbstractAtlas* atlas = font->GetAtlas().get(); NazaraAssert(atlas->GetStorage() & DataStorage_Hardware, "Font uses a non-hardware atlas which cannot be used by text sprites"); auto it = m_atlases.find(atlas); if (it == m_atlases.end()) { it = m_atlases.insert(std::make_pair(atlas, AtlasSlots())).first; AtlasSlots& atlasSlots = it->second; atlasSlots.clearSlot.Connect(atlas->OnAtlasCleared, this, &TextSprite::OnAtlasInvalidated); atlasSlots.layerChangeSlot.Connect(atlas->OnAtlasLayerChange, this, &TextSprite::OnAtlasLayerChange); atlasSlots.releaseSlot.Connect(atlas->OnAtlasRelease, this, &TextSprite::OnAtlasInvalidated); } it->second.used = true; } // Remove unused atlas slots auto atlasIt = m_atlases.begin(); while (atlasIt != m_atlases.end()) { if (!atlasIt->second.used) m_atlases.erase(atlasIt++); else ++atlasIt; } std::size_t glyphCount = drawer.GetGlyphCount(); m_localVertices.resize(glyphCount * 4); // Reset glyph count for every texture to zero for (auto& pair : m_renderInfos) pair.second.count = 0; // Count glyph count for each texture Texture* lastTexture = nullptr; unsigned int* count = nullptr; for (std::size_t i = 0; i < glyphCount; ++i) { const AbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i); Texture* texture = static_cast<Texture*>(glyph.atlas); if (lastTexture != texture) { auto it = m_renderInfos.find(texture); if (it == m_renderInfos.end()) it = m_renderInfos.insert(std::make_pair(texture, RenderIndices{0U, 0U})).first; count = &it->second.count; lastTexture = texture; } (*count)++; } // Attributes indices and reinitialize glyph count to zero to use it as a counter in the next loop // This is because the 1st glyph can use texture A, the 2nd glyph can use texture B and the 3th glyph C can use texture A again // so we need a counter to know where to write informations // also remove unused render infos unsigned int index = 0; auto infoIt = m_renderInfos.begin(); while (infoIt != m_renderInfos.end()) { RenderIndices& indices = infoIt->second; if (indices.count == 0) m_renderInfos.erase(infoIt++); //< No glyph uses this texture, remove from indices else { indices.first = index; index += indices.count; indices.count = 0; ++infoIt; } } lastTexture = nullptr; RenderIndices* indices = nullptr; for (unsigned int i = 0; i < glyphCount; ++i) { const AbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i); Texture* texture = static_cast<Texture*>(glyph.atlas); if (lastTexture != texture) { indices = &m_renderInfos[texture]; //< We changed texture, adjust the pointer lastTexture = texture; } // First, compute the uv coordinates from our atlas rect Vector2ui size(texture->GetSize()); float invWidth = 1.f / size.x; float invHeight = 1.f / size.y; Rectf uvRect(glyph.atlasRect); uvRect.x *= invWidth; uvRect.y *= invHeight; uvRect.width *= invWidth; uvRect.height *= invHeight; // Our glyph may be flipped in the atlas, to render it correctly we need to change the uv coordinates accordingly const RectCorner normalCorners[4] = {RectCorner_LeftTop, RectCorner_RightTop, RectCorner_LeftBottom, RectCorner_RightBottom}; const RectCorner flippedCorners[4] = {RectCorner_LeftBottom, RectCorner_LeftTop, RectCorner_RightBottom, RectCorner_RightTop}; // Set the position, color and UV of our vertices for (unsigned int j = 0; j < 4; ++j) { // Remember that indices->count is a counter here, not a count value m_localVertices[indices->count * 4 + j].color = glyph.color; m_localVertices[indices->count * 4 + j].position.Set(glyph.corners[j]); m_localVertices[indices->count * 4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j])); } // Increment the counter, go to next glyph indices->count++; } m_localBounds = drawer.GetBounds(); InvalidateBoundingVolume(); InvalidateInstanceData(0); clearOnFail.Reset(); }