Merge branch 'development' into Atom/dmcdiar/ATOM-5702
@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{filter:url(#filter-1);}
|
||||
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
|
||||
</style>
|
||||
<filter id="filter-1">
|
||||
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0">
|
||||
</feColorMatrix>
|
||||
</filter>
|
||||
<g id="Working-Design-Page-v2">
|
||||
<g id="_x32_A---Normal-Mode---Pre-Edit-Mode" transform="translate(-343.000000, -156.000000)">
|
||||
<g id="Tool-Bar-Copy-2" transform="translate(336.000000, 140.000000)">
|
||||
<g id="Icons-_x2F_-Toolbar-_x2F_-Move" transform="translate(5.000000, 14.000000)" class="st0">
|
||||
<g>
|
||||
<g id="Group_1_" transform="translate(2.000000, 2.000000)">
|
||||
<path id="Combined-Shape_1_" class="st1" d="M11,13.9v2l3.2,0L10,20l-4.1-4.1l3.2,0v-2H11z M15.9,5.9L20,10l-4.1,4.1l0-3.2h-2
|
||||
V9h2L15.9,5.9z M4.1,5.9l0,3.2h2v2h-2l0,3.2L0,10L4.1,5.9z M10,0l4.1,4.1l-3.2,0v2H9v-2l-3.2,0L10,0z"/>
|
||||
<rect id="Rectangle_1_" x="7" y="7" class="st1" width="6" height="6"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="20px" height="17px" viewBox="0 0 20 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icons / Toolbar / Rotate</title>
|
||||
<defs>
|
||||
<filter id="filter-1">
|
||||
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="Working-Design-Page" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="4A" transform="translate(-343.000000, -190.000000)">
|
||||
<g id="Tool-Bar-Copy-2" transform="translate(336.000000, 140.000000)">
|
||||
<g id="Icons-/-Toolbar-/-Rotate" transform="translate(5.000000, 45.000000)" filter="url(#filter-1)">
|
||||
<g>
|
||||
<rect id="Icon-Background" x="0" y="0" width="24" height="24"></rect>
|
||||
<path d="M14,12.7573593 L14,21.2426407 L9.75735931,17 L14,12.7573593 Z M12,5 C17.5228475,5 22,7.3608081 22,12 C22,16.0635474 18.5649911,18.3790487 14.0010174,18.8911124 L14.0009061,16.4168268 C17.3303835,15.9561668 19.5351812,14.3225002 19.5351812,12 C19.5351812,9.23857625 16.418278,8.0041333 12,8.0041333 C7.581722,8.0041333 4.51608017,9.23857625 4.51608017,12 C4.51608017,13.8140495 5.1333787,15.673982 7.29370866,16.4168268 C7.95862159,16.7906273 8.29107806,17.0452093 8.29107806,17.180573 C8.29107806,17.3159366 7.86071871,17.2557456 7,17 C4.90930531,16.4680156 4.01338412,15.8858396 3.24544096,14.8949777 C2.71607427,14.2119464 2,13.4055574 2,12 C2,7.3608081 6.4771525,5 12,5 Z" id="Shape" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icons / Toolbar / Scale</title>
|
||||
<defs>
|
||||
<filter id="filter-1">
|
||||
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="Working-Design-Page" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="4A" transform="translate(-344.000000, -219.000000)">
|
||||
<g id="Tool-Bar-Copy-2" transform="translate(336.000000, 140.000000)">
|
||||
<g id="Icons-/-Toolbar-/-Scale" transform="translate(5.000000, 76.000000)" filter="url(#filter-1)">
|
||||
<g>
|
||||
<rect id="Icon-Background" x="0" y="0" width="24" height="24"></rect>
|
||||
<path d="M21,3 L20.999,4.399 L21,4.40005893 L20.999,4.401 L21,9 L18.7,6.701 L14.4000589,11 L13,9.59994107 L17.299,5.3 L15,3 L21,3 Z" id="Combined-Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M3,21 L3,15 L5.356,17.356 L9.71109794,13 L11,14.2889021 L6.644,18.644 L9,21 L3,21 Z" id="Combined-Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{filter:url(#filter-1);}
|
||||
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
|
||||
</style>
|
||||
<filter id="filter-1">
|
||||
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0">
|
||||
</feColorMatrix>
|
||||
</filter>
|
||||
<g id="Working-Design-Page-v2">
|
||||
<g id="_x32_A---Normal-Mode---Pre-Edit-Mode" transform="translate(-343.000000, -156.000000)">
|
||||
<g id="Tool-Bar-Copy-2" transform="translate(336.000000, 140.000000)">
|
||||
<g id="Icons-_x2F_-Toolbar-_x2F_-Move" transform="translate(5.000000, 14.000000)" class="st0">
|
||||
<g>
|
||||
<g id="Group_1_" transform="translate(2.000000, 2.000000)">
|
||||
<path id="Combined-Shape_1_" class="st1" d="M11,13.9v2l3.2,0L10,20l-4.1-4.1l3.2,0v-2H11z M15.9,5.9L20,10l-4.1,4.1l0-3.2h-2
|
||||
V9h2L15.9,5.9z M4.1,5.9l0,3.2h2v2h-2l0,3.2L0,10L4.1,5.9z M10,0l4.1,4.1l-3.2,0v2H9v-2l-3.2,0L10,0z"/>
|
||||
<rect id="Rectangle_1_" x="7" y="7" class="st1" width="6" height="6"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="20px" height="17px" viewBox="0 0 20 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icons / Toolbar / Rotate</title>
|
||||
<defs>
|
||||
<filter id="filter-1">
|
||||
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="Working-Design-Page" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="4A" transform="translate(-343.000000, -190.000000)">
|
||||
<g id="Tool-Bar-Copy-2" transform="translate(336.000000, 140.000000)">
|
||||
<g id="Icons-/-Toolbar-/-Rotate" transform="translate(5.000000, 45.000000)" filter="url(#filter-1)">
|
||||
<g>
|
||||
<rect id="Icon-Background" x="0" y="0" width="24" height="24"></rect>
|
||||
<path d="M14,12.7573593 L14,21.2426407 L9.75735931,17 L14,12.7573593 Z M12,5 C17.5228475,5 22,7.3608081 22,12 C22,16.0635474 18.5649911,18.3790487 14.0010174,18.8911124 L14.0009061,16.4168268 C17.3303835,15.9561668 19.5351812,14.3225002 19.5351812,12 C19.5351812,9.23857625 16.418278,8.0041333 12,8.0041333 C7.581722,8.0041333 4.51608017,9.23857625 4.51608017,12 C4.51608017,13.8140495 5.1333787,15.673982 7.29370866,16.4168268 C7.95862159,16.7906273 8.29107806,17.0452093 8.29107806,17.180573 C8.29107806,17.3159366 7.86071871,17.2557456 7,17 C4.90930531,16.4680156 4.01338412,15.8858396 3.24544096,14.8949777 C2.71607427,14.2119464 2,13.4055574 2,12 C2,7.3608081 6.4771525,5 12,5 Z" id="Shape" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icons / Toolbar / Scale</title>
|
||||
<defs>
|
||||
<filter id="filter-1">
|
||||
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="Working-Design-Page" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="4A" transform="translate(-344.000000, -219.000000)">
|
||||
<g id="Tool-Bar-Copy-2" transform="translate(336.000000, 140.000000)">
|
||||
<g id="Icons-/-Toolbar-/-Scale" transform="translate(5.000000, 76.000000)" filter="url(#filter-1)">
|
||||
<g>
|
||||
<rect id="Icon-Background" x="0" y="0" width="24" height="24"></rect>
|
||||
<path d="M21,3 L20.999,4.399 L21,4.40005893 L20.999,4.401 L21,9 L18.7,6.701 L14.4000589,11 L13,9.59994107 L17.299,5.3 L15,3 L21,3 Z" id="Combined-Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="M3,21 L3,15 L5.356,17.356 L9.71109794,13 L11,14.2889021 L6.644,18.644 L9,21 L3,21 Z" id="Combined-Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:16f592487e8973abcf6b696aee6e430924c22daac0d6bb781c9e76153cd932f7
|
||||
size 8885
|
||||
oid sha256:352a64f523b3246000393309fa7f14955fe554e0b792a4177349f0f2db8a2b62
|
||||
size 5901
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4d5c38cf9b97ae28c391916e6637aebf767d5ac009df61e730396fe8b116f3e5
|
||||
size 6913
|
||||
oid sha256:31bd1feb92c3bb8a5c5df4638927a9a80e879329965732c4c32f673c236a8b0a
|
||||
size 6021
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a6f26f1c1c037fa0b848ac9b3d9a76e476b4853d770f1a77c01714286733b567
|
||||
size 6921
|
||||
oid sha256:063779c1e80ce22319cb82ff0d7635d3dcbb043b789c3830cc405ffa36d3c0ef
|
||||
size 5876
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4ffd3c4ee04fa8a414995c39c7ca79246e3d9b0ceee1ad1b85d61a5298f71495
|
||||
size 6940
|
||||
oid sha256:5bd3a952841aa924a4869c74fad7ed397667a87948270f0ce35f314e6cf2e14a
|
||||
size 5927
|
||||
|
||||
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Marsenne Twister PRNG. See MT.h for more info.
|
||||
|
||||
#include "MTPseudoRandom.h"
|
||||
// non-inline function definitions and static member definitions cannot
|
||||
// reside in header file because of the risk of multiple declarations
|
||||
|
||||
void CMTRand_int32::gen_state() // generate new m_nState vector
|
||||
{
|
||||
for (int i = 0; i < (n - m); ++i)
|
||||
{
|
||||
m_nState[i] = m_nState[i + m] ^ twiddle(m_nState[i], m_nState[i + 1]);
|
||||
}
|
||||
for (int i = n - m; i < (n - 1); ++i)
|
||||
{
|
||||
m_nState[i] = m_nState[i + m - n] ^ twiddle(m_nState[i], m_nState[i + 1]);
|
||||
}
|
||||
m_nState[n - 1] = m_nState[m - 1] ^ twiddle(m_nState[n - 1], m_nState[0]);
|
||||
p = 0; // reset position
|
||||
}
|
||||
|
||||
void CMTRand_int32::seed(uint32 s) // init by 32 bit seed
|
||||
{ //if (s == 0)
|
||||
//m_nRandom = 1;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
m_nState[i] = 0x0UL;
|
||||
}
|
||||
m_nState[0] = s;
|
||||
for (int i = 1; i < n; ++i)
|
||||
{
|
||||
m_nState[i] = 1812433253UL * (m_nState[i - 1] ^ (m_nState[i - 1] >> 30)) + i;
|
||||
// see Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier
|
||||
// in the previous versions, MSBs of the seed affect only MSBs of the array m_nState
|
||||
// 2002/01/09 modified by Makoto Matsumoto
|
||||
}
|
||||
p = n; // force gen_state() to be called for next random number
|
||||
}
|
||||
|
||||
void CMTRand_int32::seed(const uint32* array, int size) // init by array
|
||||
{
|
||||
seed(19650218UL);
|
||||
int i = 1, j = 0;
|
||||
for (int k = ((n > size) ? n : size); k; --k)
|
||||
{
|
||||
m_nState[i] = (m_nState[i] ^ ((m_nState[i - 1] ^ (m_nState[i - 1] >> 30)) * 1664525UL))
|
||||
+ array[j] + j; // non linear
|
||||
++j;
|
||||
j %= size;
|
||||
if ((++i) == n)
|
||||
{
|
||||
m_nState[0] = m_nState[n - 1];
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
for (int k = n - 1; k; --k)
|
||||
{
|
||||
PREFAST_SUPPRESS_WARNING(6385) PREFAST_SUPPRESS_WARNING(6386) m_nState[i] = (m_nState[i] ^ ((m_nState[i - 1] ^ (m_nState[i - 1] >> 30)) * 1566083941UL)) - i;
|
||||
if ((++i) == n)
|
||||
{
|
||||
m_nState[0] = m_nState[n - 1];
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
m_nState[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array
|
||||
p = n; // force gen_state() to be called for next random number
|
||||
}
|
||||
@ -1,166 +0,0 @@
|
||||
// mtrand.h
|
||||
// C++ include file for MT19937, with initialization improved 2002/1/26.
|
||||
// Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
// Ported to C++ by Jasper Bedaux 2003/1/1 (see http://www.bedaux.net/mtrand/).
|
||||
// The generators returning floating point numbers are based on
|
||||
// a version by Isaku Wada, 2002/01/09
|
||||
// Static shared data converted to per-instance, 2008-11-13 by JSP.
|
||||
//
|
||||
// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of its contributors may not be used to endorse or promote
|
||||
// products derived from this software without specific prior written
|
||||
// permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Any feedback is very welcome.
|
||||
// http://www.math.keio.ac.jp/matumoto/emt.html
|
||||
// email: matumoto@math.keio.ac.jp
|
||||
//
|
||||
// Feedback about the C++ port should be sent to Jasper Bedaux,
|
||||
// see http://www.bedaux.net/mtrand/ for e-mail address and info.
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// History:
|
||||
// - 28:7:2005: File created and minor changes by Marco Corbetta
|
||||
//
|
||||
//*************************************************************************/
|
||||
// Modifications copyright Amazon.com, Inc. or its affiliates
|
||||
|
||||
#ifndef CRYINCLUDE_CRYCOMMON_MTPSEUDORANDOM_H
|
||||
#define CRYINCLUDE_CRYCOMMON_MTPSEUDORANDOM_H
|
||||
#pragma once
|
||||
|
||||
#include <CryRandomInternal.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CMTRand_int32
|
||||
{
|
||||
// Mersenne Twister random number generator
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
CMTRand_int32() { seed(5489UL); }
|
||||
// constructor with 32 bit int as seed
|
||||
CMTRand_int32(uint32 seed_value) { seed(seed_value); }
|
||||
// constructor with array of 32 bit integers as seed
|
||||
CMTRand_int32(const uint32* array, int size) { seed(array, size); }
|
||||
// seeds with 32 bit integer
|
||||
void seed(uint32 seed_value);
|
||||
// seeds with array
|
||||
void seed(const uint32*, int size);
|
||||
// overloaded operator() to make this a generator (functor)
|
||||
//uint32 operator()() { return rand_int32(); }
|
||||
|
||||
~CMTRand_int32() {}
|
||||
|
||||
// Functions with PascalCase names were added for
|
||||
// interchangeability with CRndGen (see LCGRandom.h).
|
||||
|
||||
void Seed(uint32 seed_value)
|
||||
{
|
||||
seed(seed_value);
|
||||
}
|
||||
|
||||
uint32 GenerateUint32()
|
||||
{
|
||||
return rand_int32();
|
||||
}
|
||||
|
||||
uint64 GenerateUint64()
|
||||
{
|
||||
const uint32 a = GenerateUint32();
|
||||
const uint32 b = GenerateUint32();
|
||||
return ((uint64)b << 32) | (uint64)a;
|
||||
}
|
||||
|
||||
float GenerateFloat()
|
||||
{
|
||||
return (float)GenerateUint32() * (1.0f / 4294967295.0f);
|
||||
}
|
||||
|
||||
// Ranged function returns random value within the *inclusive* range
|
||||
// between minValue and maxValue.
|
||||
// Any orderings work correctly: minValue <= maxValue and
|
||||
// minValue >= minValue.
|
||||
template <class T>
|
||||
T GetRandom(const T minValue, const T maxValue)
|
||||
{
|
||||
return CryRandom_Internal::BoundedRandom<CMTRand_int32, T>::Get(*this, minValue, maxValue);
|
||||
}
|
||||
|
||||
// Vector (Vec2, Vec3, Vec4) ranged function returns vector with
|
||||
// every component within the *inclusive* ranges between minValue.component
|
||||
// and maxValue.component.
|
||||
// All orderings work correctly: minValue.component <= maxValue.component and
|
||||
// minValue.component >= maxValue.component.
|
||||
template <class T>
|
||||
T GetRandomComponentwise(const T& minValue, const T& maxValue)
|
||||
{
|
||||
return CryRandom_Internal::BoundedRandomComponentwise<CMTRand_int32, T>::Get(*this, minValue, maxValue);
|
||||
}
|
||||
|
||||
// The function returns a random unit vector (Vec2, Vec3, Vec4).
|
||||
template <class T>
|
||||
T GetRandomUnitVector()
|
||||
{
|
||||
return CryRandom_Internal::GetRandomUnitVector<CMTRand_int32, T>(*this);
|
||||
}
|
||||
|
||||
protected: // used by derived classes, otherwise not accessible; use the ()-operator
|
||||
// generates 32 bit random int
|
||||
uint32 rand_int32()
|
||||
{
|
||||
if (p >= n) gen_state(); // new m_nState vector needed
|
||||
// gen_state() is split off to be non-inline, because it is only called once
|
||||
// in every 624 calls and otherwise irand() would become too big to get inlined
|
||||
uint32 x = m_nState[p++];
|
||||
x ^= (x >> 11);
|
||||
x ^= (x << 7) & 0x9D2C5680UL;
|
||||
x ^= (x << 15) & 0xEFC60000UL;
|
||||
return x ^ (x >> 18);
|
||||
}
|
||||
|
||||
private:
|
||||
static const int n = 624, m = 397; // compile time constants
|
||||
|
||||
// the variables below are static (no duplicates can exist)
|
||||
uint32 m_nState[n+1]; // m_nState vector array
|
||||
int p; // position in m_nState array
|
||||
// private functions used to generate the pseudo random numbers
|
||||
uint32 twiddle(uint32 u, uint32 v)
|
||||
{
|
||||
return (((u & 0x80000000UL) | (v & 0x7FFFFFFFUL)) >> 1)
|
||||
^ ((v & 1UL) ? 0x9908B0DFUL : 0x0UL);
|
||||
}
|
||||
void gen_state(); // generate new m_nState
|
||||
// make copy constructor and assignment operator unavailable, they don't make sense
|
||||
CMTRand_int32(const CMTRand_int32&); // copy constructor not defined
|
||||
void operator=(const CMTRand_int32&); // assignment operator not defined
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_CRYCOMMON_MTPSEUDORANDOM_H
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/Physics/Common/PhysicsJoint.h>
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <AzFramework/Physics/PhysicsScene.h>
|
||||
#include <AzFramework/Physics/PhysicsSystem.h>
|
||||
|
||||
namespace AzPhysics
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_IMPL(Joint, AZ::SystemAllocator, 0);
|
||||
|
||||
void Joint::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azdynamic_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AzPhysics::Joint>()
|
||||
->Version(1)
|
||||
->Field("SceneOwner", &Joint::m_sceneOwner)
|
||||
->Field("JointHandle", &Joint::m_jointHandle)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/std/containers/variant.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzFramework/Physics/Common/PhysicsSimulatedBodyEvents.h>
|
||||
#include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
|
||||
#include <AzFramework/Physics/Common/PhysicsTypes.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
}
|
||||
|
||||
namespace AzPhysics
|
||||
{
|
||||
struct JointConfiguration;
|
||||
|
||||
//! Base class for all Joints in Physics.
|
||||
struct Joint
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
AZ_RTTI(AzPhysics::Joint, "{1EEC9382-3434-4866-9B18-E93F151A6F59}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
virtual ~Joint() = default;
|
||||
|
||||
//! The current Scene the joint is contained.
|
||||
SceneHandle m_sceneOwner = AzPhysics::InvalidSceneHandle;
|
||||
|
||||
//! The handle to this joint.
|
||||
JointHandle m_jointHandle = AzPhysics::InvalidJointHandle;
|
||||
|
||||
//! Helper functions for setting user data.
|
||||
//! @param userData Can be a pointer to any type as internally will be cast to a void*. Object lifetime not managed by the Joint.
|
||||
template<typename T>
|
||||
void SetUserData(T* userData)
|
||||
{
|
||||
m_customUserData = static_cast<void*>(userData);
|
||||
}
|
||||
//! Helper functions for getting the set user data.
|
||||
//! @return Will return a void* to the user data set.
|
||||
void* GetUserData()
|
||||
{
|
||||
return m_customUserData;
|
||||
}
|
||||
|
||||
virtual AZ::Crc32 GetNativeType() const = 0;
|
||||
virtual void* GetNativePointer() const = 0;
|
||||
|
||||
virtual AzPhysics::SimulatedBodyHandle GetParentBodyHandle() const = 0;
|
||||
virtual AzPhysics::SimulatedBodyHandle GetChildBodyHandle() const = 0;
|
||||
|
||||
virtual void SetParentBody(AzPhysics::SimulatedBodyHandle parentBody) = 0;
|
||||
virtual void SetChildBody(AzPhysics::SimulatedBodyHandle childBody) = 0;
|
||||
|
||||
virtual void GenerateJointLimitVisualizationData(
|
||||
[[ maybe_unused ]] float scale,
|
||||
[[ maybe_unused ]] AZ::u32 angularSubdivisions,
|
||||
[[ maybe_unused ]] AZ::u32 radialSubdivisions,
|
||||
[[ maybe_unused ]] AZStd::vector<AZ::Vector3>& vertexBufferOut,
|
||||
[[ maybe_unused ]] AZStd::vector<AZ::u32>& indexBufferOut,
|
||||
[[ maybe_unused ]] AZStd::vector<AZ::Vector3>& lineBufferOut,
|
||||
[[ maybe_unused ]] AZStd::vector<bool>& lineValidityBufferOut) { }
|
||||
|
||||
private:
|
||||
void* m_customUserData = nullptr;
|
||||
};
|
||||
|
||||
//! Alias for a list of non owning weak pointers to Joint objects.
|
||||
using JointList = AZStd::vector<Joint*>;
|
||||
|
||||
//! Interface to access Joint utilities and helper functions
|
||||
class JointHelpersInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AzPhysics::JointHelpersInterface, "{A511C64D-C8A5-4E8F-9C69-8DC5EFAD0C4C}");
|
||||
|
||||
JointHelpersInterface() = default;
|
||||
virtual ~JointHelpersInterface() = default;
|
||||
AZ_DISABLE_COPY_MOVE(JointHelpersInterface);
|
||||
|
||||
//! Returns a list of supported Joint types
|
||||
virtual const AZStd::vector<AZ::TypeId> GetSupportedJointTypeIds() const = 0;
|
||||
|
||||
//! Returns a TypeID if the request joint type is supported.
|
||||
//! If the Physics backend supports this joint type JointHelpersInterface::GetSupportedJointTypeId will return a AZ::TypeId.
|
||||
virtual AZStd::optional<const AZ::TypeId> GetSupportedJointTypeId(JointType typeEnum) const = 0;
|
||||
|
||||
//! Computes parameters such as joint limit local rotations to give the desired initial joint limit orientation.
|
||||
//! @param jointLimitTypeId The type ID used to identify the particular kind of joint limit configuration to be created.
|
||||
//! @param parentWorldRotation The rotation in world space of the parent world body associated with the joint.
|
||||
//! @param childWorldRotation The rotation in world space of the child world body associated with the joint.
|
||||
//! @param axis Axis used to define the centre for limiting angular degrees of freedom.
|
||||
//! @param exampleLocalRotations A vector (which may be empty) containing example valid rotations in the local space
|
||||
//! of the child world body relative to the parent world body, which may optionally be used to help estimate the extents
|
||||
//! of the joint limit.
|
||||
virtual AZStd::unique_ptr<JointConfiguration> ComputeInitialJointLimitConfiguration(
|
||||
const AZ::TypeId& jointLimitTypeId,
|
||||
const AZ::Quaternion& parentWorldRotation,
|
||||
const AZ::Quaternion& childWorldRotation,
|
||||
const AZ::Vector3& axis,
|
||||
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations) = 0;
|
||||
|
||||
/// Generates joint limit visualization data in appropriate format to pass to DebugDisplayRequests draw functions.
|
||||
/// @param configuration The joint configuration to generate visualization data for.
|
||||
/// @param parentRotation The rotation of the joint's parent body (in the same frame as childRotation).
|
||||
/// @param childRotation The rotation of the joint's child body (in the same frame as parentRotation).
|
||||
/// @param scale Scale factor for the output display data.
|
||||
/// @param angularSubdivisions Level of detail in the angular direction (may be clamped in the implementation).
|
||||
/// @param radialSubdivisions Level of detail in the radial direction (may be clamped in the implementation).
|
||||
/// @param[out] vertexBufferOut Used with indexBufferOut to define triangles to be displayed.
|
||||
/// @param[out] indexBufferOut Used with vertexBufferOut to define triangles to be displayed.
|
||||
/// @param[out] lineBufferOut Used to define lines to be displayed.
|
||||
/// @param[out] lineValidityBufferOut Whether each line in the line buffer is part of a valid or violated limit.
|
||||
virtual void GenerateJointLimitVisualizationData(
|
||||
const JointConfiguration& configuration,
|
||||
const AZ::Quaternion& parentRotation,
|
||||
const AZ::Quaternion& childRotation,
|
||||
float scale,
|
||||
AZ::u32 angularSubdivisions,
|
||||
AZ::u32 radialSubdivisions,
|
||||
AZStd::vector<AZ::Vector3>& vertexBufferOut,
|
||||
AZStd::vector<AZ::u32>& indexBufferOut,
|
||||
AZStd::vector<AZ::Vector3>& lineBufferOut,
|
||||
AZStd::vector<bool>& lineValidityBufferOut) = 0;
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/Physics/Configuration/JointConfiguration.h>
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
namespace AzPhysics
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JointConfiguration, AZ::SystemAllocator, 0);
|
||||
|
||||
void JointConfiguration::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<JointConfiguration>()
|
||||
->Version(1)
|
||||
->Field("Name", &JointConfiguration::m_debugName)
|
||||
->Field("ParentLocalRotation", &JointConfiguration::m_parentLocalRotation)
|
||||
->Field("ParentLocalPosition", &JointConfiguration::m_parentLocalPosition)
|
||||
->Field("ChildLocalRotation", &JointConfiguration::m_childLocalRotation)
|
||||
->Field("ChildLocalPosition", &JointConfiguration::m_childLocalPosition)
|
||||
->Field("StartSimulationEnabled", &JointConfiguration::m_startSimulationEnabled)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
}
|
||||
|
||||
namespace AzPhysics
|
||||
{
|
||||
//! Base Class of all Physics Joints that will be simulated.
|
||||
struct JointConfiguration
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
AZ_RTTI(AzPhysics::JointConfiguration, "{DF91D39A-4901-48C4-9159-93FD2ACA5252}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
JointConfiguration() = default;
|
||||
virtual ~JointConfiguration() = default;
|
||||
|
||||
// Entity/object association.
|
||||
void* m_customUserData = nullptr;
|
||||
|
||||
// Basic initial settings.
|
||||
AZ::Quaternion m_parentLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Parent joint frame relative to parent body.
|
||||
AZ::Vector3 m_parentLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to parent body.
|
||||
AZ::Quaternion m_childLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Child joint frame relative to child body.
|
||||
AZ::Vector3 m_childLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to child body.
|
||||
bool m_startSimulationEnabled = true;
|
||||
|
||||
// For debugging/tracking purposes only.
|
||||
AZStd::string m_debugName;
|
||||
};
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/Physics/Joint.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
|
||||
|
||||
namespace Physics
|
||||
{
|
||||
const char* JointLimitConfiguration::GetTypeName()
|
||||
{
|
||||
return "Base Joint";
|
||||
}
|
||||
|
||||
void JointLimitConfiguration::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<JointLimitConfiguration>()
|
||||
->Version(1)
|
||||
->Field("ParentLocalRotation", &JointLimitConfiguration::m_parentLocalRotation)
|
||||
->Field("ParentLocalPosition", &JointLimitConfiguration::m_parentLocalPosition)
|
||||
->Field("ChildLocalRotation", &JointLimitConfiguration::m_childLocalRotation)
|
||||
->Field("ChildLocalPosition", &JointLimitConfiguration::m_childLocalPosition)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serializeContext->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<JointLimitConfiguration>(
|
||||
"Joint Configuration", "")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &JointLimitConfiguration::m_parentLocalRotation,
|
||||
"Parent local rotation", "The rotation of the parent joint frame relative to the parent body")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &JointLimitConfiguration::m_parentLocalPosition,
|
||||
"Parent local position", "The position of the joint in the frame of the parent body")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &JointLimitConfiguration::m_childLocalRotation,
|
||||
"Child local rotation", "The rotation of the child joint frame relative to the child body")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &JointLimitConfiguration::m_childLocalPosition,
|
||||
"Child local position", "The position of the joint in the frame of the child body")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Physics
|
||||
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
namespace AzPhysics
|
||||
{
|
||||
struct SimulatedBody;
|
||||
}
|
||||
|
||||
namespace Physics
|
||||
{
|
||||
class JointLimitConfiguration
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(JointLimitConfiguration, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(JointLimitConfiguration, "{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
JointLimitConfiguration() = default;
|
||||
JointLimitConfiguration(const JointLimitConfiguration&) = default;
|
||||
virtual ~JointLimitConfiguration() = default;
|
||||
|
||||
virtual const char* GetTypeName();
|
||||
|
||||
AZ::Quaternion m_parentLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Parent joint frame relative to parent body.
|
||||
AZ::Vector3 m_parentLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to parent body.
|
||||
AZ::Quaternion m_childLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Child joint frame relative to child body.
|
||||
AZ::Vector3 m_childLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to child body.
|
||||
};
|
||||
|
||||
class Joint
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(Joint, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(Joint, "{405F517C-E986-4ACB-9606-D5D080DDE987}");
|
||||
|
||||
virtual AzPhysics::SimulatedBody* GetParentBody() const = 0;
|
||||
virtual AzPhysics::SimulatedBody* GetChildBody() const = 0;
|
||||
virtual void SetParentBody(AzPhysics::SimulatedBody* parentBody) = 0;
|
||||
virtual void SetChildBody(AzPhysics::SimulatedBody* childBody) = 0;
|
||||
virtual const AZStd::string& GetName() const = 0;
|
||||
virtual void SetName(const AZStd::string& name) = 0;
|
||||
virtual const AZ::Crc32 GetNativeType() const = 0;
|
||||
virtual void* GetNativePointer() = 0;
|
||||
/// Generates joint limit visualization data in appropriate format to pass to DebugDisplayRequests draw functions.
|
||||
/// @param scale Scale factor for the output display data.
|
||||
/// @param angularSubdivisions Level of detail in the angular direction (may be clamped in the implementation).
|
||||
/// @param radialSubdivisions Level of detail in the radial direction (may be clamped in the implementation).
|
||||
/// @param[out] vertexBufferOut Used with indexBufferOut to define triangles to be displayed.
|
||||
/// @param[out] indexBufferOut Used with vertexBufferOut to define triangles to be displayed.
|
||||
/// @param[out] lineBufferOut Used to define lines to be displayed.
|
||||
/// @param[out] lineValidityBufferOut Whether each line in the line buffer is part of a valid or violated limit.
|
||||
virtual void GenerateJointLimitVisualizationData(
|
||||
float scale,
|
||||
AZ::u32 angularSubdivisions,
|
||||
AZ::u32 radialSubdivisions,
|
||||
AZStd::vector<AZ::Vector3>& vertexBufferOut,
|
||||
AZStd::vector<AZ::u32>& indexBufferOut,
|
||||
AZStd::vector<AZ::Vector3>& lineBufferOut,
|
||||
AZStd::vector<bool>& lineValidityBufferOut) = 0;
|
||||
};
|
||||
} // namespace Physics
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
@ -1,4 +1,4 @@
|
||||
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.0708 0.87087L11.0708 0.87074C10.4286 0.371024 9.61107 0.13517 8.79265 0.213464C7.97422 0.291757 7.21961 0.678004 6.6897 1.28985L5.76756 2.36366C5.63378 2.51944 5.56909 2.72055 5.58771 2.92273C5.60634 3.12492 5.70675 3.31163 5.86686 3.44178C6.02698 3.57194 6.23368 3.63488 6.44149 3.61676C6.6493 3.59864 6.8412 3.50094 6.97498 3.34516L7.89716 2.27122C8.03184 2.11488 8.19736 1.98639 8.38395 1.89334C8.57053 1.8003 8.7744 1.74459 8.98349 1.7295C9.19258 1.71442 9.40266 1.74027 9.60131 1.80552C9.79996 1.87078 9.98315 1.97411 10.1401 2.10942C10.4422 2.38256 10.6244 2.75851 10.6488 3.15904C10.6732 3.55957 10.5379 3.95383 10.2711 4.25978L8.35381 6.49309L8.33616 6.51209C8.23375 6.62767 8.11374 6.72729 7.98031 6.80749C7.67189 6.99364 7.30661 7.06983 6.94686 7.02305C6.58711 6.97626 6.25522 6.8094 6.00789 6.55097C5.86556 6.40288 5.66865 6.31578 5.46039 6.30879C5.25213 6.30179 5.04952 6.37546 4.89703 6.51365C4.74453 6.65183 4.65462 6.84323 4.64701 7.04584C4.6394 7.24845 4.71472 7.44572 4.85645 7.59436C5.21222 7.96578 5.65746 8.24515 6.15198 8.40726C6.6465 8.56937 7.17473 8.60911 7.68898 8.52289C7.84983 8.49539 8.00828 8.45599 8.16298 8.40505C8.70939 8.22568 9.19408 7.90261 9.56335 7.47165L11.4758 5.24457C11.7478 4.92529 11.9523 4.55683 12.0773 4.16038C12.2024 3.76394 12.2457 3.34735 12.2046 2.93457C12.1671 2.53429 12.0475 2.1454 11.8527 1.79092C11.658 1.43644 11.3921 1.12358 11.0708 0.87087Z" fill="white"/>
|
||||
<path d="M5.40958 9.14055L4.58546 10.1003C4.32342 10.4101 3.94867 10.6097 3.53919 10.6576C3.12972 10.7054 2.71706 10.5977 2.3871 10.357C2.22234 10.2309 2.08525 10.0738 1.98392 9.89526C1.8826 9.71668 1.81911 9.52014 1.79719 9.31727C1.77528 9.1144 1.79539 8.90932 1.85634 8.71414C1.91729 8.51896 2.01784 8.33765 2.15204 8.18093L4.10231 5.90975L4.11666 5.89415C4.21908 5.77861 4.3391 5.67903 4.47254 5.59887C4.75216 5.42921 5.07976 5.34988 5.4085 5.37222C5.73725 5.39457 6.05033 5.51745 6.30299 5.72329C6.3635 5.77246 6.42015 5.82595 6.47246 5.88333C6.54738 5.9658 6.63971 6.03156 6.74316 6.07611C6.84661 6.12066 6.95872 6.14295 7.07184 6.14146C7.18361 6.13992 7.29372 6.11492 7.39465 6.06817C7.49558 6.02143 7.58495 5.95403 7.65666 5.8706L7.66607 5.85958C7.78641 5.72083 7.85132 5.54454 7.8489 5.36301C7.84647 5.18148 7.77687 5.00689 7.65286 4.87124C7.35341 4.54132 6.98422 4.27825 6.57057 4.10003C6.15692 3.92182 5.70858 3.83266 5.25623 3.83866C4.80388 3.84467 4.35821 3.94569 3.94971 4.13482C3.54122 4.32395 3.17954 4.59672 2.88945 4.93446L0.944626 7.19943C0.420065 7.81564 0.163643 8.60683 0.230025 9.40433C0.296406 10.2018 0.68034 10.9426 1.29998 11.4686C1.61272 11.7312 1.97644 11.9301 2.3696 12.0535C2.76277 12.1769 3.17738 12.2223 3.5889 12.187C3.687 12.1793 3.78434 12.1672 3.88093 12.1507C4.62877 12.0232 5.30663 11.6437 5.79562 11.0786L6.617 10.1221C6.75077 9.96628 6.81547 9.76517 6.79684 9.56299C6.77822 9.3608 6.6778 9.17409 6.51769 9.04394C6.35758 8.91378 6.15088 8.85084 5.94306 8.86896C5.73525 8.88708 5.54335 8.98477 5.40957 9.14055H5.40958Z" fill="white"/>
|
||||
<path d="M11.0708 0.87087L11.0708 0.87074C10.4286 0.371024 9.61107 0.13517 8.79265 0.213464C7.97422 0.291757 7.21961 0.678004 6.6897 1.28985L5.76756 2.36366C5.63378 2.51944 5.56909 2.72055 5.58771 2.92273C5.60634 3.12492 5.70675 3.31163 5.86686 3.44178C6.02698 3.57194 6.23368 3.63488 6.44149 3.61676C6.6493 3.59864 6.8412 3.50094 6.97498 3.34516L7.89716 2.27122C8.03184 2.11488 8.19736 1.98639 8.38395 1.89334C8.57053 1.8003 8.7744 1.74459 8.98349 1.7295C9.19258 1.71442 9.40266 1.74027 9.60131 1.80552C9.79996 1.87078 9.98315 1.97411 10.1401 2.10942C10.4422 2.38256 10.6244 2.75851 10.6488 3.15904C10.6732 3.55957 10.5379 3.95383 10.2711 4.25978L8.35381 6.49309L8.33616 6.51209C8.23375 6.62767 8.11374 6.72729 7.98031 6.80749C7.67189 6.99364 7.30661 7.06983 6.94686 7.02305C6.58711 6.97626 6.25522 6.8094 6.00789 6.55097C5.86556 6.40288 5.66865 6.31578 5.46039 6.30879C5.25213 6.30179 5.04952 6.37546 4.89703 6.51365C4.74453 6.65183 4.65462 6.84323 4.64701 7.04584C4.6394 7.24845 4.71472 7.44572 4.85645 7.59436C5.21222 7.96578 5.65746 8.24515 6.15198 8.40726C6.6465 8.56937 7.17473 8.60911 7.68898 8.52289C7.84983 8.49539 8.00828 8.45599 8.16298 8.40505C8.70939 8.22568 9.19408 7.90261 9.56335 7.47165L11.4758 5.24457C11.7478 4.92529 11.9523 4.55683 12.0773 4.16038C12.2024 3.76394 12.2457 3.34735 12.2046 2.93457C12.1671 2.53429 12.0475 2.1454 11.8527 1.79092C11.658 1.43644 11.3921 1.12358 11.0708 0.87087Z" fill="#3F3F3F"/>
|
||||
<path d="M5.40958 9.14055L4.58546 10.1003C4.32342 10.4101 3.94867 10.6097 3.53919 10.6576C3.12972 10.7054 2.71706 10.5977 2.3871 10.357C2.22234 10.2309 2.08525 10.0738 1.98392 9.89526C1.8826 9.71668 1.81911 9.52014 1.79719 9.31727C1.77528 9.1144 1.79539 8.90932 1.85634 8.71414C1.91729 8.51896 2.01784 8.33765 2.15204 8.18093L4.10231 5.90975L4.11666 5.89415C4.21908 5.77861 4.3391 5.67903 4.47254 5.59887C4.75216 5.42921 5.07976 5.34988 5.4085 5.37222C5.73725 5.39457 6.05033 5.51745 6.30299 5.72329C6.3635 5.77246 6.42015 5.82595 6.47246 5.88333C6.54738 5.9658 6.63971 6.03156 6.74316 6.07611C6.84661 6.12066 6.95872 6.14295 7.07184 6.14146C7.18361 6.13992 7.29372 6.11492 7.39465 6.06817C7.49558 6.02143 7.58495 5.95403 7.65666 5.8706L7.66607 5.85958C7.78641 5.72083 7.85132 5.54454 7.8489 5.36301C7.84647 5.18148 7.77687 5.00689 7.65286 4.87124C7.35341 4.54132 6.98422 4.27825 6.57057 4.10003C6.15692 3.92182 5.70858 3.83266 5.25623 3.83866C4.80388 3.84467 4.35821 3.94569 3.94971 4.13482C3.54122 4.32395 3.17954 4.59672 2.88945 4.93446L0.944626 7.19943C0.420065 7.81564 0.163643 8.60683 0.230025 9.40433C0.296406 10.2018 0.68034 10.9426 1.29998 11.4686C1.61272 11.7312 1.97644 11.9301 2.3696 12.0535C2.76277 12.1769 3.17738 12.2223 3.5889 12.187C3.687 12.1793 3.78434 12.1672 3.88093 12.1507C4.62877 12.0232 5.30663 11.6437 5.79562 11.0786L6.617 10.1221C6.75077 9.96628 6.81547 9.76517 6.79684 9.56299C6.77822 9.3608 6.6778 9.17409 6.51769 9.04394C6.35758 8.91378 6.15088 8.85084 5.94306 8.86896C5.73525 8.88708 5.54335 8.98477 5.40957 9.14055H5.40958Z" fill="#3F3F3F"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#include <AssetBrowser/AssetBrowserFilterModel.h>
|
||||
#include <AssetBrowser/AssetBrowserTableModel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
AssetBrowserTableModel::AssetBrowserTableModel(QObject* parent /* = nullptr */)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
setDynamicSortFilter(false);
|
||||
}
|
||||
|
||||
void AssetBrowserTableModel::setSourceModel(QAbstractItemModel* sourceModel)
|
||||
{
|
||||
m_filterModel = qobject_cast<AssetBrowserFilterModel*>(sourceModel);
|
||||
AZ_Assert(
|
||||
m_filterModel,
|
||||
"Error in AssetBrowserTableModel initialization, class expects source model to be an AssetBrowserFilterModel.");
|
||||
QSortFilterProxyModel::setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
QModelIndex AssetBrowserTableModel::mapToSource(const QModelIndex& proxyIndex) const
|
||||
{
|
||||
Q_ASSERT(!proxyIndex.isValid() || proxyIndex.model() == this);
|
||||
if (!proxyIndex.isValid())
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
return m_indexMap[proxyIndex.row()];
|
||||
}
|
||||
|
||||
QVariant AssetBrowserTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
return tr(AssetBrowserEntry::m_columnNames[section]);
|
||||
}
|
||||
return QSortFilterProxyModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
QVariant AssetBrowserTableModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
auto sourceIndex = mapToSource(index);
|
||||
if (!sourceIndex.isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
AssetBrowserEntry* entry = GetAssetEntry(sourceIndex);
|
||||
if (entry == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "AssetBrowserTableModel - QModelIndex does not reference an AssetEntry. Source model is not valid.");
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
return sourceIndex.data(role);
|
||||
}
|
||||
|
||||
QModelIndex AssetBrowserTableModel::index(int row, int column, const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? QModelIndex() : createIndex(row, column, m_indexMap[row].internalPointer());
|
||||
}
|
||||
|
||||
int AssetBrowserTableModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return !parent.isValid() ? m_indexMap.size() : 0;
|
||||
}
|
||||
|
||||
int AssetBrowserTableModel::BuildTableModelMap(
|
||||
const QAbstractItemModel* model, const QModelIndex& parent /*= QModelIndex()*/, int row /*= 0*/)
|
||||
{
|
||||
int rows = model ? model->rowCount(parent) : 0;
|
||||
for (int i = 0; i < rows; ++i)
|
||||
{
|
||||
QModelIndex index = model->index(i, 0, parent);
|
||||
AssetBrowserEntry* entry = GetAssetEntry(m_filterModel->mapToSource(index));
|
||||
//We only wanna see the source assets.
|
||||
if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
|
||||
{
|
||||
beginInsertRows(parent, row, row);
|
||||
m_indexMap[row] = index;
|
||||
endInsertRows();
|
||||
|
||||
Q_EMIT dataChanged(index, index);
|
||||
++row;
|
||||
}
|
||||
|
||||
if (model->hasChildren(index))
|
||||
{
|
||||
row = BuildTableModelMap(model, index, row);
|
||||
}
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
AssetBrowserEntry* AssetBrowserTableModel::GetAssetEntry(QModelIndex index) const
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
return static_cast<AssetBrowserEntry*>(index.internalPointer());
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("AssetBrowser", false, "Invalid Source Index provided to GetAssetEntry.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AssetBrowserTableModel::UpdateTableModelMaps()
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
if (!m_indexMap.isEmpty())
|
||||
{
|
||||
beginRemoveRows(m_indexMap.first(), m_indexMap.first().row(), m_indexMap.last().row());
|
||||
m_indexMap.clear();
|
||||
endRemoveRows();
|
||||
}
|
||||
BuildTableModelMap(sourceModel());
|
||||
emit layoutChanged();
|
||||
}
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
#include "AssetBrowser/moc_AssetBrowserTableModel.cpp"
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QPointer>
|
||||
#endif
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
class AssetBrowserFilterModel;
|
||||
class AssetBrowserEntry;
|
||||
|
||||
class AssetBrowserTableModel
|
||||
: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AssetBrowserTableModel, AZ::SystemAllocator, 0);
|
||||
explicit AssetBrowserTableModel(QObject* parent = nullptr);
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// QSortFilterProxyModel
|
||||
void setSourceModel(QAbstractItemModel* sourceModel) override;
|
||||
QModelIndex mapToSource(const QModelIndex& proxyIndex) const override;
|
||||
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void UpdateTableModelMaps();
|
||||
|
||||
protected:
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role /* = Qt::DisplayRole */) const override;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
AssetBrowserEntry* GetAssetEntry(QModelIndex index) const;
|
||||
int BuildTableModelMap(const QAbstractItemModel* model, const QModelIndex& parent = QModelIndex(), int row = 0);
|
||||
|
||||
private:
|
||||
QPointer<AssetBrowserFilterModel> m_filterModel;
|
||||
QMap<int, QModelIndex> m_indexMap;
|
||||
};
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <API/EditorAssetSystemAPI.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/ProductAssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(
|
||||
4244 4251 4800, "-Wunknown-warning-option") // conversion from 'int' to 'float', possible loss of data, needs to have dll-interface to
|
||||
// be used by clients of class 'QFlags<QPainter::RenderHint>::Int': forcing value to bool
|
||||
// 'true' or 'false' (performance warning)
|
||||
#include <QCoreApplication>
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QTimer>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
|
||||
: QTableView(parent)
|
||||
, m_delegate(new EntryDelegate(this))
|
||||
{
|
||||
setSortingEnabled(true);
|
||||
setItemDelegate(m_delegate);
|
||||
verticalHeader()->hide();
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
setMouseTracking(true);
|
||||
setSortingEnabled(false);
|
||||
setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
connect(this, &QTableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
|
||||
|
||||
AssetBrowserViewRequestBus::Handler::BusConnect();
|
||||
AssetBrowserComponentNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
AssetBrowserTableView::~AssetBrowserTableView()
|
||||
{
|
||||
AssetBrowserViewRequestBus::Handler::BusDisconnect();
|
||||
AssetBrowserComponentNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::setModel(QAbstractItemModel* model)
|
||||
{
|
||||
m_tableModel = qobject_cast<AssetBrowserTableModel*>(model);
|
||||
AZ_Assert(m_tableModel, "Expecting AssetBrowserTableModel");
|
||||
m_sourceFilterModel = qobject_cast<AssetBrowserFilterModel*>(m_tableModel->sourceModel());
|
||||
QTableView::setModel(model);
|
||||
connect(m_tableModel, &AssetBrowserTableModel::layoutChanged, this, &AssetBrowserTableView::layoutChangedSlot);
|
||||
|
||||
horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
|
||||
horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::SetName(const QString& name)
|
||||
{
|
||||
m_name = name;
|
||||
bool isAssetBrowserComponentReady = false;
|
||||
AssetBrowserComponentRequestBus::BroadcastResult(isAssetBrowserComponentReady, &AssetBrowserComponentRequests::AreEntriesReady);
|
||||
if (isAssetBrowserComponentReady)
|
||||
{
|
||||
OnAssetBrowserComponentReady();
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::vector<AssetBrowserEntry*> AssetBrowserTableView::GetSelectedAssets() const
|
||||
{
|
||||
QModelIndexList sourceIndexes;
|
||||
for (const auto& index : selectedIndexes())
|
||||
{
|
||||
if (index.column() == 0)
|
||||
{
|
||||
sourceIndexes.push_back(m_sourceFilterModel->mapToSource(m_tableModel->mapToSource(index)));
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::vector<AssetBrowserEntry*> entries;
|
||||
AssetBrowserModel::SourceIndexesToAssetDatabaseEntries(sourceIndexes, entries);
|
||||
return entries;
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
QTableView::selectionChanged(selected, deselected);
|
||||
Q_EMIT selectionChangedSignal(selected, deselected);
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
// if selected entry is being removed, clear selection so not to select (and attempt to preview) other entries potentially
|
||||
// marked for deletion
|
||||
if (selectionModel() && selectionModel()->selectedIndexes().size() == 1)
|
||||
{
|
||||
QModelIndex selectedIndex = selectionModel()->selectedIndexes().first();
|
||||
QModelIndex parentSelectedIndex = selectedIndex.parent();
|
||||
if (parentSelectedIndex == parent && selectedIndex.row() >= start && selectedIndex.row() <= end)
|
||||
{
|
||||
selectionModel()->clear();
|
||||
}
|
||||
}
|
||||
QTableView::rowsAboutToBeRemoved(parent, start, end);
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::layoutChangedSlot(
|
||||
[[maybe_unused]] const QList<QPersistentModelIndex>& parents, [[maybe_unused]] QAbstractItemModel::LayoutChangeHint hint)
|
||||
{
|
||||
scrollToTop();
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::SelectProduct([[maybe_unused]] AZ::Data::AssetId assetID)
|
||||
{
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::SelectFileAtPath([[maybe_unused]] const AZStd::string& assetPath)
|
||||
{
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::ClearFilter()
|
||||
{
|
||||
emit ClearStringFilter();
|
||||
emit ClearTypeFilter();
|
||||
m_sourceFilterModel->FilterUpdatedSlotImmediate();
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::Update()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::OnAssetBrowserComponentReady()
|
||||
{
|
||||
}
|
||||
|
||||
void AssetBrowserTableView::OnContextMenu([[maybe_unused]] const QPoint& point)
|
||||
{
|
||||
const auto& selectedAssets = GetSelectedAssets();
|
||||
if (selectedAssets.size() != 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu menu(this);
|
||||
AssetBrowserInteractionNotificationBus::Broadcast(
|
||||
&AssetBrowserInteractionNotificationBus::Events::AddContextMenuActions, this, &menu, selectedAssets);
|
||||
if (!menu.isEmpty())
|
||||
{
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
}
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
#include "AssetBrowser/Views/moc_AssetBrowserTableView.cpp"
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h>
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QPointer>
|
||||
#include <QTableView>
|
||||
#endif
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
class AssetBrowserEntry;
|
||||
class AssetBrowserTableModel;
|
||||
class AssetBrowserFilterModel;
|
||||
class EntryDelegate;
|
||||
|
||||
class AssetBrowserTableView //! Table view that displays the asset browser entries in a list.
|
||||
: public QTableView
|
||||
, public AssetBrowserViewRequestBus::Handler
|
||||
, public AssetBrowserComponentNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AssetBrowserTableView(QWidget* parent = nullptr);
|
||||
~AssetBrowserTableView() override;
|
||||
|
||||
void setModel(QAbstractItemModel *model) override;
|
||||
void SetName(const QString& name);
|
||||
|
||||
AZStd::vector<AssetBrowserEntry*> GetSelectedAssets() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AssetBrowserViewRequestBus
|
||||
virtual void SelectProduct(AZ::Data::AssetId assetID) override;
|
||||
virtual void SelectFileAtPath(const AZStd::string& assetPath) override;
|
||||
virtual void ClearFilter() override;
|
||||
virtual void Update() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AssetBrowserComponentNotificationBus
|
||||
void OnAssetBrowserComponentReady() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
Q_SIGNALS:
|
||||
void selectionChangedSignal(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
void ClearStringFilter();
|
||||
void ClearTypeFilter();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) override;
|
||||
void rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) override;
|
||||
void layoutChangedSlot(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
|
||||
QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QPointer<AssetBrowserTableModel> m_tableModel = nullptr;
|
||||
QPointer<AssetBrowserFilterModel> m_sourceFilterModel = nullptr;
|
||||
EntryDelegate* m_delegate = nullptr;
|
||||
|
||||
private Q_SLOTS:
|
||||
void OnContextMenu(const QPoint& point);
|
||||
};
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
@ -1,878 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
|
||||
* a third party where indicated.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Temporary dynamic tree structure used internally by GridMate.
|
||||
* To be replaced with a general Vis framework when that becomes available.
|
||||
*/
|
||||
|
||||
#ifndef RR_DYNAMIC_BOUNDING_VOLUME_TREE_H
|
||||
#define RR_DYNAMIC_BOUNDING_VOLUME_TREE_H
|
||||
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/Math/Plane.h>
|
||||
|
||||
#include <GridMate/Containers/vector.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
|
||||
namespace GridMate
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class DynamicTreeAabb : public AZ::Aabb
|
||||
{
|
||||
public:
|
||||
GM_CLASS_ALLOCATOR(DynamicTreeAabb);
|
||||
|
||||
AZ_FORCE_INLINE explicit DynamicTreeAabb() {}
|
||||
AZ_FORCE_INLINE DynamicTreeAabb(const AZ::Aabb& aabb) : AZ::Aabb(aabb) {}
|
||||
AZ_FORCE_INLINE explicit DynamicTreeAabb(const AZ::Vector3& min,const AZ::Vector3& max) : AZ::Aabb(AZ::Aabb::CreateFromMinMax(min,max)) {}
|
||||
|
||||
AZ_FORCE_INLINE static DynamicTreeAabb CreateFromFacePoints(const AZ::Vector3& a, const AZ::Vector3& b, const AZ::Vector3& c)
|
||||
{
|
||||
DynamicTreeAabb vol(a,a);
|
||||
vol.AddPoint(b);
|
||||
vol.AddPoint(c);
|
||||
return vol;
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE void SignedExpand(const AZ::Vector3& e)
|
||||
{
|
||||
AZ::Vector3 zero = AZ::Vector3::CreateZero();
|
||||
AZ::Vector3 mxE = m_max + e;
|
||||
AZ::Vector3 miE = m_min + e;
|
||||
m_max = AZ::Vector3::CreateSelectCmpGreater(e,zero,mxE,m_max );
|
||||
m_min = AZ::Vector3::CreateSelectCmpGreater(e,zero,m_min,miE);
|
||||
}
|
||||
AZ_FORCE_INLINE int Classify(const AZ::Vector3& n,const float o,int s) const
|
||||
{
|
||||
AZ::Vector3 pi, px;
|
||||
switch(s)
|
||||
{
|
||||
case (0+0+0): px=m_min;
|
||||
pi=m_max; break;
|
||||
case (1+0+0): px=AZ::Vector3(m_max.GetX(),m_min.GetY(),m_min.GetZ());
|
||||
pi=AZ::Vector3(m_min.GetX(),m_max.GetY(),m_max.GetZ());break;
|
||||
case (0+2+0): px=AZ::Vector3(m_min.GetX(),m_max.GetY(),m_min.GetZ());
|
||||
pi=AZ::Vector3(m_max.GetX(),m_min.GetY(),m_max.GetZ());break;
|
||||
case (1+2+0): px=AZ::Vector3(m_max.GetX(),m_max.GetY(),m_min.GetZ());
|
||||
pi=AZ::Vector3(m_min.GetX(),m_min.GetY(),m_max.GetZ());break;
|
||||
case (0+0+4): px=AZ::Vector3(m_min.GetX(),m_min.GetY(),m_max.GetZ());
|
||||
pi=AZ::Vector3(m_max.GetX(),m_max.GetY(),m_min.GetZ());break;
|
||||
case (1+0+4): px=AZ::Vector3(m_max.GetX(),m_min.GetY(),m_max.GetZ());
|
||||
pi=AZ::Vector3(m_min.GetX(),m_max.GetY(),m_min.GetZ());break;
|
||||
case (0+2+4): px=AZ::Vector3(m_min.GetX(),m_max.GetY(),m_max.GetZ());
|
||||
pi=AZ::Vector3(m_max.GetX(),m_min.GetY(),m_min.GetZ());break;
|
||||
case (1+2+4): px=m_max;
|
||||
pi=m_min;break;
|
||||
}
|
||||
|
||||
if (n.Dot(px) + o < 0.0f)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (n.Dot(pi) + o > 0.0f)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
AZ_FORCE_INLINE float ProjectMinimum(const AZ::Vector3& v, unsigned signs) const
|
||||
{
|
||||
const AZ::Vector3* b[]={&m_max,&m_min};
|
||||
const AZ::Vector3 p( b[(signs>>0)&1]->GetX(),b[(signs>>1)&1]->GetY(),b[(signs>>2)&1]->GetZ());
|
||||
return p.Dot(v);
|
||||
}
|
||||
|
||||
// Move the code here
|
||||
AZ_FORCE_INLINE friend bool IntersectAabbAabb(const DynamicTreeAabb& a,const DynamicTreeAabb& b);
|
||||
AZ_FORCE_INLINE friend bool IntersectAabbPoint(const DynamicTreeAabb& a, const AZ::Vector3& b);
|
||||
AZ_FORCE_INLINE friend bool IntersectAabbPlane(const DynamicTreeAabb& a, const AZ::Plane& b);
|
||||
AZ_FORCE_INLINE friend float Proximity(const DynamicTreeAabb& a, const DynamicTreeAabb& b);
|
||||
AZ_FORCE_INLINE friend int Select(const DynamicTreeAabb& o, const DynamicTreeAabb& a, const DynamicTreeAabb& b);
|
||||
AZ_FORCE_INLINE friend void Merge(const DynamicTreeAabb& a, const DynamicTreeAabb& b, DynamicTreeAabb& r);
|
||||
AZ_FORCE_INLINE friend bool NotEqual(const DynamicTreeAabb& a, const DynamicTreeAabb& b);
|
||||
private:
|
||||
AZ_FORCE_INLINE void AddSpan(const AZ::Vector3& d, float& smi, float& smx) const
|
||||
{
|
||||
AZ::Vector3 vecZero = AZ::Vector3::CreateZero();
|
||||
AZ::Vector3 mxD = m_max*d;
|
||||
AZ::Vector3 miD = m_min*d;
|
||||
AZ::Vector3 smiAdd = AZ::Vector3::CreateSelectCmpGreater(vecZero,d,mxD,miD);
|
||||
AZ::Vector3 smxAdd = AZ::Vector3::CreateSelectCmpGreater(vecZero,d,miD,mxD);
|
||||
AZ::Vector3 vecOne = AZ::Vector3::CreateOne();
|
||||
// sum components
|
||||
smi += smiAdd.Dot(vecOne);
|
||||
smx += smxAdd.Dot(vecOne);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
AZ_FORCE_INLINE bool IntersectAabbAabb(const DynamicTreeAabb& a, const DynamicTreeAabb& b)
|
||||
{
|
||||
return a.Overlaps(b);
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE bool IntersectAabbPlane(const DynamicTreeAabb& a, const AZ::Plane& b)
|
||||
{
|
||||
//use plane normal to quickly select the nearest corner of the aabb
|
||||
AZ::Vector3 testPoint = AZ::Vector3::CreateSelectCmpGreater(b.GetNormal(), AZ::Vector3::CreateZero(), a.GetMin(), a.GetMax());
|
||||
//test if nearest point is inside the plane
|
||||
return b.GetPointDist(testPoint) <= 0.0f;
|
||||
}
|
||||
|
||||
//
|
||||
AZ_FORCE_INLINE float Proximity(const DynamicTreeAabb& a, const DynamicTreeAabb& b)
|
||||
{
|
||||
const AZ::Vector3 d=(a.m_min+a.m_max)-(b.m_min+b.m_max);
|
||||
// get abs and sum
|
||||
return d.GetAbs().Dot(AZ::Vector3::CreateOne());
|
||||
}
|
||||
|
||||
//
|
||||
AZ_FORCE_INLINE int Select( const DynamicTreeAabb& o, const DynamicTreeAabb& a, const DynamicTreeAabb& b)
|
||||
{
|
||||
return Proximity(o,a) < Proximity(o,b);
|
||||
}
|
||||
|
||||
//
|
||||
AZ_FORCE_INLINE void Merge(const DynamicTreeAabb& a, const DynamicTreeAabb& b, DynamicTreeAabb& r)
|
||||
{
|
||||
r.m_min = AZ::Vector3::CreateSelectCmpGreater(b.m_min,a.m_min,a.m_min,b.m_min);
|
||||
r.m_max = AZ::Vector3::CreateSelectCmpGreater(a.m_max,b.m_max,a.m_max,b.m_max);
|
||||
}
|
||||
|
||||
//
|
||||
AZ_FORCE_INLINE bool NotEqual( const DynamicTreeAabb& a, const DynamicTreeAabb& b)
|
||||
{
|
||||
return (a.m_min != b.m_min || a.m_max != b.m_max);
|
||||
}
|
||||
|
||||
|
||||
/* NodeType */
|
||||
struct DynamicTreeNode
|
||||
{
|
||||
GM_CLASS_ALLOCATOR(DynamicTreeNode);
|
||||
|
||||
DynamicTreeAabb m_volume;
|
||||
DynamicTreeNode* m_parent;
|
||||
AZ_FORCE_INLINE bool IsLeaf() const { return(m_childs[1]==0); }
|
||||
AZ_FORCE_INLINE bool IsInternal() const { return(!IsLeaf()); }
|
||||
union
|
||||
{
|
||||
DynamicTreeNode* m_childs[2];
|
||||
void* m_data;
|
||||
int m_dataAsInt;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of dynamic aabb tree, based on the bullet dynamic tree (btDbvt).
|
||||
*
|
||||
* The BvDynamicTree class implements a fast dynamic bounding volume tree based on axis aligned bounding boxes (aabb tree).
|
||||
* This BvDynamicTree is used for soft body collision detection and for the btDbvtBroadphase. It has a fast insert, remove and update of nodes.
|
||||
* Unlike the BvTreeQuantized, nodes can be dynamically moved around, which allows for change in topology of the underlying data structure.
|
||||
*/
|
||||
class BvDynamicTree
|
||||
{
|
||||
public:
|
||||
using Ptr = AZStd::intrusive_ptr<BvDynamicTree>;
|
||||
|
||||
GM_CLASS_ALLOCATOR(BvDynamicTree);
|
||||
|
||||
typedef Internal::DynamicTreeAabb VolumeType;
|
||||
typedef Internal::DynamicTreeNode NodeType;
|
||||
|
||||
typedef vector<NodeType*> NodeArrayType;
|
||||
typedef vector<const NodeType*> ConstNodeArrayType;
|
||||
|
||||
private:
|
||||
|
||||
/* Stack element */
|
||||
struct sStkNN
|
||||
{
|
||||
const NodeType* a;
|
||||
const NodeType* b;
|
||||
sStkNN() {}
|
||||
sStkNN(const NodeType* na,const NodeType* nb) : a(na), b(nb) {}
|
||||
};
|
||||
struct sStkNP
|
||||
{
|
||||
const NodeType* node;
|
||||
int mask;
|
||||
sStkNP(const NodeType* n, unsigned m) : node(n), mask(m) {}
|
||||
};
|
||||
struct sStkNPS
|
||||
{
|
||||
const NodeType* node;
|
||||
int mask;
|
||||
float value;
|
||||
sStkNPS() {}
|
||||
sStkNPS(const NodeType* n, unsigned m, const float v) : node(n), mask(m), value(v) {}
|
||||
};
|
||||
struct sStkCLN
|
||||
{
|
||||
const NodeType* node;
|
||||
NodeType* parent;
|
||||
sStkCLN(const NodeType* n, NodeType* p) : node(n), parent(p) {}
|
||||
};
|
||||
|
||||
public:
|
||||
/* ICollideCollector templated collectors should implement this functions or inherit from this class */
|
||||
struct ICollideCollector
|
||||
{
|
||||
void Process(const NodeType*, const NodeType*) {}
|
||||
void Process(const NodeType*) {}
|
||||
void Process(const NodeType* n, const float) { Process(n); }
|
||||
bool Descent(const NodeType*) { return true; }
|
||||
bool AllLeaves(const NodeType*) { return true; }
|
||||
};
|
||||
|
||||
/* IWriter */
|
||||
struct IWriter
|
||||
{
|
||||
virtual ~IWriter() {}
|
||||
virtual void Prepare(const NodeType* root,int numnodes) = 0;
|
||||
virtual void WriteNode(const NodeType*, int index, int parent, int child0, int child1) = 0;
|
||||
virtual void WriteLeaf(const NodeType*, int index, int parent) = 0;
|
||||
};
|
||||
/* IClone */
|
||||
struct IClone
|
||||
{
|
||||
virtual ~IClone() {}
|
||||
virtual void CloneLeaf(NodeType*) {}
|
||||
};
|
||||
|
||||
// Constants
|
||||
enum
|
||||
{
|
||||
SIMPLE_STACKSIZE = 64,
|
||||
DOUBLE_STACKSIZE = SIMPLE_STACKSIZE * 2
|
||||
};
|
||||
|
||||
// Methods
|
||||
BvDynamicTree();
|
||||
~BvDynamicTree();
|
||||
|
||||
NodeType* GetRoot() const { return m_root; }
|
||||
void Clear();
|
||||
bool Empty() const { return 0 == m_root; }
|
||||
int GetNumLeaves() const { return m_leaves; }
|
||||
void OptimizeBottomUp();
|
||||
void OptimizeTopDown(int bu_treshold = 128);
|
||||
void OptimizeIncremental(int passes);
|
||||
NodeType* Insert(const VolumeType& box,void* data);
|
||||
void Update(NodeType* leaf, int lookahead=-1);
|
||||
void Update(NodeType* leaf, VolumeType& volume);
|
||||
bool Update(NodeType* leaf, VolumeType& volume, const AZ::Vector3& velocity, const float margin);
|
||||
bool Update(NodeType* leaf, VolumeType& volume, const AZ::Vector3& velocity);
|
||||
bool Update(NodeType* leaf, VolumeType& volume, const float margin);
|
||||
void Remove(NodeType* leaf);
|
||||
void Write(IWriter* iwriter) const;
|
||||
void Clone(BvDynamicTree& dest, IClone* iclone=0) const;
|
||||
static int GetMaxDepth(const NodeType* node);
|
||||
static int CountLeaves(const NodeType* node);
|
||||
static void ExtractLeaves(const NodeType* node, /*btAlignedObjectArray<const NodeType*>&*/vector<const NodeType*>& leaves);
|
||||
#if DBVT_ENABLE_BENCHMARK
|
||||
static void Benchmark();
|
||||
#else
|
||||
static void Benchmark(){}
|
||||
#endif
|
||||
/**
|
||||
* Collector should inherit from ICollide
|
||||
*/
|
||||
template<class Collector>
|
||||
static inline void enumNodes( const NodeType* root, Collector& collector)
|
||||
{
|
||||
collector.Process(root);
|
||||
if(root->IsInternal())
|
||||
{
|
||||
enumNodes(root->m_childs[0],collector);
|
||||
enumNodes(root->m_childs[1],collector);
|
||||
}
|
||||
}
|
||||
template<class Collector>
|
||||
static void enumLeaves( const NodeType* root,Collector& collector)
|
||||
{
|
||||
if(root->IsInternal())
|
||||
{
|
||||
enumLeaves(root->m_childs[0],collector);
|
||||
enumLeaves(root->m_childs[1],collector);
|
||||
}
|
||||
else
|
||||
{
|
||||
collector.Process(root);
|
||||
}
|
||||
}
|
||||
template<class Collector>
|
||||
void collideTT( const NodeType* root0,const NodeType* root1,Collector& collector) const
|
||||
{
|
||||
if(root0&&root1)
|
||||
{
|
||||
size_t depth=1;
|
||||
size_t treshold=DOUBLE_STACKSIZE-4;
|
||||
vector<sStkNN> stkStack;
|
||||
stkStack.resize(DOUBLE_STACKSIZE);
|
||||
stkStack[0]=sStkNN(root0,root1);
|
||||
do {
|
||||
sStkNN p=stkStack[--depth];
|
||||
if(depth>treshold)
|
||||
{
|
||||
stkStack.resize(stkStack.size()*2);
|
||||
treshold=stkStack.size()-4;
|
||||
}
|
||||
if(p.a==p.b)
|
||||
{
|
||||
if(p.a->IsInternal())
|
||||
{
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[0],p.a->m_childs[0]);
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[1],p.a->m_childs[1]);
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[0],p.a->m_childs[1]);
|
||||
}
|
||||
}
|
||||
else if(IntersectAabbAabb(p.a->m_volume,p.b->m_volume))
|
||||
{
|
||||
if(p.a->IsInternal())
|
||||
{
|
||||
if(p.b->IsInternal())
|
||||
{
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[0],p.b->m_childs[0]);
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[1],p.b->m_childs[0]);
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[0],p.b->m_childs[1]);
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[1],p.b->m_childs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[0],p.b);
|
||||
stkStack[depth++]=sStkNN(p.a->m_childs[1],p.b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(p.b->IsInternal())
|
||||
{
|
||||
stkStack[depth++]=sStkNN(p.a,p.b->m_childs[0]);
|
||||
stkStack[depth++]=sStkNN(p.a,p.b->m_childs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
collector.Process(p.a,p.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(depth);
|
||||
}
|
||||
}
|
||||
template<class Collector>
|
||||
void collideTTpersistentStack( const NodeType* root0, const NodeType* root1,Collector& collector)
|
||||
{
|
||||
if(root0&&root1)
|
||||
{
|
||||
size_t depth=1;
|
||||
size_t treshold=DOUBLE_STACKSIZE-4;
|
||||
|
||||
m_stkStack.resize(DOUBLE_STACKSIZE);
|
||||
m_stkStack[0]=sStkNN(root0,root1);
|
||||
do
|
||||
{
|
||||
sStkNN p=m_stkStack[--depth];
|
||||
if(depth>treshold)
|
||||
{
|
||||
m_stkStack.resize(m_stkStack.size()*2);
|
||||
treshold=m_stkStack.size()-4;
|
||||
}
|
||||
if(p.a==p.b)
|
||||
{
|
||||
if(p.a->IsInternal())
|
||||
{
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[0],p.a->m_childs[0]);
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[1],p.a->m_childs[1]);
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[0],p.a->m_childs[1]);
|
||||
}
|
||||
}
|
||||
else if(IntersectAabbAabb(p.a->m_volume,p.b->m_volume))
|
||||
{
|
||||
if(p.a->IsInternal())
|
||||
{
|
||||
if(p.b->IsInternal())
|
||||
{
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[0],p.b->m_childs[0]);
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[1],p.b->m_childs[0]);
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[0],p.b->m_childs[1]);
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[1],p.b->m_childs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[0],p.b);
|
||||
m_stkStack[depth++]=sStkNN(p.a->m_childs[1],p.b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(p.b->IsInternal())
|
||||
{
|
||||
m_stkStack[depth++]=sStkNN(p.a,p.b->m_childs[0]);
|
||||
m_stkStack[depth++]=sStkNN(p.a,p.b->m_childs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
collector.Process(p.a,p.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(depth);
|
||||
}
|
||||
}
|
||||
template<class Collector>
|
||||
void collideTV( const NodeType* root, const VolumeType& volume, Collector& collector) const
|
||||
{
|
||||
if(root)
|
||||
{
|
||||
// ATTRIBUTE_ALIGNED16(VolumeType) volume(vol);
|
||||
// btAlignedObjectArray<const NodeType*> stack;
|
||||
AZStd::fixed_vector<const NodeType*,SIMPLE_STACKSIZE> stack;
|
||||
//stack.reserve(SIMPLE_STACKSIZE);
|
||||
stack.push_back(root);
|
||||
do {
|
||||
const NodeType* n=stack[stack.size()-1];
|
||||
stack.pop_back();
|
||||
if(IntersectAabbAabb(n->m_volume,volume))
|
||||
{
|
||||
if(n->IsInternal())
|
||||
{
|
||||
stack.push_back(n->m_childs[0]);
|
||||
stack.push_back(n->m_childs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
collector.Process(n);
|
||||
}
|
||||
}
|
||||
} while(!stack.empty());
|
||||
}
|
||||
}
|
||||
|
||||
template<class Collector>
|
||||
void collideTP(const NodeType* root, const AZ::Plane& plane, Collector& collector) const
|
||||
{
|
||||
if (root)
|
||||
{
|
||||
AZStd::fixed_vector<const NodeType*,SIMPLE_STACKSIZE> stack;
|
||||
stack.push_back(root);
|
||||
do
|
||||
{
|
||||
const NodeType* n=stack[stack.size()-1];
|
||||
stack.pop_back();
|
||||
if (IntersectAabbPlane(n->m_volume, plane))
|
||||
{
|
||||
if(n->IsInternal())
|
||||
{
|
||||
stack.push_back(n->m_childs[0]);
|
||||
stack.push_back(n->m_childs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
collector.Process(n);
|
||||
}
|
||||
}
|
||||
} while (!stack.empty());
|
||||
}
|
||||
}
|
||||
|
||||
///rayTest is a re-entrant ray test, and can be called in parallel as long as the btAlignedAlloc is thread-safe (uses locking etc)
|
||||
///rayTest is slower than rayTestInternal, because it builds a local stack, using memory allocations, and it recomputes signs/rayDirectionInverses each time
|
||||
template<class Collector>
|
||||
static void rayTest( const NodeType* root, const AZ::Vector3& rayFrom, const AZ::Vector3& rayTo, Collector& collector)
|
||||
{
|
||||
if(root)
|
||||
{
|
||||
AZ::Vector3 ray = rayTo-rayFrom;
|
||||
AZ::Vector3 rayDir = ray.GetNormalized();
|
||||
|
||||
///what about division by zero? --> just set rayDirection[i] to INF/1e30
|
||||
AZ::Vector3 rayDirectionInverse = AZ::Vector3::CreateSelectCmpEqual(rayDir,AZ::Vector3::CreateZero(),AZ::Vector3(1e30),rayDir.GetReciprocal());
|
||||
|
||||
unsigned int signs[3];// = { rayDirectionInverse[0] < 0.0f, rayDirectionInverse[1] < 0.0f, rayDirectionInverse[2] < 0.0f };
|
||||
signs[0] = rayDirectionInverse.GetX() < 0.0f;
|
||||
signs[1] = rayDirectionInverse.GetY() < 0.0f;
|
||||
signs[2] = rayDirectionInverse.GetZ() < 0.0f;
|
||||
|
||||
//float lambda_max = rayDir.Dot(ray);
|
||||
|
||||
AZ::Vector3 resultNormal;
|
||||
|
||||
//btAlignedObjectArray<const NodeType*> stack;
|
||||
vector<const NodeType*> stack;
|
||||
|
||||
int depth=1;
|
||||
int treshold=DOUBLE_STACKSIZE-2;
|
||||
|
||||
stack.resize(DOUBLE_STACKSIZE);
|
||||
stack[0]=root;
|
||||
AZ::Vector3 bounds[2];
|
||||
do {
|
||||
const NodeType* node=stack[--depth];
|
||||
|
||||
bounds[0] = node->m_volume.GetMin();
|
||||
bounds[1] = node->m_volume.GetMax();
|
||||
|
||||
//float tmin = 1.0f;
|
||||
//float lambda_min = 0.0f;
|
||||
// todo..
|
||||
unsigned int result1 = /*btRayAabb2(rayFrom,rayDirectionInverse,signs,bounds,tmin,lambda_min,lambda_max)*/0;
|
||||
#ifdef COMPARE_BTRAY_AABB2
|
||||
float param = 1.0f;
|
||||
bool result2 = /*btRayAabb(rayFrom,rayTo,node->volume.GetMin(),node->volume.GetMax(),param,resultNormal)*/0;
|
||||
AZ_Assert(result1 == result2, "");
|
||||
#endif //TEST_BTRAY_AABB2
|
||||
if(result1)
|
||||
{
|
||||
if(node->IsInternal())
|
||||
{
|
||||
if(depth>treshold)
|
||||
{
|
||||
stack.resize(stack.size()*2);
|
||||
treshold=stack.size()-2;
|
||||
}
|
||||
stack[depth++]=node->m_childs[0];
|
||||
stack[depth++]=node->m_childs[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
collector.Process(node);
|
||||
}
|
||||
}
|
||||
} while(depth);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///rayTestInternal is faster than rayTest, because it uses a persistent stack (to reduce dynamic memory allocations to a minimum) and it uses precomputed signs/rayInverseDirections
|
||||
///rayTestInternal is used by btDbvtBroadphase to accelerate world ray casts
|
||||
template<class Collector>
|
||||
void rayTestInternal(const NodeType* root, const AZ::Vector3& rayFrom, const AZ::Vector3& rayTo, const AZ::Vector3& rayDirectionInverse, unsigned int signs[3], const float lambda_max, const AZ::Vector3& aabbMin, const AZ::Vector3& aabbMax, Collector& collector) const
|
||||
{
|
||||
(void)rayFrom;(void)rayTo;(void)rayDirectionInverse;(void)signs;(void)lambda_max;
|
||||
if(root)
|
||||
{
|
||||
AZ::Vector3 resultNormal;
|
||||
|
||||
int depth=1;
|
||||
int treshold=DOUBLE_STACKSIZE-2;
|
||||
vector<const NodeType*> stack;
|
||||
stack.resize(DOUBLE_STACKSIZE);
|
||||
stack[0]=root;
|
||||
AZ::Vector3 bounds[2];
|
||||
do
|
||||
{
|
||||
const NodeType* node=stack[--depth];
|
||||
bounds[0] = node->m_volume.GetMin()+aabbMin;
|
||||
bounds[1] = node->m_volume.GetMax()+aabbMax;
|
||||
|
||||
//float tmin = 1.0f;
|
||||
//float lambda_min = 0.0f;
|
||||
unsigned int result1=false;
|
||||
// todo...
|
||||
result1 = /*btRayAabb2(rayFrom,rayDirectionInverse,signs,bounds,tmin,lambda_min,lambda_max)*/false;
|
||||
if(result1)
|
||||
{
|
||||
if(node->IsInternal())
|
||||
{
|
||||
if(depth>treshold)
|
||||
{
|
||||
stack.resize(stack.size()*2);
|
||||
treshold=stack.size()-2;
|
||||
}
|
||||
stack[depth++]=node->m_childs[0];
|
||||
stack[depth++]=node->m_childs[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
collector.Process(node);
|
||||
}
|
||||
}
|
||||
} while(depth);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Collector>
|
||||
static void collideKDOP(const NodeType* root, const AZ::Vector3* normals, const float* offsets, int count, Collector& collector)
|
||||
{
|
||||
(void)root;(void)normals;(void)offsets;(void)count;(void)collector;
|
||||
/* if(root)
|
||||
{
|
||||
const int inside=(1<<count)-1;
|
||||
btAlignedObjectArray<sStkNP> stack;
|
||||
int signs[sizeof(unsigned)*8];
|
||||
btAssert(count<int (sizeof(signs)/sizeof(signs[0])));
|
||||
for(int i=0;i<count;++i)
|
||||
{
|
||||
signs[i]= ((normals[i].x()>=0)?1:0)+
|
||||
((normals[i].y()>=0)?2:0)+
|
||||
((normals[i].z()>=0)?4:0);
|
||||
}
|
||||
stack.reserve(SIMPLE_STACKSIZE);
|
||||
stack.push_back(sStkNP(root,0));
|
||||
do {
|
||||
sStkNP se=stack[stack.size()-1];
|
||||
bool out=false;
|
||||
stack.pop_back();
|
||||
for(int i=0,j=1;(!out)&&(i<count);++i,j<<=1)
|
||||
{
|
||||
if(0==(se.mask&j))
|
||||
{
|
||||
const int side=se.node->volume.Classify(normals[i],offsets[i],signs[i]);
|
||||
switch(side)
|
||||
{
|
||||
case -1: out=true;break;
|
||||
case +1: se.mask|=j;break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!out)
|
||||
{
|
||||
if((se.mask!=inside)&&(se.node->isinternal()))
|
||||
{
|
||||
stack.push_back(sStkNP(se.node->childs[0],se.mask));
|
||||
stack.push_back(sStkNP(se.node->childs[1],se.mask));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(policy.AllLeaves(se.node)) enumLeaves(se.node,policy);
|
||||
}
|
||||
}
|
||||
} while(!stack.empty());
|
||||
}*/
|
||||
}
|
||||
template<class Collector>
|
||||
static void collideOCL( const NodeType* root, const AZ::Vector3* normals, const float* offsets, const AZ::Vector3& sortaxis, int count, Collector& collector, bool fullsort=true)
|
||||
{
|
||||
(void)root;(void)normals;(void)offsets;(void)sortaxis;(void)count;(void)offsets;(void)collector;(void)fullsort;
|
||||
/* if(root)
|
||||
{
|
||||
const unsigned srtsgns=(sortaxis[0]>=0?1:0)+
|
||||
(sortaxis[1]>=0?2:0)+
|
||||
(sortaxis[2]>=0?4:0);
|
||||
const int inside=(1<<count)-1;
|
||||
btAlignedObjectArray<sStkNPS> stock;
|
||||
btAlignedObjectArray<int> ifree;
|
||||
btAlignedObjectArray<int> stack;
|
||||
int signs[sizeof(unsigned)*8];
|
||||
btAssert(count<int (sizeof(signs)/sizeof(signs[0])));
|
||||
for(int i=0;i<count;++i)
|
||||
{
|
||||
signs[i]= ((normals[i].x()>=0)?1:0)+
|
||||
((normals[i].y()>=0)?2:0)+
|
||||
((normals[i].z()>=0)?4:0);
|
||||
}
|
||||
stock.reserve(SIMPLE_STACKSIZE);
|
||||
stack.reserve(SIMPLE_STACKSIZE);
|
||||
ifree.reserve(SIMPLE_STACKSIZE);
|
||||
stack.push_back(allocate(ifree,stock,sStkNPS(root,0,root->volume.ProjectMinimum(sortaxis,srtsgns))));
|
||||
do {
|
||||
const int id=stack[stack.size()-1];
|
||||
sStkNPS se=stock[id];
|
||||
stack.pop_back();ifree.push_back(id);
|
||||
if(se.mask!=inside)
|
||||
{
|
||||
bool out=false;
|
||||
for(int i=0,j=1;(!out)&&(i<count);++i,j<<=1)
|
||||
{
|
||||
if(0==(se.mask&j))
|
||||
{
|
||||
const int side=se.node->volume.Classify(normals[i],offsets[i],signs[i]);
|
||||
switch(side)
|
||||
{
|
||||
case -1: out=true;break;
|
||||
case +1: se.mask|=j;break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(out) continue;
|
||||
}
|
||||
if(policy.Descent(se.node))
|
||||
{
|
||||
if(se.node->isinternal())
|
||||
{
|
||||
const NodeType* pns[]={ se.node->childs[0],se.node->childs[1]};
|
||||
sStkNPS nes[]={ sStkNPS(pns[0],se.mask,pns[0]->volume.ProjectMinimum(sortaxis,srtsgns)),
|
||||
sStkNPS(pns[1],se.mask,pns[1]->volume.ProjectMinimum(sortaxis,srtsgns))};
|
||||
const int q=nes[0].value<nes[1].value?1:0;
|
||||
int j=stack.size();
|
||||
if(fsort&&(j>0))
|
||||
{
|
||||
// Insert 0
|
||||
j=nearest(&stack[0],&stock[0],nes[q].value,0,stack.size());
|
||||
stack.push_back(0);
|
||||
#if DBVT_USE_MEMMOVE
|
||||
memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1));
|
||||
#else
|
||||
for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1];
|
||||
#endif
|
||||
stack[j]=allocate(ifree,stock,nes[q]);
|
||||
// Insert 1
|
||||
j=nearest(&stack[0],&stock[0],nes[1-q].value,j,stack.size());
|
||||
stack.push_back(0);
|
||||
#if DBVT_USE_MEMMOVE
|
||||
memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1));
|
||||
#else
|
||||
for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1];
|
||||
#endif
|
||||
stack[j]=allocate(ifree,stock,nes[1-q]);
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.push_back(allocate(ifree,stock,nes[q]));
|
||||
stack.push_back(allocate(ifree,stock,nes[1-q]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
policy.Process(se.node,se.value);
|
||||
}
|
||||
}
|
||||
} while(stack.size());
|
||||
}*/
|
||||
}
|
||||
|
||||
template<class Collector>
|
||||
static void collideTU(const NodeType* root, Collector& collector)
|
||||
{
|
||||
(void)root;(void)collector;
|
||||
/* if(root)
|
||||
{
|
||||
btAlignedObjectArray<const NodeType*> stack;
|
||||
stack.reserve(SIMPLE_STACKSIZE);
|
||||
stack.push_back(root);
|
||||
do {
|
||||
const NodeType* n=stack[stack.size()-1];
|
||||
stack.pop_back();
|
||||
if(policy.Descent(n))
|
||||
{
|
||||
if(n->isinternal())
|
||||
{ stack.push_back(n->childs[0]);stack.push_back(n->childs[1]); }
|
||||
else
|
||||
{ policy.Process(n); }
|
||||
}
|
||||
} while(stack.size()>0);
|
||||
}*/
|
||||
}
|
||||
|
||||
private:
|
||||
BvDynamicTree(const BvDynamicTree&) {}
|
||||
|
||||
// Helpers
|
||||
//static AZ_FORCE_INLINE int nearest(const int* i,const BvDynamicTree::sStkNPS* a,const float& v,int l,int h)
|
||||
//{
|
||||
// int m=0;
|
||||
// while(l<h)
|
||||
// {
|
||||
// m=(l+h)>>1;
|
||||
// if(a[i[m]].value>=v) l=m+1; else h=m;
|
||||
// }
|
||||
// return h;
|
||||
//}
|
||||
//static AZ_FORCE_INLINE int allocate( int_fixed_stack_type& ifree, stknps_fixed_stack_type& stock, const sStkNPS& value)
|
||||
//{
|
||||
// int i;
|
||||
// if( !ifree.empty() )
|
||||
// {
|
||||
// i=ifree[ifree.size()-1];
|
||||
// ifree.pop_back();
|
||||
// stock[i]=value;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// i=stock.size();
|
||||
// stock.push_back(value);
|
||||
// }
|
||||
// return i;
|
||||
//}
|
||||
//
|
||||
|
||||
AZ_FORCE_INLINE void deletenode( NodeType* node)
|
||||
{
|
||||
//btAlignedFree(pdbvt->m_free);
|
||||
delete m_free;
|
||||
m_free=node;
|
||||
}
|
||||
|
||||
void recursedeletenode( NodeType* node)
|
||||
{
|
||||
if(!node->IsLeaf())
|
||||
{
|
||||
recursedeletenode(node->m_childs[0]);
|
||||
recursedeletenode(node->m_childs[1]);
|
||||
}
|
||||
|
||||
if( node == m_root ) m_root=0;
|
||||
deletenode(node);
|
||||
}
|
||||
|
||||
|
||||
AZ_FORCE_INLINE NodeType* createnode( NodeType* parent, void* data)
|
||||
{
|
||||
NodeType* node;
|
||||
if(m_free)
|
||||
{ node=m_free;m_free=0; }
|
||||
else
|
||||
{ node = aznew NodeType(); }
|
||||
node->m_parent = parent;
|
||||
node->m_data = data;
|
||||
node->m_childs[1] = 0;
|
||||
return node;
|
||||
}
|
||||
AZ_FORCE_INLINE NodeType* createnode( BvDynamicTree::NodeType* parent, const VolumeType& volume, void* data)
|
||||
{
|
||||
NodeType* node = createnode(parent,data);
|
||||
node->m_volume=volume;
|
||||
return node;
|
||||
}
|
||||
//
|
||||
AZ_FORCE_INLINE NodeType* createnode( BvDynamicTree::NodeType* parent, const VolumeType& volume0, const VolumeType& volume1, void* data)
|
||||
{
|
||||
NodeType* node = createnode(parent,data);
|
||||
Merge(volume0,volume1,node->m_volume);
|
||||
return node;
|
||||
}
|
||||
void insertleaf( NodeType* root, NodeType* leaf);
|
||||
NodeType* removeleaf( NodeType* leaf);
|
||||
void fetchleaves(NodeType* root,NodeArrayType& leaves,int depth=-1);
|
||||
void split(const NodeArrayType& leaves,NodeArrayType& left,NodeArrayType& right,const AZ::Vector3& org,const AZ::Vector3& axis);
|
||||
VolumeType bounds(const NodeArrayType& leaves);
|
||||
void bottomup( NodeArrayType& leaves );
|
||||
NodeType* topdown(NodeArrayType& leaves,int bu_treshold);
|
||||
AZ_FORCE_INLINE NodeType* sort(NodeType* n,NodeType*& r);
|
||||
|
||||
NodeType* m_root;
|
||||
NodeType* m_free;
|
||||
int m_lkhd;
|
||||
int m_leaves;
|
||||
unsigned m_opath;
|
||||
|
||||
//btAlignedObjectArray<sStkNN> m_stkStack;
|
||||
// Profile and choose static or dynamic vector.
|
||||
typedef AZStd::fixed_vector<sStkNN,DOUBLE_STACKSIZE> stknn_fixed_stack_type;
|
||||
typedef AZStd::fixed_vector<int,SIMPLE_STACKSIZE> int_fixed_stack_type;
|
||||
typedef AZStd::fixed_vector<sStkNPS,SIMPLE_STACKSIZE> stknps_fixed_stack_type;
|
||||
|
||||
stknn_fixed_stack_type m_stkStack;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // RR_DYNAMIC_BOUNDING_VOLUME_TREE_H
|
||||
#pragma once
|
||||
@ -1,597 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GridMate/Replica/Interest/ProximityInterestHandler.h>
|
||||
|
||||
#include <GridMate/Replica/Replica.h>
|
||||
#include <GridMate/Replica/ReplicaFunctions.h>
|
||||
#include <GridMate/Replica/ReplicaMgr.h>
|
||||
|
||||
#include <GridMate/Replica/Interest/InterestManager.h>
|
||||
#include <GridMate/Replica/Interest/BvDynamicTree.h>
|
||||
|
||||
// for highly verbose internal debugging
|
||||
//#define INTERNAL_DEBUG_PROXIMITY
|
||||
|
||||
namespace GridMate
|
||||
{
|
||||
|
||||
void ProximityInterestChunk::OnReplicaActivate(const ReplicaContext& rc)
|
||||
{
|
||||
m_interestHandler = static_cast<ProximityInterestHandler*>(rc.m_rm->GetUserContext(AZ_CRC("ProximityInterestHandler", 0x3a90b3e4)));
|
||||
AZ_Warning("GridMate", m_interestHandler, "No proximity interest handler in the user context");
|
||||
|
||||
if (m_interestHandler)
|
||||
{
|
||||
m_interestHandler->OnNewRulesChunk(this, rc.m_peer);
|
||||
}
|
||||
}
|
||||
|
||||
void ProximityInterestChunk::OnReplicaDeactivate(const ReplicaContext& rc)
|
||||
{
|
||||
if (rc.m_peer && m_interestHandler)
|
||||
{
|
||||
m_interestHandler->OnDeleteRulesChunk(this, rc.m_peer);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProximityInterestChunk::AddRuleFn(RuleNetworkId netId, AZ::Aabb bbox, const RpcContext& ctx)
|
||||
{
|
||||
if (IsProxy())
|
||||
{
|
||||
auto rulePtr = m_interestHandler->CreateRule(ctx.m_sourcePeer);
|
||||
rulePtr->Set(bbox);
|
||||
m_rules.insert(AZStd::make_pair(netId, rulePtr));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProximityInterestChunk::RemoveRuleFn(RuleNetworkId netId, const RpcContext&)
|
||||
{
|
||||
if (IsProxy())
|
||||
{
|
||||
m_rules.erase(netId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProximityInterestChunk::UpdateRuleFn(RuleNetworkId netId, AZ::Aabb bbox, const RpcContext&)
|
||||
{
|
||||
if (IsProxy())
|
||||
{
|
||||
auto it = m_rules.find(netId);
|
||||
if (it != m_rules.end())
|
||||
{
|
||||
it->second->Set(bbox);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProximityInterestChunk::AddRuleForPeerFn(RuleNetworkId netId, PeerId peerId, AZ::Aabb bbox, const RpcContext&)
|
||||
{
|
||||
ProximityInterestChunk* peerChunk = m_interestHandler->FindRulesChunkByPeerId(peerId);
|
||||
if (peerChunk)
|
||||
{
|
||||
auto it = peerChunk->m_rules.find(netId);
|
||||
if (it == peerChunk->m_rules.end())
|
||||
{
|
||||
auto rulePtr = m_interestHandler->CreateRule(peerId);
|
||||
peerChunk->m_rules.insert(AZStd::make_pair(netId, rulePtr));
|
||||
rulePtr->Set(bbox);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
* ProximityInterest
|
||||
*/
|
||||
ProximityInterest::ProximityInterest(ProximityInterestHandler* handler)
|
||||
: m_handler(handler)
|
||||
, m_bbox(AZ::Aabb::CreateNull())
|
||||
{
|
||||
AZ_Assert(m_handler, "Invalid interest handler");
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
* ProximityInterestRule
|
||||
*/
|
||||
void ProximityInterestRule::Set(const AZ::Aabb& bbox)
|
||||
{
|
||||
m_bbox = bbox;
|
||||
m_handler->UpdateRule(this);
|
||||
}
|
||||
|
||||
void ProximityInterestRule::Destroy()
|
||||
{
|
||||
m_handler->DestroyRule(this);
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
* ProximityInterestAttribute
|
||||
*/
|
||||
void ProximityInterestAttribute::Set(const AZ::Aabb& bbox)
|
||||
{
|
||||
m_bbox = bbox;
|
||||
m_handler->UpdateAttribute(this);
|
||||
}
|
||||
|
||||
void ProximityInterestAttribute::Destroy()
|
||||
{
|
||||
m_handler->DestroyAttribute(this);
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
* ProximityInterestHandler
|
||||
*/
|
||||
ProximityInterestHandler::ProximityInterestHandler()
|
||||
: m_im(nullptr)
|
||||
, m_rm(nullptr)
|
||||
, m_lastRuleNetId(0)
|
||||
, m_rulesReplica(nullptr)
|
||||
{
|
||||
m_attributeWorld = AZStd::make_unique<SpatialIndex>();
|
||||
AZ_Assert(m_attributeWorld, "Out of memory");
|
||||
}
|
||||
|
||||
ProximityInterestRule::Ptr ProximityInterestHandler::CreateRule(PeerId peerId)
|
||||
{
|
||||
ProximityInterestRule* rulePtr = aznew ProximityInterestRule(this, peerId, GetNewRuleNetId());
|
||||
if (m_rm && peerId == m_rm->GetLocalPeerId())
|
||||
{
|
||||
m_rulesReplica->AddRuleRpc(rulePtr->GetNetworkId(), rulePtr->Get());
|
||||
}
|
||||
|
||||
CreateAndInsertIntoSpatialStructure(rulePtr);
|
||||
|
||||
return rulePtr;
|
||||
}
|
||||
|
||||
ProximityInterestAttribute::Ptr ProximityInterestHandler::CreateAttribute(ReplicaId replicaId)
|
||||
{
|
||||
auto newAttribute = aznew ProximityInterestAttribute(this, replicaId);
|
||||
AZ_Assert(newAttribute, "Out of memory");
|
||||
|
||||
CreateAndInsertIntoSpatialStructure(newAttribute);
|
||||
|
||||
return newAttribute;
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::FreeRule(ProximityInterestRule* rule)
|
||||
{
|
||||
//TODO: should be pool-allocated
|
||||
delete rule;
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::DestroyRule(ProximityInterestRule* rule)
|
||||
{
|
||||
if (m_rm && rule->GetPeerId() == m_rm->GetLocalPeerId())
|
||||
{
|
||||
m_rulesReplica->RemoveRuleRpc(rule->GetNetworkId());
|
||||
}
|
||||
|
||||
MarkAttributesDirtyInRule(rule);
|
||||
|
||||
rule->m_bbox = AZ::Aabb::CreateNull();
|
||||
m_removedRules.insert(rule);
|
||||
m_localRules.erase(rule);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::UpdateRule(ProximityInterestRule* rule)
|
||||
{
|
||||
if (m_rm && rule->GetPeerId() == m_rm->GetLocalPeerId())
|
||||
{
|
||||
m_rulesReplica->UpdateRuleRpc(rule->GetNetworkId(), rule->Get());
|
||||
}
|
||||
|
||||
m_dirtyRules.insert(rule);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::FreeAttribute(ProximityInterestAttribute* attrib)
|
||||
{
|
||||
delete attrib;
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::DestroyAttribute(ProximityInterestAttribute* attrib)
|
||||
{
|
||||
RemoveFromSpatialStructure(attrib);
|
||||
|
||||
m_attributes.erase(attrib);
|
||||
m_removedAttributes.insert(attrib);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::RemoveFromSpatialStructure(ProximityInterestAttribute* attribute)
|
||||
{
|
||||
attribute->m_bbox = AZ::Aabb::CreateNull();
|
||||
m_attributeWorld->Remove(attribute->GetNode());
|
||||
attribute->SetNode(nullptr);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::UpdateAttribute(ProximityInterestAttribute* attrib)
|
||||
{
|
||||
auto node = attrib->GetNode();
|
||||
AZ_Assert(node, "Attribute wasn't created correctly");
|
||||
node->m_volume = attrib->Get();
|
||||
m_attributeWorld->Update(node);
|
||||
|
||||
m_dirtyAttributes.insert(attrib);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::OnNewRulesChunk(ProximityInterestChunk* chunk, ReplicaPeer* peer)
|
||||
{
|
||||
if (chunk != m_rulesReplica) // non-local
|
||||
{
|
||||
m_peerChunks.insert(AZStd::make_pair(peer->GetId(), chunk));
|
||||
|
||||
for (auto& rule : m_localRules)
|
||||
{
|
||||
chunk->AddRuleForPeerRpc(rule->GetNetworkId(), rule->GetPeerId(), rule->Get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::OnDeleteRulesChunk(ProximityInterestChunk* chunk, ReplicaPeer* peer)
|
||||
{
|
||||
(void)chunk;
|
||||
m_peerChunks.erase(peer->GetId());
|
||||
}
|
||||
|
||||
RuleNetworkId ProximityInterestHandler::GetNewRuleNetId()
|
||||
{
|
||||
++m_lastRuleNetId;
|
||||
|
||||
if (m_rulesReplica)
|
||||
{
|
||||
return m_rulesReplica->GetReplicaId() | (static_cast<AZ::u64>(m_lastRuleNetId) << 32);
|
||||
}
|
||||
|
||||
return (static_cast<AZ::u64>(m_lastRuleNetId) << 32);
|
||||
}
|
||||
|
||||
ProximityInterestChunk* ProximityInterestHandler::FindRulesChunkByPeerId(PeerId peerId)
|
||||
{
|
||||
auto it = m_peerChunks.find(peerId);
|
||||
if (it == m_peerChunks.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const InterestMatchResult& ProximityInterestHandler::GetLastResult()
|
||||
{
|
||||
return m_resultCache;
|
||||
}
|
||||
|
||||
ProximityInterestHandler::RuleSet& ProximityInterestHandler::GetAffectedRules()
|
||||
{
|
||||
/*
|
||||
* The expectation that lots of attributes will change frequently,
|
||||
* so there is no point in trying to optimize cases
|
||||
* where only a few attributes have changed.
|
||||
*/
|
||||
if (m_dirtyAttributes.empty() && !m_dirtyRules.empty())
|
||||
{
|
||||
return m_dirtyRules;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assuming all rules might have been affected.
|
||||
*
|
||||
* There is an optimization chance here if the number of rules is large, as in 1,000+ rules.
|
||||
* To handle such scale we would need another spatial structure for rules.
|
||||
*/
|
||||
return m_localRules;
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::GetAttributesWithinRule(ProximityInterestRule* rule, SpatialIndex::NodeCollector& nodes)
|
||||
{
|
||||
m_attributeWorld->Query(rule->Get(), nodes);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::ClearDirtyState()
|
||||
{
|
||||
m_dirtyAttributes.clear();
|
||||
m_dirtyRules.clear();
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::CreateAndInsertIntoSpatialStructure(ProximityInterestAttribute* attribute)
|
||||
{
|
||||
m_attributes.insert(attribute);
|
||||
SpatialIndex::Node* node = m_attributeWorld->Insert(attribute->Get(), attribute);
|
||||
attribute->SetNode(node);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::CreateAndInsertIntoSpatialStructure(ProximityInterestRule* rule)
|
||||
{
|
||||
m_localRules.insert(rule);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::UpdateInternal(InterestMatchResult& result)
|
||||
{
|
||||
/*
|
||||
* The goal is to return all dirty attributes that were either dirty because:
|
||||
* 1) they changed which rules have apply to
|
||||
* 2) rules have changed and no longer apply to those attributes
|
||||
* and thus resulted in different peer(s) associated with a given replica.
|
||||
*/
|
||||
|
||||
const RuleSet& rules = GetAffectedRules();
|
||||
|
||||
for (auto& dirtyAttribute : m_dirtyAttributes)
|
||||
{
|
||||
result.insert(dirtyAttribute->GetReplicaId());
|
||||
}
|
||||
|
||||
/*
|
||||
* The exectation is to have a lot more attributes than rules.
|
||||
* The amount of rules should grow linear with amount of peers,
|
||||
* so it should be OK to iterate through all rules each update.
|
||||
*/
|
||||
for (auto& rule : rules)
|
||||
{
|
||||
CheckChangesForRule(rule, result);
|
||||
}
|
||||
|
||||
for (auto& removedRule : m_removedRules)
|
||||
{
|
||||
FreeRule(removedRule);
|
||||
}
|
||||
m_removedRules.clear();
|
||||
|
||||
// mark removed attribute as having no peers
|
||||
for (auto& removedAttribute : m_removedAttributes)
|
||||
{
|
||||
result.insert(removedAttribute->GetReplicaId());
|
||||
FreeAttribute(removedAttribute);
|
||||
}
|
||||
m_removedAttributes.clear();
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::CheckChangesForRule(ProximityInterestRule* rule, InterestMatchResult& result)
|
||||
{
|
||||
SpatialIndex::NodeCollector collector;
|
||||
GetAttributesWithinRule(rule, collector);
|
||||
|
||||
auto peerId = rule->GetPeerId();
|
||||
for (ProximityInterestAttribute* attr : collector.GetNodes())
|
||||
{
|
||||
AZ_Assert(attr, "bad node?");
|
||||
|
||||
auto findIt = result.find(attr->GetReplicaId());
|
||||
if (findIt != result.end())
|
||||
{
|
||||
findIt->second.insert(peerId);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto resultIt = result.insert(attr->GetReplicaId());
|
||||
AZ_Assert(resultIt.second, "Successfully inserted");
|
||||
resultIt.first->second.insert(peerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::MarkAttributesDirtyInRule(ProximityInterestRule* rule)
|
||||
{
|
||||
SpatialIndex::NodeCollector collector;
|
||||
GetAttributesWithinRule(rule, collector);
|
||||
|
||||
for (ProximityInterestAttribute* attr : collector.GetNodes())
|
||||
{
|
||||
AZ_Assert(attr, "bad node?");
|
||||
|
||||
UpdateAttribute(attr);
|
||||
}
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::ProduceChanges(const InterestMatchResult& before, const InterestMatchResult& after)
|
||||
{
|
||||
m_resultCache.clear();
|
||||
|
||||
#if defined(INTERNAL_DEBUG_PROXIMITY)
|
||||
before.PrintMatchResult("before");
|
||||
after.PrintMatchResult("after");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 'after' contains only the stuff that might have changed
|
||||
*/
|
||||
for (auto& possiblyDirty : after)
|
||||
{
|
||||
ReplicaId repId = possiblyDirty.first;
|
||||
const InterestPeerSet& peerSet = possiblyDirty.second;
|
||||
|
||||
auto foundInBefore = before.find(repId);
|
||||
if (foundInBefore != before.end())
|
||||
{
|
||||
if (!HasSamePeers(foundInBefore->second, peerSet))
|
||||
{
|
||||
// was in the last calculation but has a different peer set now
|
||||
m_resultCache.insert(AZStd::make_pair(repId, peerSet));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// since it wasn't present during last calculation
|
||||
m_resultCache.insert(AZStd::make_pair(repId, peerSet));
|
||||
}
|
||||
}
|
||||
|
||||
// Mark attributes (replicas) for removal that have not moved but a rule (clients) no longer sees it
|
||||
for (auto& possiblyDirty : before)
|
||||
{
|
||||
ReplicaId repId = possiblyDirty.first;
|
||||
|
||||
const auto foundInAfter = after.find(repId);
|
||||
/*
|
||||
* If the prior state was a replica A present on peer X: "A{X}", and now A should no longer be present on any peer: "A{}"
|
||||
* then by the rules of InterestHandlers interacting with InterestManager, we should return in @m_resultCache the following:
|
||||
*
|
||||
* A{} - indicating that replica A must be removed all peers.
|
||||
*
|
||||
* On the next pass, the prior state would be: "A{}" and the current state would be "A{}" as well. At that point, we have
|
||||
* already sent the update to remove A from X, so @m_resultCache should no longer mention A at all.
|
||||
*/
|
||||
if (foundInAfter == after.end() && !possiblyDirty.second.empty() /* "not A{}" see the above comment */)
|
||||
{
|
||||
m_resultCache.insert(AZStd::make_pair(repId, InterestPeerSet()));
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(INTERNAL_DEBUG_PROXIMITY)
|
||||
m_resultCache.PrintMatchResult("changes");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool ProximityInterestHandler::HasSamePeers(const InterestPeerSet& one, const InterestPeerSet& another)
|
||||
{
|
||||
if (one.size() != another.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& peerFromOne : one)
|
||||
{
|
||||
if (another.find(peerFromOne) == another.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Safe to assume it's the same sets since all entries are unique in a peer sets
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::Update()
|
||||
{
|
||||
InterestMatchResult newResult;
|
||||
|
||||
UpdateInternal(newResult);
|
||||
ProduceChanges(m_lastResult, newResult);
|
||||
|
||||
m_lastResult = std::move(newResult);
|
||||
ClearDirtyState();
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::OnRulesHandlerRegistered(InterestManager* manager)
|
||||
{
|
||||
AZ_Assert(m_im == nullptr, "Handler is already registered with manager %p (%p)\n", m_im, manager);
|
||||
AZ_Assert(m_rulesReplica == nullptr, "Rules replica is already created\n");
|
||||
AZ_TracePrintf("GridMate", "Proximity interest handler is registered\n");
|
||||
m_im = manager;
|
||||
m_rm = m_im->GetReplicaManager();
|
||||
m_rm->RegisterUserContext(AZ_CRC("ProximityInterestHandler", 0x3a90b3e4), this);
|
||||
|
||||
auto replica = Replica::CreateReplica("ProximityInterestHandlerRules");
|
||||
m_rulesReplica = CreateAndAttachReplicaChunk<ProximityInterestChunk>(replica);
|
||||
m_rm->AddPrimary(replica);
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::OnRulesHandlerUnregistered(InterestManager* manager)
|
||||
{
|
||||
(void)manager;
|
||||
AZ_Assert(m_im == manager, "Handler was not registered with manager %p (%p)\n", manager, m_im);
|
||||
AZ_TracePrintf("GridMate", "Proximity interest handler is unregistered\n");
|
||||
m_rulesReplica = nullptr;
|
||||
m_im = nullptr;
|
||||
m_rm->UnregisterUserContext(AZ_CRC("ProximityInterestHandler", 0x3a90b3e4));
|
||||
m_rm = nullptr;
|
||||
|
||||
for (auto& chunk : m_peerChunks)
|
||||
{
|
||||
chunk.second->m_interestHandler = nullptr;
|
||||
}
|
||||
m_peerChunks.clear();
|
||||
|
||||
ClearDirtyState();
|
||||
DestroyAll();
|
||||
|
||||
m_resultCache.clear();
|
||||
}
|
||||
|
||||
void ProximityInterestHandler::DestroyAll()
|
||||
{
|
||||
for (ProximityInterestRule* rule : m_localRules)
|
||||
{
|
||||
FreeRule(rule);
|
||||
}
|
||||
m_localRules.clear();
|
||||
|
||||
for (ProximityInterestAttribute* attr : m_attributes)
|
||||
{
|
||||
FreeAttribute(attr);
|
||||
}
|
||||
m_attributes.clear();
|
||||
|
||||
for (auto& removedRule : m_removedRules)
|
||||
{
|
||||
FreeRule(removedRule);
|
||||
}
|
||||
m_removedRules.clear();
|
||||
|
||||
for (auto& removedAttribute : m_removedAttributes)
|
||||
{
|
||||
FreeAttribute(removedAttribute);
|
||||
}
|
||||
m_removedAttributes.clear();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
ProximityInterestHandler::~ProximityInterestHandler()
|
||||
{
|
||||
/*
|
||||
* If a handler was registered with a InterestManager, then InterestManager ought to have called OnRulesHandlerUnregistered
|
||||
* but this is a safety pre-caution.
|
||||
*/
|
||||
DestroyAll();
|
||||
}
|
||||
|
||||
SpatialIndex::SpatialIndex()
|
||||
{
|
||||
m_tree.reset(aznew GridMate::BvDynamicTree());
|
||||
}
|
||||
|
||||
void SpatialIndex::Remove(Node* node)
|
||||
{
|
||||
m_tree->Remove(node);
|
||||
}
|
||||
|
||||
void SpatialIndex::Update(Node* node)
|
||||
{
|
||||
m_tree->Update(node);
|
||||
}
|
||||
|
||||
SpatialIndex::Node* SpatialIndex::Insert(const AZ::Aabb& get, ProximityInterestAttribute* attribute)
|
||||
{
|
||||
return m_tree->Insert(get, attribute);
|
||||
}
|
||||
|
||||
void SpatialIndex::Query(const AZ::Aabb& shape, NodeCollector& nodes)
|
||||
{
|
||||
m_tree->collideTV(m_tree->GetRoot(), shape, nodes);
|
||||
}
|
||||
}
|
||||
@ -1,314 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GM_REPLICA_PROXIMITYINTERESTHANDLER_H
|
||||
#define GM_REPLICA_PROXIMITYINTERESTHANDLER_H
|
||||
|
||||
#include <GridMate/Replica/RemoteProcedureCall.h>
|
||||
#include <GridMate/Replica/ReplicaChunk.h>
|
||||
#include <GridMate/Replica/Interest/RulesHandler.h>
|
||||
#include <GridMate/Replica/Interest/BvDynamicTree.h>
|
||||
#include <GridMate/Serialize/UtilityMarshal.h>
|
||||
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace GridMate
|
||||
{
|
||||
class ProximityInterestHandler;
|
||||
class ProximityInterestAttribute;
|
||||
|
||||
/*
|
||||
* Base interest
|
||||
*/
|
||||
class ProximityInterest
|
||||
{
|
||||
friend class ProximityInterestHandler;
|
||||
|
||||
public:
|
||||
const AZ::Aabb& Get() const { return m_bbox; }
|
||||
|
||||
protected:
|
||||
explicit ProximityInterest(ProximityInterestHandler* handler);
|
||||
|
||||
ProximityInterestHandler* m_handler;
|
||||
AZ::Aabb m_bbox;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
* Proximity rule
|
||||
*/
|
||||
class ProximityInterestRule
|
||||
: public InterestRule
|
||||
, public ProximityInterest
|
||||
{
|
||||
friend class ProximityInterestHandler;
|
||||
|
||||
public:
|
||||
using Ptr = AZStd::intrusive_ptr<ProximityInterestRule>;
|
||||
|
||||
GM_CLASS_ALLOCATOR(ProximityInterestRule);
|
||||
|
||||
void Set(const AZ::Aabb& bbox);
|
||||
|
||||
private:
|
||||
|
||||
// Intrusive ptr
|
||||
template<class T>
|
||||
friend struct AZStd::IntrusivePtrCountPolicy;
|
||||
unsigned int m_refCount = 0;
|
||||
AZ_FORCE_INLINE void add_ref() { ++m_refCount; }
|
||||
AZ_FORCE_INLINE void release() { --m_refCount; if (!m_refCount) Destroy(); }
|
||||
AZ_FORCE_INLINE bool IsDeleted() const { return m_refCount == 0; }
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ProximityInterestRule(ProximityInterestHandler* handler, PeerId peerId, RuleNetworkId netId)
|
||||
: InterestRule(peerId, netId)
|
||||
, ProximityInterest(handler)
|
||||
{}
|
||||
|
||||
void Destroy();
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SpatialIndex
|
||||
{
|
||||
public:
|
||||
typedef Internal::DynamicTreeNode Node;
|
||||
|
||||
class NodeCollector
|
||||
{
|
||||
typedef AZStd::vector<ProximityInterestAttribute*> Type;
|
||||
|
||||
public:
|
||||
void Process(const Internal::DynamicTreeNode* node)
|
||||
{
|
||||
m_nodes.push_back(reinterpret_cast<ProximityInterestAttribute*>(node->m_data));
|
||||
}
|
||||
|
||||
const Type& GetNodes() const
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
private:
|
||||
Type m_nodes;
|
||||
};
|
||||
|
||||
SpatialIndex();
|
||||
~SpatialIndex() = default;
|
||||
|
||||
AZ_FORCE_INLINE void Remove(Node* node);
|
||||
AZ_FORCE_INLINE void Update(Node* node);
|
||||
AZ_FORCE_INLINE Node* Insert(const AZ::Aabb& get, ProximityInterestAttribute* attribute);
|
||||
AZ_FORCE_INLINE void Query(const AZ::Aabb& get, NodeCollector& nodes);
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<BvDynamicTree> m_tree;
|
||||
};
|
||||
|
||||
/*
|
||||
* Proximity attribute
|
||||
*/
|
||||
class ProximityInterestAttribute
|
||||
: public InterestAttribute
|
||||
, public ProximityInterest
|
||||
{
|
||||
friend class ProximityInterestHandler;
|
||||
template<class T> friend class InterestPtr;
|
||||
|
||||
public:
|
||||
using Ptr = AZStd::intrusive_ptr<ProximityInterestAttribute>;
|
||||
|
||||
GM_CLASS_ALLOCATOR(ProximityInterestAttribute);
|
||||
|
||||
void Set(const AZ::Aabb& bbox);
|
||||
|
||||
private:
|
||||
|
||||
// Intrusive ptr
|
||||
template<class T>
|
||||
friend struct AZStd::IntrusivePtrCountPolicy;
|
||||
unsigned int m_refCount = 0;
|
||||
AZ_FORCE_INLINE void add_ref() { ++m_refCount; }
|
||||
AZ_FORCE_INLINE void release() { Destroy(); }
|
||||
AZ_FORCE_INLINE bool IsDeleted() const { return m_refCount == 0; }
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ProximityInterestAttribute(ProximityInterestHandler* handler, ReplicaId repId)
|
||||
: InterestAttribute(repId)
|
||||
, ProximityInterest(handler)
|
||||
, m_worldNode(nullptr)
|
||||
{}
|
||||
|
||||
void Destroy();
|
||||
|
||||
void SetNode(SpatialIndex::Node* node) { m_worldNode = node; }
|
||||
SpatialIndex::Node* GetNode() const { return m_worldNode; }
|
||||
SpatialIndex::Node* m_worldNode; ///< non-owning pointer
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ProximityInterestChunk
|
||||
: public ReplicaChunk
|
||||
{
|
||||
public:
|
||||
GM_CLASS_ALLOCATOR(ProximityInterestChunk);
|
||||
|
||||
// ReplicaChunk
|
||||
typedef AZStd::intrusive_ptr<ProximityInterestChunk> Ptr;
|
||||
bool IsReplicaMigratable() override { return false; }
|
||||
bool IsBroadcast() override { return true; }
|
||||
static const char* GetChunkName() { return "ProximityInterestChunk"; }
|
||||
|
||||
ProximityInterestChunk()
|
||||
: AddRuleRpc("AddRule")
|
||||
, RemoveRuleRpc("RemoveRule")
|
||||
, UpdateRuleRpc("UpdateRule")
|
||||
, AddRuleForPeerRpc("AddRuleForPeerRpc")
|
||||
, m_interestHandler(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void OnReplicaActivate(const ReplicaContext& rc) override;
|
||||
void OnReplicaDeactivate(const ReplicaContext& rc) override;
|
||||
|
||||
bool AddRuleFn(RuleNetworkId netId, AZ::Aabb bbox, const RpcContext& ctx);
|
||||
bool RemoveRuleFn(RuleNetworkId netId, const RpcContext&);
|
||||
bool UpdateRuleFn(RuleNetworkId netId, AZ::Aabb bbox, const RpcContext&);
|
||||
bool AddRuleForPeerFn(RuleNetworkId netId, PeerId peerId, AZ::Aabb bbox, const RpcContext&);
|
||||
|
||||
Rpc<RpcArg<RuleNetworkId>, RpcArg<AZ::Aabb>>::BindInterface<ProximityInterestChunk, &ProximityInterestChunk::AddRuleFn> AddRuleRpc;
|
||||
Rpc<RpcArg<RuleNetworkId>>::BindInterface<ProximityInterestChunk, &ProximityInterestChunk::RemoveRuleFn> RemoveRuleRpc;
|
||||
Rpc<RpcArg<RuleNetworkId>, RpcArg<AZ::Aabb>>::BindInterface<ProximityInterestChunk, &ProximityInterestChunk::UpdateRuleFn> UpdateRuleRpc;
|
||||
|
||||
Rpc<RpcArg<RuleNetworkId>, RpcArg<PeerId>, RpcArg<AZ::Aabb>>::BindInterface<ProximityInterestChunk, &ProximityInterestChunk::AddRuleForPeerFn> AddRuleForPeerRpc;
|
||||
|
||||
unordered_map<RuleNetworkId, ProximityInterestRule::Ptr> m_rules;
|
||||
ProximityInterestHandler* m_interestHandler;
|
||||
};
|
||||
|
||||
/*
|
||||
* Rules handler
|
||||
*/
|
||||
class ProximityInterestHandler
|
||||
: public BaseRulesHandler
|
||||
{
|
||||
friend class ProximityInterestRule;
|
||||
friend class ProximityInterestAttribute;
|
||||
friend class ProximityInterestChunk;
|
||||
|
||||
public:
|
||||
|
||||
typedef unordered_set<ProximityInterestAttribute*> AttributeSet;
|
||||
typedef unordered_set<ProximityInterestRule*> RuleSet;
|
||||
|
||||
GM_CLASS_ALLOCATOR(ProximityInterestHandler);
|
||||
|
||||
ProximityInterestHandler();
|
||||
~ProximityInterestHandler();
|
||||
|
||||
/*
|
||||
* Creates new proximity rule and binds it to the peer.
|
||||
* Note: the lifetime of the created rule is tied to the lifetime of this handler.
|
||||
*/
|
||||
ProximityInterestRule::Ptr CreateRule(PeerId peerId);
|
||||
|
||||
/*
|
||||
* Creates new proximity attribute and binds it to the replica.
|
||||
* Note: the lifetime of the created attribute is tied to the lifetime of this handler.
|
||||
*/
|
||||
ProximityInterestAttribute::Ptr CreateAttribute(ReplicaId replicaId);
|
||||
|
||||
// Calculates rules and attributes matches
|
||||
void Update() override;
|
||||
|
||||
// Returns last recalculated results
|
||||
const InterestMatchResult& GetLastResult() override;
|
||||
|
||||
// Returns the manager it's bound to
|
||||
InterestManager* GetManager() override { return m_im; }
|
||||
|
||||
// Rules that this handler is aware of
|
||||
const RuleSet& GetLocalRules() const { return m_localRules; }
|
||||
|
||||
private:
|
||||
|
||||
// BaseRulesHandler
|
||||
void OnRulesHandlerRegistered(InterestManager* manager) override;
|
||||
void OnRulesHandlerUnregistered(InterestManager* manager) override;
|
||||
|
||||
void DestroyRule(ProximityInterestRule* rule);
|
||||
void FreeRule(ProximityInterestRule* rule);
|
||||
void UpdateRule(ProximityInterestRule* rule);
|
||||
|
||||
void DestroyAttribute(ProximityInterestAttribute* attrib);
|
||||
void FreeAttribute(ProximityInterestAttribute* attrib);
|
||||
void UpdateAttribute(ProximityInterestAttribute* attrib);
|
||||
|
||||
void OnNewRulesChunk(ProximityInterestChunk* chunk, ReplicaPeer* peer);
|
||||
void OnDeleteRulesChunk(ProximityInterestChunk* chunk, ReplicaPeer* peer);
|
||||
|
||||
RuleNetworkId GetNewRuleNetId();
|
||||
|
||||
ProximityInterestChunk* FindRulesChunkByPeerId(PeerId peerId);
|
||||
|
||||
void DestroyAll();
|
||||
|
||||
InterestManager* m_im;
|
||||
ReplicaManager* m_rm;
|
||||
|
||||
AZ::u32 m_lastRuleNetId;
|
||||
|
||||
unordered_map<PeerId, ProximityInterestChunk*> m_peerChunks;
|
||||
|
||||
RuleSet m_localRules;
|
||||
RuleSet m_removedRules;
|
||||
RuleSet m_dirtyRules;
|
||||
|
||||
AttributeSet m_attributes;
|
||||
AttributeSet m_removedAttributes;
|
||||
AttributeSet m_dirtyAttributes;
|
||||
|
||||
ProximityInterestChunk* m_rulesReplica;
|
||||
|
||||
// collection of all known attributes
|
||||
AZStd::unique_ptr<SpatialIndex> m_attributeWorld;
|
||||
|
||||
InterestMatchResult m_resultCache;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// internal processing helpers
|
||||
AZ_FORCE_INLINE RuleSet& GetAffectedRules();
|
||||
AZ_FORCE_INLINE void GetAttributesWithinRule(ProximityInterestRule* rule, SpatialIndex::NodeCollector& nodes);
|
||||
AZ_FORCE_INLINE void ClearDirtyState();
|
||||
|
||||
AZ_FORCE_INLINE void CreateAndInsertIntoSpatialStructure(ProximityInterestAttribute* attribute);
|
||||
AZ_FORCE_INLINE void RemoveFromSpatialStructure(ProximityInterestAttribute* attribute);
|
||||
AZ_FORCE_INLINE void CreateAndInsertIntoSpatialStructure(ProximityInterestRule* rule);
|
||||
|
||||
void UpdateInternal(InterestMatchResult& result);
|
||||
void CheckChangesForRule(ProximityInterestRule* rule, InterestMatchResult& result);
|
||||
void MarkAttributesDirtyInRule(ProximityInterestRule* rule);
|
||||
|
||||
static bool HasSamePeers(const InterestPeerSet& one, const InterestPeerSet& another);
|
||||
void ProduceChanges(const InterestMatchResult& before, const InterestMatchResult& after);
|
||||
|
||||
InterestMatchResult m_lastResult;
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
#endif // GM_REPLICA_PROXIMITYINTERESTHANDLER_H
|
||||