void CustomGeometry::SetGeometryDataAttr(const PODVector<unsigned char>& value) { if (value.Empty()) return; MemoryBuffer buffer(value); SetNumGeometries(buffer.ReadVLE()); elementMask_ = buffer.ReadUInt(); for (unsigned i = 0; i < geometries_.Size(); ++i) { unsigned numVertices = buffer.ReadVLE(); vertices_[i].Resize(numVertices); primitiveTypes_[i] = (PrimitiveType)buffer.ReadUByte(); for (unsigned j = 0; j < numVertices; ++j) { if (elementMask_ & MASK_POSITION) vertices_[i][j].position_ = buffer.ReadVector3(); if (elementMask_ & MASK_NORMAL) vertices_[i][j].normal_ = buffer.ReadVector3(); if (elementMask_ & MASK_COLOR) vertices_[i][j].color_ = buffer.ReadUInt(); if (elementMask_ & MASK_TEXCOORD1) vertices_[i][j].texCoord_ = buffer.ReadVector2(); if (elementMask_ & MASK_TANGENT) vertices_[i][j].tangent_ = buffer.ReadVector4(); } } Commit(); }
void CrowdAgent::SetAgentDataAttr(const PODVector<unsigned char>& value) { if (value.Empty()) return; dtCrowdAgent* agent = const_cast<dtCrowdAgent*>(GetDetourCrowdAgent()); if (!agent) return; MemoryBuffer buffer(value); // Path corridor is tricky char corridorData[sizeof(dtPathCorridor)]; // Duplicate the existing path corridor into a block memcpy(corridorData, &agent->corridor, sizeof(dtPathCorridor)); // Read the entire block of the crowd agent buffer.Read(agent, sizeof(dtCrowdAgent)); // Restore the values of the original path corridor memcpy(&agent->corridor, corridorData, sizeof(dtPathCorridor)); // Tell the path corridor to rebuild the path, it will reevaluate the path, existing velocities maintained agent->corridor.reset(agent->targetRef, agent->targetPos); agent->params.userData = this; }
static void ClipPolygon(PODVector<DecalVertex>& dest, const PODVector<DecalVertex>& src, const Plane& plane, bool skinned) { unsigned last = 0; float lastDistance = 0.0f; dest.Clear(); if (src.Empty()) return; for (unsigned i = 0; i < src.Size(); ++i) { float distance = plane.Distance(src[i].position_); if (distance >= 0.0f) { if (lastDistance < 0.0f) dest.Push(ClipEdge(src[last], src[i], lastDistance, distance, skinned)); dest.Push(src[i]); } else { if (lastDistance >= 0.0f && i != 0) dest.Push(ClipEdge(src[last], src[i], lastDistance, distance, skinned)); } last = i; lastDistance = distance; } // Recheck the distances of the last and first vertices and add the final clipped vertex if applicable float distance = plane.Distance(src[0].position_); if ((lastDistance < 0.0f && distance >= 0.0f) || (lastDistance >= 0.0f && distance < 0.0f)) dest.Push(ClipEdge(src[last], src[0], lastDistance, distance, skinned)); }
void UIBatch::AddOrMerge(const UIBatch& batch, PODVector<UIBatch>& batches) { if (batch.vertexEnd_ == batch.vertexStart_) return; if (!batches.Empty() && batches.Back().Merge(batch)) return; batches.Push(batch); }
void CollisionChain2D::SetVerticesAttr(const PODVector<unsigned char>& value) { if (value.Empty()) return; PODVector<Vector2> vertices; MemoryBuffer buffer(value); while (!buffer.IsEof()) vertices.Push(buffer.ReadVector2()); SetVertices(vertices); }
void UI::SetVertexData(VertexBuffer* dest, const PODVector<float>& vertexData) { if (vertexData.Empty()) return; // Update quad geometry into the vertex buffer // Resize the vertex buffer first if too small or much too large unsigned numVertices = vertexData.Size() / UI_VERTEX_SIZE; if (dest->GetVertexCount() < numVertices || dest->GetVertexCount() > numVertices * 2) dest->SetSize(numVertices, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true); dest->SetData(&vertexData[0]); }
void DynamicNavigationMesh::SetNavigationDataAttr(const PODVector<unsigned char>& value) { ReleaseNavigationMesh(); if (value.Empty()) return; MemoryBuffer buffer(value); boundingBox_ = buffer.ReadBoundingBox(); numTilesX_ = buffer.ReadInt(); numTilesZ_ = buffer.ReadInt(); dtNavMeshParams params; // NOLINT(hicpp-member-init) buffer.Read(¶ms, sizeof(dtNavMeshParams)); navMesh_ = dtAllocNavMesh(); if (!navMesh_) { URHO3D_LOGERROR("Could not allocate navigation mesh"); return; } if (dtStatusFailed(navMesh_->init(¶ms))) { URHO3D_LOGERROR("Could not initialize navigation mesh"); ReleaseNavigationMesh(); return; } dtTileCacheParams tcParams; // NOLINT(hicpp-member-init) buffer.Read(&tcParams, sizeof(tcParams)); tileCache_ = dtAllocTileCache(); if (!tileCache_) { URHO3D_LOGERROR("Could not allocate tile cache"); ReleaseNavigationMesh(); return; } if (dtStatusFailed(tileCache_->init(&tcParams, allocator_.Get(), compressor_.Get(), meshProcessor_.Get()))) { URHO3D_LOGERROR("Could not initialize tile cache"); ReleaseNavigationMesh(); return; } ReadTiles(buffer, true); // \todo Shall we send E_NAVIGATION_MESH_REBUILT here? }
VertexDeclaration::VertexDeclaration(Graphics* graphics, ShaderVariation* vertexShader, VertexBuffer** vertexBuffers, unsigned* elementMasks) : inputLayout_(0) { PODVector<D3D11_INPUT_ELEMENT_DESC> elementDescs; unsigned vbElementMask = 0; for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) { if (vertexBuffers[i] && elementMasks[i]) { for (unsigned j = 0; j < MAX_VERTEX_ELEMENTS; ++j) { if (elementMasks[i] & (1 << j)) { D3D11_INPUT_ELEMENT_DESC newDesc; newDesc.SemanticName = VertexBuffer::elementSemantics[j]; newDesc.SemanticIndex = VertexBuffer::elementSemanticIndices[j]; newDesc.Format = (DXGI_FORMAT)VertexBuffer::elementFormats[j]; newDesc.InputSlot = (UINT)i; newDesc.AlignedByteOffset = vertexBuffers[i]->GetElementOffset((VertexElement)j); newDesc.InputSlotClass = (j >= ELEMENT_INSTANCEMATRIX1 && j <= ELEMENT_INSTANCEMATRIX3) ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; newDesc.InstanceDataStepRate = (j >= ELEMENT_INSTANCEMATRIX1 && j <= ELEMENT_INSTANCEMATRIX3) ? 1 : 0; elementDescs.Push(newDesc); vbElementMask |= 1 << j; } } } } if (elementDescs.Empty()) return; ID3D11InputLayout* d3dInputLayout = 0; const PODVector<unsigned char>& byteCode = vertexShader->GetByteCode(); graphics->GetImpl()->GetDevice()->CreateInputLayout(&elementDescs[0], (UINT)elementDescs.Size(), &byteCode[0], byteCode.Size(), &d3dInputLayout); if (d3dInputLayout) inputLayout_ = d3dInputLayout; else URHO3D_LOGERRORF("Failed to create input layout for shader %s, missing element mask %d", vertexShader->GetFullName().CString(), vertexShader->GetElementMask() & ~vbElementMask); }
RigidBody2D* PhysicsWorld2D::GetRigidBody(int screenX, int screenY, unsigned collisionMask, Camera* camera) { if (!camera) { PODVector<Camera*> cameras; GetScene()->GetComponents<Camera>(cameras, true); if (!cameras.Empty()) camera = cameras[0]; } if (!camera) { LOGWARNING("Could not find camera in scene"); return 0; } Graphics* graphics = GetSubsystem<Graphics>(); Vector3 screenPoint((float)screenX / graphics->GetWidth(), (float)screenY / graphics->GetHeight(), 0.0f); Vector3 worldPoint = camera->ScreenToWorldPoint(screenPoint); return GetRigidBody(Vector2(worldPoint.x_, worldPoint.y_), collisionMask); }
void DecalSet::SetDecalsAttr(const PODVector<unsigned char>& value) { RemoveAllDecals(); if (value.Empty()) return; MemoryBuffer buffer(value); skinned_ = buffer.ReadBool(); unsigned numDecals = buffer.ReadVLE(); while (numDecals--) { decals_.Resize(decals_.Size() + 1); Decal& newDecal = decals_.Back(); newDecal.timer_ = buffer.ReadFloat(); newDecal.timeToLive_ = buffer.ReadFloat(); newDecal.vertices_.Resize(buffer.ReadVLE()); newDecal.indices_.Resize(buffer.ReadVLE()); for (PODVector<DecalVertex>::Iterator i = newDecal.vertices_.Begin(); i != newDecal.vertices_.End(); ++i) { i->position_ = buffer.ReadVector3(); i->normal_ = buffer.ReadVector3(); i->texCoord_ = buffer.ReadVector2(); i->tangent_ = buffer.ReadVector4(); if (skinned_) { for (unsigned j = 0; j < 4; ++j) i->blendWeights_[j] = buffer.ReadFloat(); for (unsigned j = 0; j < 4; ++j) i->blendIndices_[j] = buffer.ReadUByte(); } } for (PODVector<unsigned short>::Iterator i = newDecal.indices_.Begin(); i != newDecal.indices_.End(); ++i) *i = buffer.ReadUShort(); newDecal.CalculateBoundingBox(); numVertices_ += newDecal.vertices_.Size(); numIndices_ += newDecal.indices_.Size(); } if (skinned_) { unsigned numBones = buffer.ReadVLE(); skinMatrices_.Resize(numBones); bones_.Resize(numBones); for (unsigned i = 0; i < numBones; ++i) { Bone& newBone = bones_[i]; newBone.name_ = buffer.ReadString(); newBone.collisionMask_ = buffer.ReadUByte(); if (newBone.collisionMask_ & BONECOLLISION_SPHERE) newBone.radius_ = buffer.ReadFloat(); if (newBone.collisionMask_ & BONECOLLISION_BOX) newBone.boundingBox_ = buffer.ReadBoundingBox(); buffer.Read(&newBone.offsetMatrix_.m00_, sizeof(Matrix3x4)); } assignBonesPending_ = true; skinningDirty_ = true; } UpdateEventSubscription(true); UpdateBatch(); MarkDecalsDirty(); }
VertexDeclaration::VertexDeclaration(Graphics* graphics, ShaderVariation* vertexShader, VertexBuffer** vertexBuffers) : inputLayout_(0) { PODVector<D3D11_INPUT_ELEMENT_DESC> elementDescs; unsigned prevBufferDescs = 0; for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) { if (!vertexBuffers[i]) continue; const PODVector<VertexElement>& srcElements = vertexBuffers[i]->GetElements(); bool isExisting = false; for (unsigned j = 0; j < srcElements.Size(); ++j) { const VertexElement& srcElement = srcElements[j]; const char* semanticName = ShaderVariation::elementSemanticNames[srcElement.semantic_]; // Override existing element if necessary for (unsigned k = 0; k < prevBufferDescs; ++k) { if (elementDescs[k].SemanticName == semanticName && elementDescs[k].SemanticIndex == srcElement.index_) { isExisting = true; elementDescs[k].InputSlot = i; elementDescs[k].AlignedByteOffset = srcElement.offset_; elementDescs[k].InputSlotClass = srcElement.perInstance_ ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; elementDescs[k].InstanceDataStepRate = srcElement.perInstance_ ? 1 : 0; break; } } if (isExisting) continue; D3D11_INPUT_ELEMENT_DESC newDesc; newDesc.SemanticName = semanticName; newDesc.SemanticIndex = srcElement.index_; newDesc.Format = d3dElementFormats[srcElement.type_]; newDesc.InputSlot = (UINT)i; newDesc.AlignedByteOffset = srcElement.offset_; newDesc.InputSlotClass = srcElement.perInstance_ ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; newDesc.InstanceDataStepRate = srcElement.perInstance_ ? 1 : 0; elementDescs.Push(newDesc); } prevBufferDescs = elementDescs.Size(); } if (elementDescs.Empty()) return; const PODVector<unsigned char>& byteCode = vertexShader->GetByteCode(); HRESULT hr = graphics->GetImpl()->GetDevice()->CreateInputLayout(&elementDescs[0], (UINT)elementDescs.Size(), &byteCode[0], byteCode.Size(), (ID3D11InputLayout**)&inputLayout_); if (FAILED(hr)) { ATOMIC_SAFE_RELEASE(inputLayout_); ATOMIC_LOGERRORF("Failed to create input layout for shader %s due to missing vertex element(s) (HRESULT %x)", vertexShader->GetFullName().CString(), (unsigned)hr); } }
void DynamicNavigationMesh::SetNavigationDataAttr(const PODVector<unsigned char>& value) { ReleaseNavigationMesh(); if (value.Empty()) return; MemoryBuffer buffer(value); boundingBox_ = buffer.ReadBoundingBox(); numTilesX_ = buffer.ReadInt(); numTilesZ_ = buffer.ReadInt(); dtNavMeshParams params; buffer.Read(¶ms, sizeof(dtNavMeshParams)); navMesh_ = dtAllocNavMesh(); if (!navMesh_) { LOGERROR("Could not allocate navigation mesh"); return; } if (dtStatusFailed(navMesh_->init(¶ms))) { LOGERROR("Could not initialize navigation mesh"); ReleaseNavigationMesh(); return; } dtTileCacheParams tcParams; buffer.Read(&tcParams, sizeof(tcParams)); tileCache_ = dtAllocTileCache(); if (!tileCache_) { LOGERROR("Could not allocate tile cache"); ReleaseNavigationMesh(); return; } if (dtStatusFailed(tileCache_->init(&tcParams, allocator_, compressor_, meshProcessor_))) { LOGERROR("Could not initialize tile cache"); ReleaseNavigationMesh(); return; } while (!buffer.IsEof()) { dtTileCacheLayerHeader header; buffer.Read(&header, sizeof(dtTileCacheLayerHeader)); const int dataSize = buffer.ReadInt(); unsigned char* data = (unsigned char*)dtAlloc(dataSize, DT_ALLOC_PERM); buffer.Read(data, dataSize); if (dtStatusFailed(tileCache_->addTile(data, dataSize, DT_TILE_FREE_DATA, 0))) { LOGERROR("Failed to add tile"); dtFree(data); return; } } for (int x = 0; x < numTilesX_; ++x) { for (int z = 0; z < numTilesZ_; ++z) tileCache_->buildNavMeshTilesAt(x, z, navMesh_); } tileCache_->update(0, navMesh_); }
void NavigationMesh::SetNavigationDataAttr(const PODVector<unsigned char>& value) { ReleaseNavigationMesh(); if (value.Empty()) return; MemoryBuffer buffer(value); boundingBox_ = buffer.ReadBoundingBox(); numTilesX_ = buffer.ReadInt(); numTilesZ_ = buffer.ReadInt(); dtNavMeshParams params; rcVcopy(params.orig, &boundingBox_.min_.x_); params.tileWidth = buffer.ReadFloat(); params.tileHeight = buffer.ReadFloat(); params.maxTiles = buffer.ReadInt(); params.maxPolys = buffer.ReadInt(); navMesh_ = dtAllocNavMesh(); if (!navMesh_) { ATOMIC_LOGERROR("Could not allocate navigation mesh"); return; } if (dtStatusFailed(navMesh_->init(¶ms))) { ATOMIC_LOGERROR("Could not initialize navigation mesh"); ReleaseNavigationMesh(); return; } unsigned numTiles = 0; while (!buffer.IsEof()) { /*int x =*/ buffer.ReadInt(); /*int z =*/ buffer.ReadInt(); /*dtTileRef tileRef =*/ buffer.ReadUInt(); unsigned navDataSize = buffer.ReadUInt(); unsigned char* navData = (unsigned char*)dtAlloc(navDataSize, DT_ALLOC_PERM); if (!navData) { ATOMIC_LOGERROR("Could not allocate data for navigation mesh tile"); return; } buffer.Read(navData, navDataSize); if (dtStatusFailed(navMesh_->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, 0))) { ATOMIC_LOGERROR("Failed to add navigation mesh tile"); dtFree(navData); return; } else ++numTiles; } ATOMIC_LOGDEBUG("Created navigation mesh with " + String(numTiles) + " tiles from serialized data"); }
void UI::Render(VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigned batchStart, unsigned batchEnd) { if (batches.Empty()) return; Vector2 invScreenSize(1.0f / (float)graphics_->GetWidth(), 1.0f / (float)graphics_->GetHeight()); Vector2 scale(2.0f * invScreenSize.x_, -2.0f * invScreenSize.y_); Vector2 offset(-1.0f, 1.0f); Matrix4 projection(Matrix4::IDENTITY); projection.m00_ = scale.x_; projection.m03_ = offset.x_; projection.m11_ = scale.y_; projection.m13_ = offset.y_; projection.m22_ = 1.0f; projection.m23_ = 0.0f; projection.m33_ = 1.0f; graphics_->ClearParameterSources(); graphics_->SetColorWrite(true); graphics_->SetCullMode(CULL_NONE); graphics_->SetDepthTest(CMP_ALWAYS); graphics_->SetDepthWrite(false); graphics_->SetFillMode(FILL_SOLID); graphics_->SetStencilTest(false); graphics_->ResetRenderTargets(); graphics_->SetVertexBuffer(buffer); ShaderVariation* noTextureVS = graphics_->GetShader(VS, "Basic", "VERTEXCOLOR"); ShaderVariation* diffTextureVS = graphics_->GetShader(VS, "Basic", "DIFFMAP VERTEXCOLOR"); ShaderVariation* noTexturePS = graphics_->GetShader(PS, "Basic", "VERTEXCOLOR"); ShaderVariation* diffTexturePS = graphics_->GetShader(PS, "Basic", "DIFFMAP VERTEXCOLOR"); ShaderVariation* diffMaskTexturePS = graphics_->GetShader(PS, "Basic", "DIFFMAP ALPHAMASK VERTEXCOLOR"); ShaderVariation* alphaTexturePS = graphics_->GetShader(PS, "Basic", "ALPHAMAP VERTEXCOLOR"); unsigned alphaFormat = Graphics::GetAlphaFormat(); for (unsigned i = batchStart; i < batchEnd; ++i) { const UIBatch& batch = batches[i]; if (batch.vertexStart_ == batch.vertexEnd_) continue; ShaderVariation* ps; ShaderVariation* vs; if (!batch.texture_) { ps = noTexturePS; vs = noTextureVS; } else { // If texture contains only an alpha channel, use alpha shader (for fonts) vs = diffTextureVS; if (batch.texture_->GetFormat() == alphaFormat) ps = alphaTexturePS; else if (batch.blendMode_ != BLEND_ALPHA && batch.blendMode_ != BLEND_ADDALPHA && batch.blendMode_ != BLEND_PREMULALPHA) ps = diffMaskTexturePS; else ps = diffTexturePS; } graphics_->SetShaders(vs, ps); if (graphics_->NeedParameterUpdate(SP_OBJECT, this)) graphics_->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY); if (graphics_->NeedParameterUpdate(SP_CAMERA, this)) graphics_->SetShaderParameter(VSP_VIEWPROJ, projection); if (graphics_->NeedParameterUpdate(SP_MATERIAL, this)) graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f)); graphics_->SetBlendMode(batch.blendMode_); graphics_->SetScissorTest(true, batch.scissor_); graphics_->SetTexture(0, batch.texture_); graphics_->Draw(TRIANGLE_LIST, batch.vertexStart_ / UI_VERTEX_SIZE, (batch.vertexEnd_ - batch.vertexStart_) / UI_VERTEX_SIZE); } }
/// Convert screen coordinates to element coordinates. IntVector2 ScreenToElement(const IntVector2& screenPos) override { IntVector2 result(-1, -1); if (node_.Expired()) return result; Scene* scene = node_->GetScene(); auto* model = node_->GetComponent<StaticModel>(); if (scene == nullptr || model == nullptr) return result; auto* renderer = GetSubsystem<Renderer>(); if (renderer == nullptr) return result; // \todo Always uses the first viewport, in case there are multiple auto* octree = scene->GetComponent<Octree>(); if (viewport_ == nullptr) viewport_ = renderer->GetViewportForScene(scene, 0); if (viewport_.Expired() || octree == nullptr) return result; if (viewport_->GetScene() != scene) { URHO3D_LOGERROR("UIComponent and Viewport set to component's root element belong to different scenes."); return result; } Camera* camera = viewport_->GetCamera(); if (camera == nullptr) return result; IntRect rect = viewport_->GetRect(); if (rect == IntRect::ZERO) { auto* graphics = GetSubsystem<Graphics>(); rect.right_ = graphics->GetWidth(); rect.bottom_ = graphics->GetHeight(); } Ray ray(camera->GetScreenRay((float)screenPos.x_ / rect.Width(), (float)screenPos.y_ / rect.Height())); PODVector<RayQueryResult> queryResultVector; RayOctreeQuery query(queryResultVector, ray, RAY_TRIANGLE_UV, M_INFINITY, DRAWABLE_GEOMETRY, DEFAULT_VIEWMASK); octree->Raycast(query); if (queryResultVector.Empty()) return result; for (unsigned i = 0; i < queryResultVector.Size(); i++) { RayQueryResult& queryResult = queryResultVector[i]; if (queryResult.drawable_ != model) { // ignore billboard sets by default if (queryResult.drawable_->GetTypeInfo()->IsTypeOf(BillboardSet::GetTypeStatic())) continue; return result; } Vector2& uv = queryResult.textureUV_; result = IntVector2(static_cast<int>(uv.x_ * GetWidth()), static_cast<int>(uv.y_ * GetHeight())); return result; } return result; }