From 4ac0c29d9bf09579fe7e53ea99d7bede2700ec1a Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 24 Oct 2016 09:40:34 -0700 Subject: [PATCH 01/79] Adding Image utility to GPU --- libraries/gpu/src/gpu/Image.cpp | 17 ++++++ libraries/gpu/src/gpu/Image.h | 73 ++++++++++++++++++++++++ libraries/model/src/model/TextureMap.cpp | 7 ++- 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 libraries/gpu/src/gpu/Image.cpp create mode 100644 libraries/gpu/src/gpu/Image.h diff --git a/libraries/gpu/src/gpu/Image.cpp b/libraries/gpu/src/gpu/Image.cpp new file mode 100644 index 0000000000..6649fc7876 --- /dev/null +++ b/libraries/gpu/src/gpu/Image.cpp @@ -0,0 +1,17 @@ +#include "TextureUtils.h" + + +int image::Pixel::cpp { 0 }; + +namespace image { +template <> void compress(const PB_RGB32& src, CB_8& dst) { + + for (auto& b : dst.bytes) { + b = 12; + } +} + +template <> void compress(const PB_RGBA32& src, CB_8& dst) { + +} +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h new file mode 100644 index 0000000000..a36990b215 --- /dev/null +++ b/libraries/gpu/src/gpu/Image.h @@ -0,0 +1,73 @@ +/* + Let s try compressing images + +*/ +#include "Forward.h" + + +namespace image { + + class Pixel { + public: + using Byte = uint8_t; + static const Byte BLACK { 0 }; + static const Byte WHITE { 255 }; + + struct RGB32 { + Byte r { BLACK }; + Byte g { BLACK }; + Byte b { BLACK }; + Byte x { WHITE }; + }; + + struct RGBA32 { + Byte r { BLACK }; + Byte g { BLACK }; + Byte b { BLACK }; + Byte a { WHITE }; + }; + + + static int cpp; + }; + + template class PixelBlock { + public: + static const uint32_t WIDTH { 4 }; + static const uint32_t HEIGHT { WIDTH }; + static const uint32_t SIZE { WIDTH * HEIGHT }; + constexpr uint32_t getByteSize() const { return SIZE * sizeof(P); } + + P pixels[SIZE]; + + PixelBlock() {} + + + PixelBlock(const P* srcPixels) { + setPixels(srcPixels); + } + + void setPixels(const P* srcPixels) { + memcpy(pixels, srcPixels, getByteSize()); + } + + }; + + template class CompressedBlock { + public: + uint8_t bytes[Size]; + }; + + template void compress(const PB& srcPixelBlock, CB& dstBlock) { } + + using PB_RGB32 = PixelBlock; + using PB_RGBA32 = PixelBlock; + + using CB_8 = CompressedBlock<8>; + using CB_16 = CompressedBlock<16>; + + template <> void compress(const PB_RGB32& src, CB_8& dst); + template <> void compress(const PB_RGBA32& src, CB_8& dst); + + +} \ No newline at end of file diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 30f176b5a6..a6ae3f675b 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -15,7 +15,7 @@ #include #include "ModelLogging.h" - +#include using namespace model; using namespace gpu; @@ -201,6 +201,11 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); + image::PB_RGB32 pb; + image::CB_8 cb; + + image::compress(pb, cb); + if (generateMips) { ::generateMips(theTexture, image, formatMip); } From 07d1daaa9b3fc8b3a093fd5558d4040c40010549 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 24 Oct 2016 18:35:15 -0700 Subject: [PATCH 02/79] Designing IMage --- libraries/gpu/src/gpu/Image.cpp | 16 +++++++-- libraries/gpu/src/gpu/Image.h | 42 ++++++++++++++++++------ libraries/model/src/model/TextureMap.cpp | 2 +- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/libraries/gpu/src/gpu/Image.cpp b/libraries/gpu/src/gpu/Image.cpp index 6649fc7876..e8d1899f11 100644 --- a/libraries/gpu/src/gpu/Image.cpp +++ b/libraries/gpu/src/gpu/Image.cpp @@ -1,17 +1,29 @@ -#include "TextureUtils.h" +#include "Image.h" int image::Pixel::cpp { 0 }; namespace image { -template <> void compress(const PB_RGB32& src, CB_8& dst) { + + template <> void compress(const PB_RGB32& src, CB_8& dst) { for (auto& b : dst.bytes) { b = 12; } } +template <> void uncompress(const CB_8& src, PB_RGB32& dst) { + for (auto& b : dst.bytes) { + b = 12; + } +} + template <> void compress(const PB_RGBA32& src, CB_8& dst) { } + +template <> void uncompress(const CB_8& src, PB_RGBA32& dst) { + +} + } \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index a36990b215..37f5f2788a 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -10,9 +10,13 @@ namespace image { class Pixel { public: using Byte = uint8_t; - static const Byte BLACK { 0 }; - static const Byte WHITE { 255 }; - + using Byte2 = uint16_t; + using Byte4 = uint32_t; + + static const Byte BLACK8 { 0 }; + static const Byte WHITE8 { 255 }; + + struct RGB32 { Byte r { BLACK }; Byte g { BLACK }; @@ -26,8 +30,14 @@ namespace image { Byte b { BLACK }; Byte a { WHITE }; }; - - + + + struct RGB16_565 { + Byte2 b : 5; + Byte2 g : 6; + Byte2 r : 5; + }; + static int cpp; }; @@ -36,7 +46,7 @@ namespace image { static const uint32_t WIDTH { 4 }; static const uint32_t HEIGHT { WIDTH }; static const uint32_t SIZE { WIDTH * HEIGHT }; - constexpr uint32_t getByteSize() const { return SIZE * sizeof(P); } + uint32_t getByteSize() const { return SIZE * sizeof(P); } P pixels[SIZE]; @@ -50,7 +60,6 @@ namespace image { void setPixels(const P* srcPixels) { memcpy(pixels, srcPixels, getByteSize()); } - }; template class CompressedBlock { @@ -58,7 +67,19 @@ namespace image { uint8_t bytes[Size]; }; - template void compress(const PB& srcPixelBlock, CB& dstBlock) { } + class BC { + public: + struct BC1 { + Pixel::RGB16_565 color_0; + Pixel::RGB16_565 color_1; + Pixel::Byte4 table; + }; + }; + + + template void compress(const PB& srcBlock, CB& dstBlock) { } + template void uncompress(const CB& srcBlock, PB& dstBlock) { } + using PB_RGB32 = PixelBlock; using PB_RGBA32 = PixelBlock; @@ -68,6 +89,7 @@ namespace image { template <> void compress(const PB_RGB32& src, CB_8& dst); template <> void compress(const PB_RGBA32& src, CB_8& dst); - - + + template <> void uncompress(const CB_8& src, PB_RGB32& dst); + template <> void uncompress(const CB_8& src, PB_RGBA32& dst); } \ No newline at end of file diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index a6ae3f675b..e80a8b2502 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -15,7 +15,7 @@ #include #include "ModelLogging.h" -#include +#include using namespace model; using namespace gpu; From ce68be2a59c823eda49e993305368a5c3ad73db7 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 26 Oct 2016 23:09:41 -0700 Subject: [PATCH 03/79] a few step further --- libraries/gpu/src/gpu/Image.cpp | 31 +++++-- libraries/gpu/src/gpu/Image.h | 110 ++++++++++++++++------- libraries/model/src/model/TextureMap.cpp | 2 +- 3 files changed, 103 insertions(+), 40 deletions(-) diff --git a/libraries/gpu/src/gpu/Image.cpp b/libraries/gpu/src/gpu/Image.cpp index e8d1899f11..b3fcbe11eb 100644 --- a/libraries/gpu/src/gpu/Image.cpp +++ b/libraries/gpu/src/gpu/Image.cpp @@ -1,28 +1,45 @@ #include "Image.h" -int image::Pixel::cpp { 0 }; +int image::BC::cpp { 0 }; namespace image { - template <> void compress(const PB_RGB32& src, CB_8& dst) { + namespace pixel { + template <> const RGB16_565 mix(const RGB16_565 p0, const RGB16_565 p1, const Byte alpha) { + return RGB16_565( + mix5_4(p0.r, p1.r, alpha), + mix6_4(p0.g, p1.g, alpha), + mix5_4(p0.b, p1.b, alpha)); + } + } + +template <> void compress(const PB_RGB32& src, CB_BC1& dst) { for (auto& b : dst.bytes) { b = 12; } } -template <> void uncompress(const CB_8& src, PB_RGB32& dst) { - for (auto& b : dst.bytes) { - b = 12; +template <> void uncompress(const CB_BC1& src, PB_RGB32& dst) { + auto bc1 = src.bc; + auto c0 = bc1.color0; + auto c1 = bc1.color1; + + for (auto& p : dst.pixels) { + auto r = pixel::mix( + c0, + c1, + (pixel::Byte)bc1.table); + ///p.val = } } -template <> void compress(const PB_RGBA32& src, CB_8& dst) { +template <> void compress(const PB_RGBA32& src, CB_BC4& dst) { } -template <> void uncompress(const CB_8& src, PB_RGBA32& dst) { +template <> void uncompress(const CB_BC4& src, PB_RGBA32& dst) { } diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index 37f5f2788a..ff106f65b6 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -7,8 +7,8 @@ namespace image { - class Pixel { - public: + namespace pixel { + using Byte = uint8_t; using Byte2 = uint16_t; using Byte4 = uint32_t; @@ -16,19 +16,22 @@ namespace image { static const Byte BLACK8 { 0 }; static const Byte WHITE8 { 255 }; - + template int bitVal() { return 1 << N; } + template int bitProduct() { return bitVal() * bitVal(); } + template T mix(const T x, const T y, const A a) { return T(((bitVal() - a) * x + a * y) / bitProduct()); } + struct RGB32 { - Byte r { BLACK }; - Byte g { BLACK }; - Byte b { BLACK }; - Byte x { WHITE }; + Byte r { BLACK8 }; + Byte g { BLACK8 }; + Byte b { BLACK8 }; + Byte x { WHITE8 }; }; struct RGBA32 { - Byte r { BLACK }; - Byte g { BLACK }; - Byte b { BLACK }; - Byte a { WHITE }; + Byte r { BLACK8 }; + Byte g { BLACK8 }; + Byte b { BLACK8 }; + Byte a { WHITE8 }; }; @@ -36,17 +39,48 @@ namespace image { Byte2 b : 5; Byte2 g : 6; Byte2 r : 5; + + RGB16_565() : b(BLACK8), g(BLACK8), r(BLACK8) {} + RGB16_565(Byte pR, Byte pG, Byte pB) : b(pB), g(pG), r(pR) {} }; + + + Byte mix5_4(const Byte x, const Byte y, const Byte a) { return mix<5, 4>(x, y, a); } + Byte mix6_4(const Byte x, const Byte y, const Byte a) { return mix<6, 4>(x, y, a); } + + + template const P mix(const P p0, const P p1, const S alpha) { return p0; } + + template <> const RGB16_565 mix(const RGB16_565 p0, const RGB16_565 p1, const Byte alpha); + - static int cpp; }; + template class Pixel { + public: + using Format = F; + using Storage = S; + + union { + Format val; + Storage raw; + }; + + Pixel() {}; + Pixel(Format v) : val(v) {} + Pixel(Storage s) : raw(s) {} + }; + + using PixRGB565 = Pixel; + using PixRGB32 = Pixel; + using PixRGBA32 = Pixel; + template class PixelBlock { public: static const uint32_t WIDTH { 4 }; static const uint32_t HEIGHT { WIDTH }; static const uint32_t SIZE { WIDTH * HEIGHT }; - uint32_t getByteSize() const { return SIZE * sizeof(P); } + uint32_t getSize() const { return SIZE * sizeof(P); } P pixels[SIZE]; @@ -58,38 +92,50 @@ namespace image { } void setPixels(const P* srcPixels) { - memcpy(pixels, srcPixels, getByteSize()); + memcpy(pixels, srcPixels, getSize()); } }; - template class CompressedBlock { - public: - uint8_t bytes[Size]; - }; - class BC { public: + static int cpp; + struct BC1 { - Pixel::RGB16_565 color_0; - Pixel::RGB16_565 color_1; - Pixel::Byte4 table; + PixRGB565 color0; + PixRGB565 color1; + pixel::Byte4 table; + }; + struct BC4 { + PixRGB565 color0; + PixRGB565 color1; + pixel::Byte4 table; }; }; - - + + template class CompressedBlock { + public: + static const uint32_t SIZE { sizeof(T) }; + union { + pixel::Byte bytes[SIZE]; + T bc; + }; + + CompressedBlock() {} + }; + template void compress(const PB& srcBlock, CB& dstBlock) { } template void uncompress(const CB& srcBlock, PB& dstBlock) { } - using PB_RGB32 = PixelBlock; - using PB_RGBA32 = PixelBlock; + using PB_RGB32 = PixelBlock; + using PB_RGBA32 = PixelBlock; - using CB_8 = CompressedBlock<8>; - using CB_16 = CompressedBlock<16>; + using CB_BC1 = CompressedBlock; + using CB_BC4 = CompressedBlock; - template <> void compress(const PB_RGB32& src, CB_8& dst); - template <> void compress(const PB_RGBA32& src, CB_8& dst); + template <> void compress(const PB_RGB32& src, CB_BC1& dst); + template <> void compress(const PB_RGBA32& src, CB_BC4& dst); - template <> void uncompress(const CB_8& src, PB_RGB32& dst); - template <> void uncompress(const CB_8& src, PB_RGBA32& dst); + template <> void uncompress(const CB_BC1& src, PB_RGB32& dst); + template <> void uncompress(const CB_BC4& src, PB_RGBA32& dst); } \ No newline at end of file diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index e80a8b2502..b0efbf2f30 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -202,7 +202,7 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); image::PB_RGB32 pb; - image::CB_8 cb; + image::CB_BC1 cb; image::compress(pb, cb); From b38f69dc7882fd4b8e464bd22d04f58a20d1fdc2 Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 29 Oct 2016 22:43:42 -0700 Subject: [PATCH 04/79] stage 0 of fooling around with image compression.... --- libraries/gpu/src/gpu/Image.cpp | 9 +++-- libraries/gpu/src/gpu/Image.h | 49 ++++++++++++++---------- libraries/model/src/model/TextureMap.cpp | 22 +++++++++-- 3 files changed, 53 insertions(+), 27 deletions(-) diff --git a/libraries/gpu/src/gpu/Image.cpp b/libraries/gpu/src/gpu/Image.cpp index b3fcbe11eb..eddc1d60d7 100644 --- a/libraries/gpu/src/gpu/Image.cpp +++ b/libraries/gpu/src/gpu/Image.cpp @@ -23,15 +23,16 @@ template <> void compress(const PB_RGB32& src, CB_BC1& dst) { template <> void uncompress(const CB_BC1& src, PB_RGB32& dst) { auto bc1 = src.bc; - auto c0 = bc1.color0; - auto c1 = bc1.color1; - for (auto& p : dst.pixels) { + auto c0 = bc1.color0.val; + auto c1 = bc1.color1.val; + + for (int i = 0; i < PB_RGB32::SIZE; ++i) { + //dst.pixels[i] = ; auto r = pixel::mix( c0, c1, (pixel::Byte)bc1.table); - ///p.val = } } diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index ff106f65b6..c9969b8e15 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -7,19 +7,25 @@ namespace image { + // Storage types + using Byte = uint8_t; + using Byte2 = uint16_t; + using Byte4 = uint32_t; + + static const Byte BLACK8 { 0 }; + static const Byte WHITE8 { 255 }; + + template int bitVal() { return 1 << N; } + template int bitProduct() { return bitVal() * bitVal(); } + template T mix(const T x, const T y, const A a) { return T(((bitVal() - a) * x + a * y) / bitProduct()); } + + Byte mix5_4(const Byte x, const Byte y, const Byte a) { return mix<5, 4>(x, y, a); } + Byte mix6_4(const Byte x, const Byte y, const Byte a) { return mix<6, 4>(x, y, a); } + + namespace pixel { - using Byte = uint8_t; - using Byte2 = uint16_t; - using Byte4 = uint32_t; - - static const Byte BLACK8 { 0 }; - static const Byte WHITE8 { 255 }; - - template int bitVal() { return 1 << N; } - template int bitProduct() { return bitVal() * bitVal(); } - template T mix(const T x, const T y, const A a) { return T(((bitVal() - a) * x + a * y) / bitProduct()); } - + struct RGB32 { Byte r { BLACK8 }; Byte g { BLACK8 }; @@ -43,16 +49,9 @@ namespace image { RGB16_565() : b(BLACK8), g(BLACK8), r(BLACK8) {} RGB16_565(Byte pR, Byte pG, Byte pB) : b(pB), g(pG), r(pR) {} }; - - - Byte mix5_4(const Byte x, const Byte y, const Byte a) { return mix<5, 4>(x, y, a); } - Byte mix6_4(const Byte x, const Byte y, const Byte a) { return mix<6, 4>(x, y, a); } - - + template const P mix(const P p0, const P p1, const S alpha) { return p0; } - template <> const RGB16_565 mix(const RGB16_565 p0, const RGB16_565 p1, const Byte alpha); - }; @@ -62,8 +61,8 @@ namespace image { using Storage = S; union { - Format val; Storage raw; + Format val{ Format() }; // Format last to be initialized by Format's default constructor }; Pixel() {}; @@ -75,11 +74,16 @@ namespace image { using PixRGB32 = Pixel; using PixRGBA32 = Pixel; + template class PixelBlock { public: + using Format = typename P::Format; + using Storage = typename P::Storage; + static const uint32_t WIDTH { 4 }; static const uint32_t HEIGHT { WIDTH }; static const uint32_t SIZE { WIDTH * HEIGHT }; + uint32_t getSize() const { return SIZE * sizeof(P); } P pixels[SIZE]; @@ -94,6 +98,8 @@ namespace image { void setPixels(const P* srcPixels) { memcpy(pixels, srcPixels, getSize()); } + + const Storage* getStorage() const { return static_cast (&pixels->raw); } }; class BC { @@ -104,6 +110,9 @@ namespace image { PixRGB565 color0; PixRGB565 color1; pixel::Byte4 table; + + + Byte }; struct BC4 { PixRGB565 color0; diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index bd1a4baf48..1cbff8bd21 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -248,10 +248,26 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); - image::PB_RGB32 pb; - image::CB_BC1 cb; + image::PixRGB32 pix0; - image::compress(pb, cb); + image::PixRGBA32 pix1; + + image::PixRGB565 pix3; + + image::PB_RGB32 pb0; + image::CB_BC1 cb; + image::PB_RGB32 pb1; + + auto pix0_s = sizeof(pix0); + auto pix1_s = sizeof(pix1); + auto pix3_s = sizeof(pix3); + + auto pb0_s = sizeof(pb0); + auto cb_s = sizeof(cb); + + auto cb_bytes = pb0.getStorage(); + image::compress(pb0, cb); + image::uncompress(cb, pb1); if (generateMips) { ::generateMips(theTexture, image, formatMip); From 41109553ebb5c1f315a7f794a1190ba031fe65ed Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 4 Nov 2016 22:56:18 -0700 Subject: [PATCH 05/79] Saving state before merge up --- libraries/gpu/src/gpu/Image.cpp | 2 +- libraries/gpu/src/gpu/Image.h | 167 ++++++++++++++++------- libraries/model/src/model/TextureMap.cpp | 3 + 3 files changed, 118 insertions(+), 54 deletions(-) diff --git a/libraries/gpu/src/gpu/Image.cpp b/libraries/gpu/src/gpu/Image.cpp index eddc1d60d7..5de1008d8f 100644 --- a/libraries/gpu/src/gpu/Image.cpp +++ b/libraries/gpu/src/gpu/Image.cpp @@ -32,7 +32,7 @@ template <> void uncompress(const CB_BC1& src, PB_RGB32& dst) { auto r = pixel::mix( c0, c1, - (pixel::Byte)bc1.table); + (Byte)bc1.table); } } diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index c9969b8e15..f456240503 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -2,6 +2,8 @@ Let s try compressing images */ + +#include #include "Forward.h" @@ -11,6 +13,20 @@ namespace image { using Byte = uint8_t; using Byte2 = uint16_t; using Byte4 = uint32_t; + using Byte8 = uint64_t; + + // Storage type selector based on size (sizeof of a type) + template + struct storage { typedef T1 type; }; + + template + struct storage<2, T1, T2, T4, T8> { typedef T2 type; }; + + template + struct storage<4, T1, T2, T4, T8> { typedef T4 type; }; + + template + struct storage<8, T1, T2, T4, T8> { typedef T8 type; }; static const Byte BLACK8 { 0 }; static const Byte WHITE8 { 255 }; @@ -25,7 +41,6 @@ namespace image { namespace pixel { - struct RGB32 { Byte r { BLACK8 }; Byte g { BLACK8 }; @@ -40,7 +55,6 @@ namespace image { Byte a { WHITE8 }; }; - struct RGB16_565 { Byte2 b : 5; Byte2 g : 6; @@ -49,58 +63,66 @@ namespace image { RGB16_565() : b(BLACK8), g(BLACK8), r(BLACK8) {} RGB16_565(Byte pR, Byte pG, Byte pB) : b(pB), g(pG), r(pR) {} }; + + struct R8 { + Byte r { BLACK8 }; + }; + template const P mix(const P p0, const P p1, const S alpha) { return p0; } template <> const RGB16_565 mix(const RGB16_565 p0, const RGB16_565 p1, const Byte alpha); - }; - - template class Pixel { - public: - using Format = F; - using Storage = S; - - union { - Storage raw; - Format val{ Format() }; // Format last to be initialized by Format's default constructor + template ::type > class Pixel { + public: + using Format = F; + using Storage = S; + + union { + Storage raw; + Format val{ Format() }; // Format last to be initialized by Format's default constructor + }; + + Pixel() {}; + Pixel(Format v) : val(v) {} + Pixel(Storage s) : raw(s) {} }; + - Pixel() {}; - Pixel(Format v) : val(v) {} - Pixel(Storage s) : raw(s) {} + template class PixelBlock { + public: + using Format = typename P::Format; + using Storage = typename P::Storage; + + static const uint32_t WIDTH { 4 }; + static const uint32_t HEIGHT { WIDTH }; + static const uint32_t SIZE { WIDTH * HEIGHT }; + + uint32_t getSize() const { return SIZE * sizeof(P); } + + P pixels[SIZE]; + + PixelBlock() {} + + + PixelBlock(const P* srcPixels) { + setPixels(srcPixels); + } + + void setPixels(const P* srcPixels) { + memcpy(pixels, srcPixels, getSize()); + } + + const Storage* getStorage() const { return static_cast (&pixels->raw); } + }; }; - using PixRGB565 = Pixel; - using PixRGB32 = Pixel; - using PixRGBA32 = Pixel; - - - template class PixelBlock { - public: - using Format = typename P::Format; - using Storage = typename P::Storage; - static const uint32_t WIDTH { 4 }; - static const uint32_t HEIGHT { WIDTH }; - static const uint32_t SIZE { WIDTH * HEIGHT }; - - uint32_t getSize() const { return SIZE * sizeof(P); } - - P pixels[SIZE]; - - PixelBlock() {} - - - PixelBlock(const P* srcPixels) { - setPixels(srcPixels); - } - - void setPixels(const P* srcPixels) { - memcpy(pixels, srcPixels, getSize()); - } - - const Storage* getStorage() const { return static_cast (&pixels->raw); } - }; + + using PixRGB565 = pixel::Pixel; + using PixRGB32 = pixel::Pixel; + using PixRGBA32 = pixel::Pixel; + using PixR8 = pixel::Pixel; + class BC { public: @@ -109,15 +131,13 @@ namespace image { struct BC1 { PixRGB565 color0; PixRGB565 color1; - pixel::Byte4 table; - - - Byte + Byte4 table; }; + struct BC4 { PixRGB565 color0; PixRGB565 color1; - pixel::Byte4 table; + Byte4 table; }; }; @@ -125,19 +145,20 @@ namespace image { public: static const uint32_t SIZE { sizeof(T) }; union { - pixel::Byte bytes[SIZE]; + Byte bytes[SIZE]; T bc; }; CompressedBlock() {} }; + template void compress(const PB& srcBlock, CB& dstBlock) { } template void uncompress(const CB& srcBlock, PB& dstBlock) { } - using PB_RGB32 = PixelBlock; - using PB_RGBA32 = PixelBlock; + using PB_RGB32 = pixel::PixelBlock; + using PB_RGBA32 = pixel::PixelBlock; using CB_BC1 = CompressedBlock; using CB_BC4 = CompressedBlock; @@ -147,4 +168,44 @@ namespace image { template <> void uncompress(const CB_BC1& src, PB_RGB32& dst); template <> void uncompress(const CB_BC4& src, PB_RGBA32& dst); + + + template + class PixelBlockArray { + public: + using Pixel = P; + using Block = pixel::PixelBlock; + + using Blocks = std::vector; + + }; + + class Grid { + public: + using Coord = uint16_t; + using Coord2 = glm::u16vec2; + using Size = uint32_t; + + Coord2 _block { 1, 1 }; + Coord2 _surface { 1, 1 }; + + Coord width() const { return _surface.x; } + Coord height() const { return _surface.y; } + Size size() const { return width() * height(); } + + Coord blockWidth() const { return _block.x; } + Coord blockHeight() const { return _block.y; } + Size blockSize() const { return blockWidth() * blockHeight(); } + + Coord pixelWidth() const { return _surface.x * _block.x; } + Coordisd pixelHeight() const { return _surface.y * _block.y; } + Size pixelSize() const { return pixelWidth() * pixelHeight(); } + + Coord2 pixelToBlock(const Coord2& coord) const { + auto blockX = coord.x / blockWidth(); + auto blockY = coord.y / blockHeight(); + return Coord2(blockX, blockY); + } + + }; } \ No newline at end of file diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 1cbff8bd21..1b51d16883 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -252,6 +252,8 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag image::PixRGBA32 pix1; + image::PixR8 pix2; + image::PixRGB565 pix3; image::PB_RGB32 pb0; @@ -260,6 +262,7 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag auto pix0_s = sizeof(pix0); auto pix1_s = sizeof(pix1); + auto pix2_s = sizeof(pix2); auto pix3_s = sizeof(pix3); auto pb0_s = sizeof(pb0); From 1c61664ca01c3d8d295eb8dc4dc34eaa15a53901 Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 13 Nov 2016 23:20:39 -0800 Subject: [PATCH 06/79] Still refining th edesign of th eiMage classes --- libraries/gpu/src/gpu/Image.h | 106 +++++++++++++++++------ libraries/model/src/model/TextureMap.cpp | 3 + 2 files changed, 82 insertions(+), 27 deletions(-) diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index f456240503..bda16910c4 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -55,6 +55,12 @@ namespace image { Byte a { WHITE8 }; }; + struct R10G10B12 { + Byte4 r : 10; + Byte4 g : 10; + Byte4 b : 12; + }; + struct RGB16_565 { Byte2 b : 5; Byte2 g : 6; @@ -88,18 +94,15 @@ namespace image { }; - template class PixelBlock { + template class PixelBlock { public: using Format = typename P::Format; using Storage = typename P::Storage; - static const uint32_t WIDTH { 4 }; - static const uint32_t HEIGHT { WIDTH }; - static const uint32_t SIZE { WIDTH * HEIGHT }; + constexpr uint16_t getLength() const { return length; } + uint32_t getSize() const { return length * sizeof(P); } - uint32_t getSize() const { return SIZE * sizeof(P); } - - P pixels[SIZE]; + P pixels[length]; PixelBlock() {} @@ -114,6 +117,23 @@ namespace image { const Storage* getStorage() const { return static_cast (&pixels->raw); } }; + + template class Tile { + public: + using Format = typename P::Format; + using Storage = typename P::Storage; + using Block = typename PixelBlock; + + constexpr uint16_t getWidth() const { return tileW; } + constexpr uint16_t getHeight() const { return tileH; } + + Block _block; + + Tile() {} + Tile(const P* srcPixels) : _block(srcPixels) {} + + + }; }; @@ -121,6 +141,7 @@ namespace image { using PixRGB565 = pixel::Pixel; using PixRGB32 = pixel::Pixel; using PixRGBA32 = pixel::Pixel; + using PixR10G10B12 = pixel::Pixel; using PixR8 = pixel::Pixel; @@ -157,8 +178,8 @@ namespace image { template void uncompress(const CB& srcBlock, PB& dstBlock) { } - using PB_RGB32 = pixel::PixelBlock; - using PB_RGBA32 = pixel::PixelBlock; + using PB_RGB32 = pixel::PixelBlock; + using PB_RGBA32 = pixel::PixelBlock; using CB_BC1 = CompressedBlock; using CB_BC4 = CompressedBlock; @@ -170,14 +191,14 @@ namespace image { template <> void uncompress(const CB_BC4& src, PB_RGBA32& dst); - template + template class PixelBlockArray { public: - using Pixel = P; - using Block = pixel::PixelBlock; + using Block = B; using Blocks = std::vector; + Blocks _blocks; }; class Grid { @@ -186,26 +207,57 @@ namespace image { using Coord2 = glm::u16vec2; using Size = uint32_t; - Coord2 _block { 1, 1 }; + static const Coord2 TILE_PIXEL; + static const Coord2 TILE_QUAD; + static const Coord2 TILE_DEFAULT; + + Grid(const Coord2& surface, const Coord2& tile = TILE_DEFAULT) : _surface(surface), _tile(tile) {} + Grid(Coord width, Coord height, const Coord2& tile = TILE_DEFAULT) : _surface(width, height), _tile(tile) {} + Coord2 _surface { 1, 1 }; + Coord2 _tile { TILE_DEFAULT }; Coord width() const { return _surface.x; } Coord height() const { return _surface.y; } - Size size() const { return width() * height(); } - - Coord blockWidth() const { return _block.x; } - Coord blockHeight() const { return _block.y; } - Size blockSize() const { return blockWidth() * blockHeight(); } - - Coord pixelWidth() const { return _surface.x * _block.x; } - Coordisd pixelHeight() const { return _surface.y * _block.y; } - Size pixelSize() const { return pixelWidth() * pixelHeight(); } - - Coord2 pixelToBlock(const Coord2& coord) const { - auto blockX = coord.x / blockWidth(); - auto blockY = coord.y / blockHeight(); - return Coord2(blockX, blockY); + const Coord2& size() const { return _surface; } + + Coord tileWidth() const { return evalNumTiles(_surface.x, _tile.x); } + Coord tileHeight() const { return evalNumTiles(_surface.y, _tile.y); } + Coord2 tileSize() const { return Coord2(tileWidth(), tileHeight()); } + + + Coord2 toTile(const Coord2& pixel) const { return pixel / _tile; } + Coord2 toTileSubpix(const Coord2& pixel) const { return pixel % _tile; } + Coord2 toTile(const Coord2& pixel, Coord2& subpix) const { + subpix = toTileSubpix(pixel); + return toTile(pixel); } + Coord2 toPixel(const Coord2& tile) const { return tile * _tile; } + Coord2 toPixel(const Coord2& tile, const Coord2& subpix) const { return tile * _tile + subpix; } + + + static Coord evalNumTiles(Coord pixelLength, Coord tileLength) { + auto tilePos = pixelLength / tileLength; + if (tilePos * tileLength < pixelLength) { + tilePos++; + } + return tilePos; + } + }; + + template + class Pixmap { + public: + using Tile = T; + + Grid _grid; + PixelBlockArray _blocks; + + void resize(const Grid::Coord2& widthHeight) { + _grid = Grid(widthHeight, Coord2(Tile::getWidth(), Tile::getHeight())); + + } + }; } \ No newline at end of file diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 1b51d16883..83a9e008cc 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -272,6 +272,9 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag image::compress(pb0, cb); image::uncompress(cb, pb1); + image::Grid grid; + grid. + if (generateMips) { ::generateMips(theTexture, image, formatMip); } From f159d4c91dae39f9f05c9009e10a6dd44da2abec Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Tue, 31 Jan 2017 20:45:35 +0000 Subject: [PATCH 07/79] create nameTag.js script Running the script creates a text entity that will hover over the users head showing their display name. --- scripts/system/nameTag.js | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 scripts/system/nameTag.js diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js new file mode 100644 index 0000000000..adaab83297 --- /dev/null +++ b/scripts/system/nameTag.js @@ -0,0 +1,98 @@ +"use strict"; + +/*jslint vars: true, plusplus: true*/ +/*global Entities, Script, Quat, Vec3, MyAvatar, print*/ +// nameTag.js +// +// Created by Triplelexx on 17/01/31 +// Copyright 2017 High Fidelity, Inc. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +const NAMETAG_DIMENSIONS = { + x: 1.0, + y: 0.2, + z: 1.0 +} + +const CLIENTONLY = false; +const NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; +const ENTITY_CHECK_INTERVAL = 5000; // ms = 5 seconds +const STARTUP_DELAY = 2000; // ms = 2 second +const OLD_AGE = 3500; // we recreate the entity if older than this time in seconds +const TTL = 2; // time to live in seconds if script is not running +const HEIGHT_ABOVE_HEAD = 0.2; +const HEAD_OFFSET = -0.025; + +var nametagEntityID = NULL_UUID; +var lastCheckForEntity = 0; + +// create the name tag entity after a brief delay +Script.setTimeout(function() { + addNameTag(); +}, STARTUP_DELAY); + +function addNameTag() { + var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); + nametagPosition.y += HEIGHT_ABOVE_HEAD; + var modelNameTagProperties = { + type: 'Text', + text: MyAvatar.displayName, + parentID: MyAvatar.sessionUUID, + dimensions: NAMETAG_DIMENSIONS, + position: nametagPosition + } + nametagEntityID = Entities.addEntity(modelNameTagProperties, CLIENTONLY); +} + +function deleteNameTag() { + if(nametagEntityID !== NULL_UUID) { + Entities.deleteEntity(nametagEntityID); + nametagEntityID = NULL_UUID; + } +} + +// cleanup on ending +Script.scriptEnding.connect(cleanup); +function cleanup() { + deleteNameTag(); +} + +Script.update.connect(update); +function update() { + // bail if no entity + if(nametagEntityID == NULL_UUID) { + return; + } + + if(Date.now() - lastCheckForEntity > ENTITY_CHECK_INTERVAL) { + checkForEntity(); + lastCheckForEntity = Date.now(); + } +} + +function checkForEntity() { + var nametagProps = Entities.getEntityProperties(nametagEntityID); + + // it is possible for the age to not be a valid number, we check for this and bail accordingly + if(nametagProps.age < 1) { + return; + } + + // it's too old make a new one, otherwise update + if(nametagProps.age > OLD_AGE || nametagProps.age == undefined) { + deleteNameTag(); + addNameTag(); + } else { + var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); + nametagPosition.y += HEIGHT_ABOVE_HEAD; + Entities.editEntity(nametagEntityID, { + position: nametagPosition, + // lifetime is in seconds we add TTL on top of the next poll time + lifetime: Math.round(nametagProps.age) + (ENTITY_CHECK_INTERVAL / 1000) + TTL, + text: MyAvatar.displayName + }); + } +} From be68f84100ed073266722f22b7df556f07060504 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Tue, 31 Jan 2017 22:14:39 +0000 Subject: [PATCH 08/79] update nameTag.js comments --- scripts/system/nameTag.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index adaab83297..cd8df2c477 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -7,6 +7,7 @@ // Created by Triplelexx on 17/01/31 // Copyright 2017 High Fidelity, Inc. // +// Running the script creates a text entity that will hover over the user's head showing their display name. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -38,6 +39,7 @@ function addNameTag() { var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); nametagPosition.y += HEIGHT_ABOVE_HEAD; var modelNameTagProperties = { + name: MyAvatar.displayName + ' Name Tag', type: 'Text', text: MyAvatar.displayName, parentID: MyAvatar.sessionUUID, @@ -62,7 +64,7 @@ function cleanup() { Script.update.connect(update); function update() { - // bail if no entity + // if no entity we return if(nametagEntityID == NULL_UUID) { return; } @@ -76,12 +78,12 @@ function update() { function checkForEntity() { var nametagProps = Entities.getEntityProperties(nametagEntityID); - // it is possible for the age to not be a valid number, we check for this and bail accordingly + // it is possible for the age to not be a valid number, we check for this and return accordingly if(nametagProps.age < 1) { return; } - // it's too old make a new one, otherwise update + // it's too old or we receive undefined make a new one, otherwise update if(nametagProps.age > OLD_AGE || nametagProps.age == undefined) { deleteNameTag(); addNameTag(); From b5d2926605f57b78137a12f9ca7493b3a8448290 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Wed, 1 Feb 2017 12:49:41 +0000 Subject: [PATCH 09/79] make text entity smaller and allow dynamic resizing based on name length --- scripts/system/nameTag.js | 74 ++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index cd8df2c477..ceb7583a2e 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -12,12 +12,6 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -const NAMETAG_DIMENSIONS = { - x: 1.0, - y: 0.2, - z: 1.0 -} - const CLIENTONLY = false; const NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; const ENTITY_CHECK_INTERVAL = 5000; // ms = 5 seconds @@ -26,8 +20,11 @@ const OLD_AGE = 3500; // we recreate the entity if older than this time in secon const TTL = 2; // time to live in seconds if script is not running const HEIGHT_ABOVE_HEAD = 0.2; const HEAD_OFFSET = -0.025; +const SIZE_Y = 0.075; +const LETTER_OFFSET = 0.0225; +const LINE_HEIGHT = 0.05; -var nametagEntityID = NULL_UUID; +var nameTagEntityID = NULL_UUID; var lastCheckForEntity = 0; // create the name tag entity after a brief delay @@ -36,26 +33,53 @@ Script.setTimeout(function() { }, STARTUP_DELAY); function addNameTag() { - var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); - nametagPosition.y += HEIGHT_ABOVE_HEAD; + var nameTagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); + nameTagPosition.y += HEIGHT_ABOVE_HEAD; var modelNameTagProperties = { name: MyAvatar.displayName + ' Name Tag', type: 'Text', text: MyAvatar.displayName, + lineHeight: LINE_HEIGHT, parentID: MyAvatar.sessionUUID, - dimensions: NAMETAG_DIMENSIONS, - position: nametagPosition + dimensions: dimensionsFromName(), + position: nameTagPosition } - nametagEntityID = Entities.addEntity(modelNameTagProperties, CLIENTONLY); + nameTagEntityID = Entities.addEntity(modelNameTagProperties, CLIENTONLY); } +function updateNameTag() { + var nameTagProps = Entities.getEntityProperties(nameTagEntityID); + var nameTagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); + nameTagPosition.y += HEIGHT_ABOVE_HEAD; + + Entities.editEntity(nameTagEntityID, { + position: nameTagPosition, + dimensions: dimensionsFromName(), + // lifetime is in seconds we add TTL on top of the next poll time + lifetime: Math.round(nameTagProps.age) + (ENTITY_CHECK_INTERVAL / 1000) + TTL, + text: MyAvatar.displayName + }); +}; + function deleteNameTag() { - if(nametagEntityID !== NULL_UUID) { - Entities.deleteEntity(nametagEntityID); - nametagEntityID = NULL_UUID; + if(nameTagEntityID !== NULL_UUID) { + Entities.deleteEntity(nameTagEntityID); + nameTagEntityID = NULL_UUID; } } +function dimensionsFromName() { + var nameTagDimensions = { + x: 0.0, + y: SIZE_Y, + z: 0.0 + } + for(var letter in MyAvatar.displayName) { + nameTagDimensions.x += LETTER_OFFSET; + } + return nameTagDimensions; +}; + // cleanup on ending Script.scriptEnding.connect(cleanup); function cleanup() { @@ -65,7 +89,7 @@ function cleanup() { Script.update.connect(update); function update() { // if no entity we return - if(nametagEntityID == NULL_UUID) { + if(nameTagEntityID == NULL_UUID) { return; } @@ -76,25 +100,17 @@ function update() { } function checkForEntity() { - var nametagProps = Entities.getEntityProperties(nametagEntityID); - + var nameTagProps = Entities.getEntityProperties(nameTagEntityID); // it is possible for the age to not be a valid number, we check for this and return accordingly - if(nametagProps.age < 1) { + if(nameTagProps.age < 1) { return; } - + // it's too old or we receive undefined make a new one, otherwise update - if(nametagProps.age > OLD_AGE || nametagProps.age == undefined) { + if(nameTagProps.age > OLD_AGE || nameTagProps.age == undefined) { deleteNameTag(); addNameTag(); } else { - var nametagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); - nametagPosition.y += HEIGHT_ABOVE_HEAD; - Entities.editEntity(nametagEntityID, { - position: nametagPosition, - // lifetime is in seconds we add TTL on top of the next poll time - lifetime: Math.round(nametagProps.age) + (ENTITY_CHECK_INTERVAL / 1000) + TTL, - text: MyAvatar.displayName - }); + updateNameTag(); } } From 5bf29f46570c92c392047d5bdf7824e5e17d783c Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Wed, 1 Feb 2017 12:59:40 +0000 Subject: [PATCH 10/79] improve dimensionsFromName implementation --- scripts/system/nameTag.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index ceb7583a2e..c95db0e647 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -69,15 +69,11 @@ function deleteNameTag() { } function dimensionsFromName() { - var nameTagDimensions = { - x: 0.0, + return { + x: LETTER_OFFSET * MyAvatar.displayName.length, y: SIZE_Y, z: 0.0 - } - for(var letter in MyAvatar.displayName) { - nameTagDimensions.x += LETTER_OFFSET; - } - return nameTagDimensions; + }; }; // cleanup on ending From f34f1312ab0117d20bd6136e4842d223527effd8 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 1 Feb 2017 15:53:49 -0800 Subject: [PATCH 11/79] Few fixes --- libraries/gpu/src/gpu/Image.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index bda16910c4..67d2071c4a 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -122,7 +122,7 @@ namespace image { public: using Format = typename P::Format; using Storage = typename P::Storage; - using Block = typename PixelBlock; + using Block = PixelBlock; constexpr uint16_t getWidth() const { return tileW; } constexpr uint16_t getHeight() const { return tileH; } @@ -250,9 +250,10 @@ namespace image { class Pixmap { public: using Tile = T; + using Block = typename Tile::Block; Grid _grid; - PixelBlockArray _blocks; + PixelBlockArray _blocks; void resize(const Grid::Coord2& widthHeight) { _grid = Grid(widthHeight, Coord2(Tile::getWidth(), Tile::getHeight())); @@ -260,4 +261,4 @@ namespace image { } }; -} \ No newline at end of file +} From 1a58dad3adc3525bd79c754b297412c35f781b41 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Thu, 2 Feb 2017 01:12:55 +0000 Subject: [PATCH 12/79] change age check check for equal to -1 instead of < 1, think this would be more suitable if undefined is returned. --- scripts/system/nameTag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index c95db0e647..88f7ab1f89 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -98,7 +98,7 @@ function update() { function checkForEntity() { var nameTagProps = Entities.getEntityProperties(nameTagEntityID); // it is possible for the age to not be a valid number, we check for this and return accordingly - if(nameTagProps.age < 1) { + if(nameTagProps.age == -1) { return; } From 569378bdeba31f3ee23770c243d49ce1b2811b1c Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 2 Feb 2017 01:57:43 -0800 Subject: [PATCH 13/79] REcompiling for windows... --- libraries/gpu/src/gpu/Image.cpp | 6 +-- libraries/gpu/src/gpu/Image.h | 67 ++++++++++++------------ libraries/model/src/model/TextureMap.cpp | 15 ++---- 3 files changed, 40 insertions(+), 48 deletions(-) diff --git a/libraries/gpu/src/gpu/Image.cpp b/libraries/gpu/src/gpu/Image.cpp index 5de1008d8f..46486d9436 100644 --- a/libraries/gpu/src/gpu/Image.cpp +++ b/libraries/gpu/src/gpu/Image.cpp @@ -15,10 +15,6 @@ namespace image { } template <> void compress(const PB_RGB32& src, CB_BC1& dst) { - - for (auto& b : dst.bytes) { - b = 12; - } } template <> void uncompress(const CB_BC1& src, PB_RGB32& dst) { @@ -27,7 +23,7 @@ template <> void uncompress(const CB_BC1& src, PB_RGB32& dst) { auto c0 = bc1.color0.val; auto c1 = bc1.color1.val; - for (int i = 0; i < PB_RGB32::SIZE; ++i) { + for (int i = 0; i < PB_RGB32::LENGTH; ++i) { //dst.pixels[i] = ; auto r = pixel::mix( c0, diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index bda16910c4..4457730594 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -82,40 +82,37 @@ namespace image { public: using Format = F; using Storage = S; - - union { - Storage raw; - Format val{ Format() }; // Format last to be initialized by Format's default constructor - }; - - Pixel() {}; + + Format val { Format() }; + + Pixel() : val(Format()) {}; Pixel(Format v) : val(v) {} - Pixel(Storage s) : raw(s) {} + Pixel(Storage s) : val(*static_cast (&s)) {} + + const Storage* storage() const { return static_cast (&val); } }; - template class PixelBlock { public: using Format = typename P::Format; using Storage = typename P::Storage; - - constexpr uint16_t getLength() const { return length; } - uint32_t getSize() const { return length * sizeof(P); } - + + static const uint16_t LENGTH { length }; + static const uint32_t SIZE { length * sizeof(P) }; + P pixels[length]; - + PixelBlock() {} - - + PixelBlock(const P* srcPixels) { setPixels(srcPixels); } - + void setPixels(const P* srcPixels) { memcpy(pixels, srcPixels, getSize()); } - - const Storage* getStorage() const { return static_cast (&pixels->raw); } + + const Storage* storage() const { return pixels->storage(); } }; template class Tile { @@ -123,12 +120,12 @@ namespace image { using Format = typename P::Format; using Storage = typename P::Storage; using Block = typename PixelBlock; - - constexpr uint16_t getWidth() const { return tileW; } - constexpr uint16_t getHeight() const { return tileH; } - + + uint16_t getWidth() const { return tileW; } + uint16_t getHeight() const { return tileH; } + Block _block; - + Tile() {} Tile(const P* srcPixels) : _block(srcPixels) {} @@ -162,15 +159,18 @@ namespace image { }; }; - template class CompressedBlock { + template ::type> class CompressedBlock { public: - static const uint32_t SIZE { sizeof(T) }; - union { - Byte bytes[SIZE]; - T bc; - }; - + using Format = F; + using Storage = S; + + static const uint32_t SIZE { sizeof(F) }; + + Format bc; + CompressedBlock() {} + + const Storage* storage() const { return static_cast (&bc); } }; @@ -250,9 +250,10 @@ namespace image { class Pixmap { public: using Tile = T; - + using Block = typename T::Block; + Grid _grid; - PixelBlockArray _blocks; + PixelBlockArray _blocks; void resize(const Grid::Coord2& widthHeight) { _grid = Grid(widthHeight, Coord2(Tile::getWidth(), Tile::getHeight())); diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 215ee367e4..3e2263ffc8 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -265,7 +265,6 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag image::PixRGB565 pix3; image::PB_RGB32 pb0; - image::CB_BC1 cb; image::PB_RGB32 pb1; auto pix0_s = sizeof(pix0); @@ -274,15 +273,11 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag auto pix3_s = sizeof(pix3); auto pb0_s = sizeof(pb0); - auto cb_s = sizeof(cb); - - auto cb_bytes = pb0.getStorage(); - image::compress(pb0, cb); - image::uncompress(cb, pb1); - - image::Grid grid; - grid. - + + image::Pixmap theMap(); + + // theMap(image.width(), image.height(), image.byteCount(), image.constBits()); + if (generateMips) { ::generateMips(theTexture, image, formatMip); } From 6dc2cee95dd5323c8bb9483cef99e0e0fa3499eb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:34:22 -0800 Subject: [PATCH 14/79] use type definition --- libraries/model-networking/src/model-networking/ModelCache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index bcca846625..adef3ce2b5 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -159,7 +159,7 @@ protected: class Texture { public: QString name; - QSharedPointer texture; + NetworkTexturePointer texture; }; using Textures = std::vector; From b4cef787d99b90bd82489b75cc22751695a19191 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:34:44 -0800 Subject: [PATCH 15/79] cleanup whitespace --- libraries/fbx/src/FBXReader_Material.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index 8c0f4b34ac..f3d0c30a41 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -47,10 +47,10 @@ FBXTexture FBXReader::getTexture(const QString& textureID) { texture.texcoordSet = 0; if (_textureParams.contains(textureID)) { auto p = _textureParams.value(textureID); - + texture.transform.setTranslation(p.translation); texture.transform.setRotation(glm::quat(glm::radians(p.rotation))); - + auto scaling = p.scaling; // Protect from bad scaling which should never happen if (scaling.x == 0.0f) { @@ -63,7 +63,7 @@ FBXTexture FBXReader::getTexture(const QString& textureID) { scaling.z = 1.0f; } texture.transform.setScale(scaling); - + if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) { texture.texcoordSet = 1; } @@ -78,11 +78,10 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { QJsonDocument materialMapDocument = QJsonDocument::fromJson(materialMapString.toUtf8()); QJsonObject materialMap = materialMapDocument.object(); - // foreach (const QString& materialID, materials) { for (QHash::iterator it = _fbxMaterials.begin(); it != _fbxMaterials.end(); it++) { FBXMaterial& material = (*it); - // Maya is the exporting the shading model and we aretrying to use it + // Maya is the exporting the shading model and we are trying to use it bool isMaterialLambert = (material.shadingModel.toLower() == "lambert"); // the pure material associated with this part @@ -127,21 +126,19 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity()); } - - FBXTexture normalTexture; QString bumpTextureID = bumpTextures.value(material.materialID); QString normalTextureID = normalTextures.value(material.materialID); if (!normalTextureID.isNull()) { normalTexture = getTexture(normalTextureID); normalTexture.isBumpmap = false; - + material.normalTexture = normalTexture; detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity()); } else if (!bumpTextureID.isNull()) { normalTexture = getTexture(bumpTextureID); normalTexture.isBumpmap = true; - + material.normalTexture = normalTexture; detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity()); } @@ -151,7 +148,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { if (!specularTextureID.isNull()) { specularTexture = getTexture(specularTextureID); detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity()); - material.specularTexture = specularTexture; + material.specularTexture = specularTexture; } FBXTexture metallicTexture; @@ -222,7 +219,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { ambientTextureID = ambientFactorTextures.value(material.materialID); } } - + if (_loadLightmaps && !ambientTextureID.isNull()) { ambientTexture = getTexture(ambientTextureID); detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity()); From 64dbfd08194e9a61b253327657d0c0ea4e1a9fdb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:35:40 -0800 Subject: [PATCH 16/79] cap size of textures from FBX files --- libraries/fbx/src/FBXReader.h | 9 ++-- .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/TextureCache.cpp | 53 +++++++++++++------ .../src/model-networking/TextureCache.h | 13 +++-- libraries/networking/src/ResourceCache.h | 4 +- 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index cd1dbc5c4f..8b58ad62d1 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -100,22 +100,25 @@ public: /// A single binding to a joint in an FBX document. class FBXCluster { public: - + int jointIndex; glm::mat4 inverseBindMatrix; }; +const int MAX_FBX_TEXTURE_SIZE = 1024 * 1024; + /// A texture map in an FBX document. class FBXTexture { public: QString name; QByteArray filename; QByteArray content; - + Transform transform; + int maxSize { MAX_FBX_TEXTURE_SIZE }; int texcoordSet; QString texcoordSetName; - + bool isBumpmap{ false }; bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 2a02540821..946e507d98 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -472,7 +472,7 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, TextureType type, MapChannel channel) { const auto url = getTextureUrl(baseUrl, fbxTexture); - const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content); + const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxSize); _textures[channel] = Texture { fbxTexture.name, texture }; auto map = std::make_shared(); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 6a4edd60ed..e108e69aa1 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -167,16 +167,17 @@ class TextureExtra { public: NetworkTexture::Type type; const QByteArray& content; + int maxSize; }; -ScriptableResource* TextureCache::prefetch(const QUrl& url, int type) { +ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxSize) { auto byteArray = QByteArray(); - TextureExtra extra = { (Type)type, byteArray }; + TextureExtra extra = { (Type)type, byteArray, maxSize }; return ResourceCache::prefetch(url, &extra); } -NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content) { - TextureExtra extra = { type, content }; +NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) { + TextureExtra extra = { type, content, maxSize }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); } @@ -251,13 +252,15 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh const TextureExtra* textureExtra = static_cast(extra); auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE; auto content = textureExtra ? textureExtra->content : QByteArray(); - return QSharedPointer(new NetworkTexture(url, type, content), + auto maxSize = textureExtra ? textureExtra->maxSize : ABSOLUTE_MAX_TEXTURE_SIZE; + return QSharedPointer(new NetworkTexture(url, type, content, maxSize), &Resource::deleter); } -NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content) : +NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) : Resource(url), - _type(type) + _type(type), + _maxSize(maxSize) { _textureSource = std::make_shared(); @@ -274,7 +277,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& con } NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) : - NetworkTexture(url, CUSTOM_TEXTURE, content) + NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_SIZE) { _textureLoader = textureLoader; } @@ -290,7 +293,8 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& resource, const QByteArray& data, const QUrl& url = QUrl()); + ImageReader(const QWeakPointer& resource, const QByteArray& data, + const QUrl& url = QUrl(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); virtual void run() override; @@ -300,6 +304,7 @@ private: QWeakPointer _resource; QUrl _url; QByteArray _content; + int _maxSize; }; void NetworkTexture::downloadFinished(const QByteArray& data) { @@ -308,14 +313,15 @@ void NetworkTexture::downloadFinished(const QByteArray& data) { } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url)); + QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxSize)); } ImageReader::ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url) : + const QUrl& url, int maxSize) : _resource(resource), _url(url), - _content(data) + _content(data), + _maxSize(maxSize) { #if DEBUG_DUMP_TEXTURE_LOADS static auto start = usecTimestampNow() / USECS_PER_MSEC; @@ -375,10 +381,10 @@ void ImageReader::run() { // Note that QImage.format is the pixel format which is different from the "format" of the image file... auto imageFormat = image.format(); - int originalWidth = image.width(); - int originalHeight = image.height(); + int imageWidth = image.width(); + int imageHeight = image.height(); - if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { + if (imageWidth == 0 || imageHeight == 0 || imageFormat == QImage::Format_Invalid) { if (filenameExtension.empty()) { qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url; } else { @@ -386,6 +392,21 @@ void ImageReader::run() { } return; } + + if (imageWidth * imageHeight > _maxSize) { + float scaleFactor = sqrtf(_maxSize / (float)(imageWidth * imageHeight)); + int originalWidth = imageWidth; + int originalHeight = imageHeight; + imageWidth = (int)(scaleFactor * (float)imageWidth + 0.5f); + imageHeight = (int)(scaleFactor * (float)imageHeight + 0.5f); + //QSize newSize(imageWidth, imageHeight); + QImage newImage = image.scaled(QSize(imageWidth, imageHeight), Qt::IgnoreAspectRatio); + image.swap(newImage); + qCDebug(modelnetworking) << "Downscale image" << _url + << "from" << originalWidth << "x" << originalHeight + << "to" << imageWidth << "x" << imageHeight; + } + gpu::TexturePointer texture = nullptr; { // Double-check the resource still exists between long operations. @@ -408,7 +429,7 @@ void ImageReader::run() { } else { QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, texture), - Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); + Q_ARG(int, imageWidth), Q_ARG(int, imageHeight)); } } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 8ccfe5364c..9ad06eddfb 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -23,6 +23,8 @@ #include #include +const int ABSOLUTE_MAX_TEXTURE_SIZE = 8192 * 8192; + namespace gpu { class Batch; } @@ -60,7 +62,7 @@ public: typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName); using TextureLoaderFunc = std::function; - NetworkTexture(const QUrl& url, Type type, const QByteArray& content); + NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize); NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content); QString getType() const override { return "NetworkTexture"; } @@ -70,7 +72,7 @@ public: int getWidth() const { return _width; } int getHeight() const { return _height; } Type getTextureType() const { return _type; } - + TextureLoaderFunc getTextureLoader() const; signals: @@ -81,7 +83,7 @@ protected: virtual bool isCacheable() const override { return _loaded; } virtual void downloadFinished(const QByteArray& data) override; - + Q_INVOKABLE void loadContent(const QByteArray& content); Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight); @@ -92,6 +94,7 @@ private: int _originalHeight { 0 }; int _width { 0 }; int _height { 0 }; + int _maxSize { ABSOLUTE_MAX_TEXTURE_SIZE }; }; using NetworkTexturePointer = QSharedPointer; @@ -129,11 +132,11 @@ public: /// Loads a texture from the specified URL. NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE, - const QByteArray& content = QByteArray()); + const QByteArray& content = QByteArray(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads - Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type); + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 03d37bc9ac..a369416ebe 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -86,7 +86,7 @@ private: /// Wrapper to expose resources to JS/QML class ScriptableResource : public QObject { Q_OBJECT - Q_PROPERTY(QUrl url READ getUrl) + Q_PROPERTY(QUrl url READ getURL) Q_PROPERTY(int state READ getState NOTIFY stateChanged) /**jsdoc @@ -125,7 +125,7 @@ public: */ Q_INVOKABLE void release(); - const QUrl& getUrl() const { return _url; } + const QUrl& getURL() const { return _url; } int getState() const { return (int)_state; } const QSharedPointer& getResource() const { return _resource; } From 2f8823d10384af30a0cd8c452db557acbf583558 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 14:09:47 -0800 Subject: [PATCH 17/79] name change: maxSize to maxNumPixels --- libraries/fbx/src/FBXReader.h | 4 +-- .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/TextureCache.cpp | 35 +++++++++---------- .../src/model-networking/TextureCache.h | 10 +++--- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 8b58ad62d1..5b4d3ec3bf 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -105,7 +105,7 @@ public: glm::mat4 inverseBindMatrix; }; -const int MAX_FBX_TEXTURE_SIZE = 1024 * 1024; +const int MAX_FBX_TEXTURE_NUM_PIXELS = 1024 * 1024; /// A texture map in an FBX document. class FBXTexture { @@ -115,7 +115,7 @@ public: QByteArray content; Transform transform; - int maxSize { MAX_FBX_TEXTURE_SIZE }; + int maxNumPixels { MAX_FBX_TEXTURE_NUM_PIXELS }; int texcoordSet; QString texcoordSetName; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 946e507d98..dd3193073d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -472,7 +472,7 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, TextureType type, MapChannel channel) { const auto url = getTextureUrl(baseUrl, fbxTexture); - const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxSize); + const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxNumPixels); _textures[channel] = Texture { fbxTexture.name, texture }; auto map = std::make_shared(); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index e108e69aa1..447a1b93c8 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -167,17 +167,17 @@ class TextureExtra { public: NetworkTexture::Type type; const QByteArray& content; - int maxSize; + int maxNumPixels; }; -ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxSize) { +ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNumPixels) { auto byteArray = QByteArray(); - TextureExtra extra = { (Type)type, byteArray, maxSize }; + TextureExtra extra = { (Type)type, byteArray, maxNumPixels }; return ResourceCache::prefetch(url, &extra); } -NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) { - TextureExtra extra = { type, content, maxSize }; +NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels) { + TextureExtra extra = { type, content, maxNumPixels }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); } @@ -252,15 +252,15 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh const TextureExtra* textureExtra = static_cast(extra); auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE; auto content = textureExtra ? textureExtra->content : QByteArray(); - auto maxSize = textureExtra ? textureExtra->maxSize : ABSOLUTE_MAX_TEXTURE_SIZE; - return QSharedPointer(new NetworkTexture(url, type, content, maxSize), + auto maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS; + return QSharedPointer(new NetworkTexture(url, type, content, maxNumPixels), &Resource::deleter); } -NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) : +NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels) : Resource(url), _type(type), - _maxSize(maxSize) + _maxNumPixels(maxNumPixels) { _textureSource = std::make_shared(); @@ -277,7 +277,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& con } NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) : - NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_SIZE) + NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_NUM_PIXELS) { _textureLoader = textureLoader; } @@ -294,7 +294,7 @@ class ImageReader : public QRunnable { public: ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url = QUrl(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + const QUrl& url = QUrl(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); virtual void run() override; @@ -304,7 +304,7 @@ private: QWeakPointer _resource; QUrl _url; QByteArray _content; - int _maxSize; + int _maxNumPixels; }; void NetworkTexture::downloadFinished(const QByteArray& data) { @@ -313,15 +313,15 @@ void NetworkTexture::downloadFinished(const QByteArray& data) { } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxSize)); + QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxNumPixels)); } ImageReader::ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url, int maxSize) : + const QUrl& url, int maxNumPixels) : _resource(resource), _url(url), _content(data), - _maxSize(maxSize) + _maxNumPixels(maxNumPixels) { #if DEBUG_DUMP_TEXTURE_LOADS static auto start = usecTimestampNow() / USECS_PER_MSEC; @@ -393,13 +393,12 @@ void ImageReader::run() { return; } - if (imageWidth * imageHeight > _maxSize) { - float scaleFactor = sqrtf(_maxSize / (float)(imageWidth * imageHeight)); + if (imageWidth * imageHeight > _maxNumPixels) { + float scaleFactor = sqrtf(_maxNumPixels / (float)(imageWidth * imageHeight)); int originalWidth = imageWidth; int originalHeight = imageHeight; imageWidth = (int)(scaleFactor * (float)imageWidth + 0.5f); imageHeight = (int)(scaleFactor * (float)imageHeight + 0.5f); - //QSize newSize(imageWidth, imageHeight); QImage newImage = image.scaled(QSize(imageWidth, imageHeight), Qt::IgnoreAspectRatio); image.swap(newImage); qCDebug(modelnetworking) << "Downscale image" << _url diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 9ad06eddfb..cb509490c6 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -23,7 +23,7 @@ #include #include -const int ABSOLUTE_MAX_TEXTURE_SIZE = 8192 * 8192; +const int ABSOLUTE_MAX_TEXTURE_NUM_PIXELS = 8192 * 8192; namespace gpu { class Batch; @@ -62,7 +62,7 @@ public: typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName); using TextureLoaderFunc = std::function; - NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize); + NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels); NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content); QString getType() const override { return "NetworkTexture"; } @@ -94,7 +94,7 @@ private: int _originalHeight { 0 }; int _width { 0 }; int _height { 0 }; - int _maxSize { ABSOLUTE_MAX_TEXTURE_SIZE }; + int _maxNumPixels { ABSOLUTE_MAX_TEXTURE_NUM_PIXELS }; }; using NetworkTexturePointer = QSharedPointer; @@ -132,11 +132,11 @@ public: /// Loads a texture from the specified URL. NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE, - const QByteArray& content = QByteArray(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads - Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; From b440ccad280b445fa17660b449eae4c1a3a3c444 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 2 Feb 2017 17:53:48 -0800 Subject: [PATCH 18/79] Improving the IMage class --- libraries/gpu/src/gpu/Image.h | 135 ++++++++++++++++++++++- libraries/model/src/model/TextureMap.cpp | 5 +- 2 files changed, 134 insertions(+), 6 deletions(-) diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index 4457730594..6af763e6bd 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -37,8 +37,20 @@ namespace image { Byte mix5_4(const Byte x, const Byte y, const Byte a) { return mix<5, 4>(x, y, a); } Byte mix6_4(const Byte x, const Byte y, const Byte a) { return mix<6, 4>(x, y, a); } - - + + + + // Coordinate and count types + using Coord = uint16_t; + using Coord2 = glm::u16vec2; + using Count = uint32_t; + + // Maximum pixel along one direction coord is 32768 + static const Coord MAX_COORD { 32768 }; + // Maximum number of pixels + static const Count MAX_COUNT { MAX_COORD * MAX_COORD }; + + namespace pixel { struct RGB32 { @@ -83,6 +95,8 @@ namespace image { using Format = F; using Storage = S; + static const uint32_t SIZE { sizeof(S) }; + Format val { Format() }; Pixel() : val(Format()) {}; @@ -191,14 +205,75 @@ namespace image { template <> void uncompress(const CB_BC4& src, PB_RGBA32& dst); + template + class PixelArray { + public: + using Pixel = P; + using Storage = typename P::Storage; + using Storages = std::vector; + + static int evalNumPixels(size_t byteSize) { + size_t numPixels = byteSize / Pixel::SIZE; + if (byteSize > numPixels * Pixel::SIZE) { + numPixels++; + } + return (int)numPixels; + }; + static size_t evalByteSize(int numPixels) { + return numPixels * Pixel::SIZE; + }; + + PixelArray(size_t byteSize, const void* bytes) { + setBytes(byteSize, bytes); + } + + int numPixels() const { return _storages.size(); } + size_t byteSize() const { return evalByteSize(_storages.size()); } + + Storages _storages; + + private: + void setBytes(size_t byteSize, const void* bytes) { + _storages = Storages(evalNumPixels(byteSize)); + if (bytes) { + memcpy(_storages.data(), bytes, byteSize); + } + } + }; + template class PixelBlockArray { public: using Block = B; - using Blocks = std::vector; - + + static int evalNumBlocks(size_t byteSize) { + size_t numBlocks = byteSize / Block::SIZE; + if (byteSize > numBlocks * Block::SIZE) { + numBlocks++; + } + return (int) numBlocks; + }; + static size_t evalByteSize(int numBlocks) { + return numBlocks * Block::SIZE; + }; + + PixelBlockArray(size_t byteSize, const void* bytes) { + setBytes(byteSize, bytes); + } + + int numBlocks() const { return evalByteSize(_blocks.size()); } + size_t byteSize() const { return evalByteSize(_blocks.size()); } + Blocks _blocks; + + private: + void setBytes(size_t byteSize, const void* bytes) { + _blocks = Blocks(evalNumBlocks(byteSize)); + if (bytes) { + memcpy(_blocks.data(), bytes, byteSize); + } + } }; class Grid { @@ -247,7 +322,7 @@ namespace image { }; template - class Pixmap { + class Tilemap { public: using Tile = T; using Block = typename T::Block; @@ -261,4 +336,54 @@ namespace image { } }; + + class Dim { + public: + + Coord2 _dims { 0 }; + + static Coord cap(Coord c) { return (c < MAX_COORD ? c : MAX_COORD); } + static Coord2 cap(const Coord2& dims) { return Coord2(cap(dims.x), cap(dims.y)); } + + static Count numPixels(const Coord2& dims) { return Count(cap(dims.x)) * Count(cap(dims.y)); } + + + static Coord nextMip(Coord c) { return (c > 1 ? (c >> 1) : c); } + static Coord2 nextMip(const Coord2& dims) { return Coord2(nextMip(dims.x), nextMip(dims.y)); } + + Dim(Coord w, Coord h) : _dims(w, h) {} + Dim(const Coord2& dims) : _dims(dims) {} + + Count numPixels() const { return Dim::numPixels(_dims); } + Dim nextMip() const { return Dim(nextMip(_dims)); } + }; + + template < typename P > class Surface { + public: + using Pixel = P; + using Format = typename P::Format; + using Pixels = pixel::Pixels

; + + Dim _dims { 0, 0 }; + Pixels _pixels; + + Surface(Coord width, Coord height, size_t byteSize, const void* bytes) : + _dims(width, height), + _pixels(byteSize, bytes) + {} + + void downsample() { + Dim subDim = _dims.nextMip(); + + Surface next() + + + for (int y = 0; y < _dims.y; y++) { + for (int x = 0; x < _dims.x; x++) { + + } + } + } + + }; } \ No newline at end of file diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 3e2263ffc8..bef0f0c92c 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -274,7 +274,10 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag auto pb0_s = sizeof(pb0); - image::Pixmap theMap(); + image::Surface surface(image.width(), image.height(), image.byteCount(), image.constBits()); + + auto sub = surface.downsample(); + // theMap(image.width(), image.height(), image.byteCount(), image.constBits()); From a5e61184bf4055f403a3b9064c24fe7bd068373f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Dec 2016 16:34:49 -0800 Subject: [PATCH 19/79] Add support for adding thread names to a trace --- libraries/shared/src/Profile.cpp | 1 + libraries/shared/src/Profile.h | 6 ++++ libraries/shared/src/Trace.cpp | 59 ++++++++++++++++++++++---------- libraries/shared/src/Trace.h | 1 + 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/libraries/shared/src/Profile.cpp b/libraries/shared/src/Profile.cpp index f23c17c6be..b4f7ed8509 100644 --- a/libraries/shared/src/Profile.cpp +++ b/libraries/shared/src/Profile.cpp @@ -10,6 +10,7 @@ Q_LOGGING_CATEGORY(trace_app, "trace.app") Q_LOGGING_CATEGORY(trace_app_detail, "trace.app.detail") +Q_LOGGING_CATEGORY(trace_metadata, "trace.metadata") Q_LOGGING_CATEGORY(trace_network, "trace.network") Q_LOGGING_CATEGORY(trace_parse, "trace.parse") Q_LOGGING_CATEGORY(trace_render, "trace.render") diff --git a/libraries/shared/src/Profile.h b/libraries/shared/src/Profile.h index da786526a7..bbba240840 100644 --- a/libraries/shared/src/Profile.h +++ b/libraries/shared/src/Profile.h @@ -16,6 +16,7 @@ // When profiling something that may happen many times per frame, use a xxx_detail category so that they may easily be filtered out of trace results Q_DECLARE_LOGGING_CATEGORY(trace_app) Q_DECLARE_LOGGING_CATEGORY(trace_app_detail) +Q_DECLARE_LOGGING_CATEGORY(trace_metadata) Q_DECLARE_LOGGING_CATEGORY(trace_network) Q_DECLARE_LOGGING_CATEGORY(trace_render) Q_DECLARE_LOGGING_CATEGORY(trace_render_detail) @@ -69,6 +70,10 @@ inline void counter(const QLoggingCategory& category, const QString& name, const } } +inline void metadata(const QString& metadataType, const QVariantMap& args) { + tracing::traceEvent(trace_metadata(), metadataType, tracing::Metadata, "", args); +} + #define PROFILE_RANGE(category, name) Duration profileRangeThis(trace_##category(), name); #define PROFILE_RANGE_EX(category, name, argbColor, payload, ...) Duration profileRangeThis(trace_##category(), name, argbColor, (uint64_t)payload, ##__VA_ARGS__); #define PROFILE_RANGE_BEGIN(category, rangeId, name, argbColor) rangeId = Duration::beginRange(trace_##category(), name, argbColor) @@ -78,6 +83,7 @@ inline void counter(const QLoggingCategory& category, const QString& name, const #define PROFILE_COUNTER_IF_CHANGED(category, name, type, value) { static type lastValue = 0; type newValue = value; if (newValue != lastValue) { counter(trace_##category(), name, { { name, newValue }}); lastValue = newValue; } } #define PROFILE_COUNTER(category, name, ...) counter(trace_##category(), name, ##__VA_ARGS__); #define PROFILE_INSTANT(category, name, ...) instant(trace_##category(), name, ##__VA_ARGS__); +#define PROFILE_SET_THREAD_NAME(threadName) metadata("thread_name", { { "name", threadName } }); #define SAMPLE_PROFILE_RANGE(chance, category, name, ...) if (randFloat() <= chance) { PROFILE_RANGE(category, name); } #define SAMPLE_PROFILE_RANGE_EX(chance, category, name, ...) if (randFloat() <= chance) { PROFILE_RANGE_EX(category, name, argbColor, payload, ##__VA_ARGS__); } diff --git a/libraries/shared/src/Trace.cpp b/libraries/shared/src/Trace.cpp index e4ad70d912..1e3d490a9c 100644 --- a/libraries/shared/src/Trace.cpp +++ b/libraries/shared/src/Trace.cpp @@ -132,6 +132,9 @@ void Tracer::serialize(const QString& originalPath) { { std::lock_guard guard(_eventsMutex); currentEvents.swap(_events); + for (auto& event : _metadataEvents) { + currentEvents.push_back(event); + } } // If the file exists and we can't remove it, fail early @@ -194,33 +197,53 @@ void Tracer::serialize(const QString& originalPath) { #endif } -void Tracer::traceEvent(const QLoggingCategory& category, - const QString& name, EventType type, - qint64 timestamp, qint64 processID, qint64 threadID, - const QString& id, - const QVariantMap& args, const QVariantMap& extra) { +void Tracer::traceEvent(const QLoggingCategory& category, + const QString& name, EventType type, + qint64 timestamp, qint64 processID, qint64 threadID, + const QString& id, + const QVariantMap& args, const QVariantMap& extra) { std::lock_guard guard(_eventsMutex); - if (!_enabled) { + + // We always want to store metadata events even if tracing is not enabled so that when + // tracing is enabled we will be able to associate that metadata with that trace. + // Metadata events should be used sparingly - as of 12/30/16 the Chrome Tracing + // spec only supports thread+process metadata, so we should only expect to see metadata + // events created when a new thread or process is created. + if (!_enabled && type != Metadata) { return; } - _events.push_back({ - id, - name, - type, - timestamp, - processID, - threadID, - category, - args, - extra - }); + if (type == Metadata) { + _metadataEvents.push_back({ + id, + name, + type, + timestamp, + processID, + threadID, + category, + args, + extra + }); + } else { + _events.push_back({ + id, + name, + type, + timestamp, + processID, + threadID, + category, + args, + extra + }); + } } void Tracer::traceEvent(const QLoggingCategory& category, const QString& name, EventType type, const QString& id, const QVariantMap& args, const QVariantMap& extra) { - if (!_enabled) { + if (!_enabled && type != Metadata) { return; } diff --git a/libraries/shared/src/Trace.h b/libraries/shared/src/Trace.h index ee4f28f0ce..93e2c6c4c2 100644 --- a/libraries/shared/src/Trace.h +++ b/libraries/shared/src/Trace.h @@ -97,6 +97,7 @@ private: bool _enabled { false }; std::list _events; + std::list _metadataEvents; std::mutex _eventsMutex; }; From f2638637f700de3684f4c7921d4bc69cf76b82e7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Dec 2016 16:41:09 -0800 Subject: [PATCH 20/79] Add thread names to traces --- interface/src/Application.cpp | 1 + .../src/display-plugins/OpenGLDisplayPlugin.cpp | 2 ++ libraries/script-engine/src/ScriptEngine.cpp | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cfbaee7ade..d39ad337a8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -436,6 +436,7 @@ bool setupEssentials(int& argc, char** argv) { } DependencyManager::set(); + PROFILE_SET_THREAD_NAME("Main Thread"); #if defined(Q_OS_WIN) // Select appropriate audio DLL diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 574c574f66..cf6b39812a 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -118,6 +118,8 @@ public: virtual void run() override { + PROFILE_SET_THREAD_NAME("Present Thread"); + // FIXME determine the best priority balance between this and the main thread... // It may be dependent on the display plugin being used, since VR plugins should // have higher priority on rendering (although we could say that the Oculus plugin diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2191d45d45..7f5931b1e7 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -863,6 +863,10 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi } void ScriptEngine::run() { + auto filenameParts = _fileNameString.split("/"); + auto name = filenameParts.size() > 0 ? filenameParts[filenameParts.size() - 1] : "unknown"; + PROFILE_SET_THREAD_NAME("Script: " + name); + if (DependencyManager::get()->isStopped()) { return; // bail early - avoid setting state in init(), as evaluate() will bail too } From e181c2a16ef74484ba6c6ce9e3879f7f0982aa65 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Dec 2016 16:48:00 -0800 Subject: [PATCH 21/79] Add script_udpate_rate to trace --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d39ad337a8..4b6156adbc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3411,6 +3411,10 @@ void Application::idle(float nsecsElapsed) { static std::once_flag once; std::call_once(once, [] { initCpuUsage(); + PROFILE_COUNTER(app, "fps", { { "fps", _frameCounter.rate() } }); + PROFILE_COUNTER(app, "downloads", { + { "current", ResourceCache::getLoadingRequests().length() }, + { "pending", ResourceCache::getPendingRequestCount() } }); vec3 kernelUserAndSystem; From 9d4fdfa38a13bd3cbdee365f1e768cc589b3296a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Dec 2016 16:48:25 -0800 Subject: [PATCH 22/79] Add Test.profileRange --- interface/src/scripting/TestScriptingInterface.cpp | 6 ++++++ interface/src/scripting/TestScriptingInterface.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 22a33ae858..a8901365e5 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -134,3 +134,9 @@ void TestScriptingInterface::startTraceEvent(QString name) { void TestScriptingInterface::endTraceEvent(QString name) { tracing::traceEvent(trace_test(), name, tracing::DurationEnd); } + +void TestScriptingInterface::profileRange(const QString& name, QScriptValue fn) { + PROFILE_RANGE(script, name); + fn.call(); +} + diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index 9539493b51..73b8f0ac93 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -13,6 +13,8 @@ #include #include +class QScriptValue; + class TestScriptingInterface : public QObject { Q_OBJECT @@ -69,6 +71,7 @@ public slots: void endTraceEvent(QString name); + Q_INVOKABLE void profileRange(const QString& name, QScriptValue function); private: bool waitForCondition(qint64 maxWaitMs, std::function condition); From ce9f8bed1b9f7361115bd3be06c3891fc0e7d038 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 3 Feb 2017 09:41:48 -0800 Subject: [PATCH 23/79] Remove duplicate fps/downloads PROFILE_COUNTER --- interface/src/Application.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4b6156adbc..d39ad337a8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3411,10 +3411,6 @@ void Application::idle(float nsecsElapsed) { static std::once_flag once; std::call_once(once, [] { initCpuUsage(); - PROFILE_COUNTER(app, "fps", { { "fps", _frameCounter.rate() } }); - PROFILE_COUNTER(app, "downloads", { - { "current", ResourceCache::getLoadingRequests().length() }, - { "pending", ResourceCache::getPendingRequestCount() } }); vec3 kernelUserAndSystem; From 55df6f8f76e85b3dc00eec577fffa6ac60b05ea3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Dec 2016 16:49:27 -0800 Subject: [PATCH 24/79] Add tracing to ScriptEngine and EntitiesScriptingInterface --- .../entities/src/EntityScriptingInterface.cpp | 49 +++++++++++++++++++ libraries/script-engine/src/ScriptEngine.cpp | 15 +++++- libraries/shared/src/Profile.cpp | 2 + libraries/shared/src/Profile.h | 2 + 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index edace784ad..2a8dcf5b78 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -178,6 +178,8 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, bool clientOnly) { + PROFILE_RANGE(script_entities, __FUNCTION__); + _activityTracking.addedEntityCount++; EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties); @@ -270,6 +272,8 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit } EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) { + PROFILE_RANGE(script_entities, __FUNCTION__); + EntityItemProperties results; if (_entityTree) { _entityTree->withReadLock([&] { @@ -316,6 +320,8 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit } QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) { + PROFILE_RANGE(script_entities, __FUNCTION__); + _activityTracking.editedEntityCount++; EntityItemProperties properties = scriptSideProperties; @@ -467,6 +473,8 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& } void EntityScriptingInterface::deleteEntity(QUuid id) { + PROFILE_RANGE(script_entities, __FUNCTION__); + _activityTracking.deletedEntityCount++; EntityItemID entityID(id); @@ -522,6 +530,8 @@ void EntityScriptingInterface::setEntitiesScriptEngine(EntitiesScriptEngineProvi } void EntityScriptingInterface::callEntityMethod(QUuid id, const QString& method, const QStringList& params) { + PROFILE_RANGE(script_entities, __FUNCTION__); + std::lock_guard lock(_entitiesScriptEngineLock); if (_entitiesScriptEngine) { EntityItemID entityID{ id }; @@ -530,6 +540,8 @@ void EntityScriptingInterface::callEntityMethod(QUuid id, const QString& method, } QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { + PROFILE_RANGE(script_entities, __FUNCTION__); + EntityItemID result; if (_entityTree) { EntityItemPointer closestEntity; @@ -553,6 +565,8 @@ void EntityScriptingInterface::dumpTree() const { } QVector EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const { + PROFILE_RANGE(script_entities, __FUNCTION__); + QVector result; if (_entityTree) { QVector entities; @@ -568,6 +582,8 @@ QVector EntityScriptingInterface::findEntities(const glm::vec3& center, f } QVector EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const { + PROFILE_RANGE(script_entities, __FUNCTION__); + QVector result; if (_entityTree) { QVector entities; @@ -584,6 +600,8 @@ QVector EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn } QVector EntityScriptingInterface::findEntitiesInFrustum(QVariantMap frustum) const { + PROFILE_RANGE(script_entities, __FUNCTION__); + QVector result; const QString POSITION_PROPERTY = "position"; @@ -627,6 +645,7 @@ QVector EntityScriptingInterface::findEntitiesInFrustum(QVariantMap frust RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) { + PROFILE_RANGE(script_entities, __FUNCTION__); QVector entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); QVector entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard); @@ -734,6 +753,8 @@ RayToEntityIntersectionResult::RayToEntityIntersectionResult() : } QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, const RayToEntityIntersectionResult& value) { + PROFILE_RANGE(script_entities, __FUNCTION__); + QScriptValue obj = engine->newObject(); obj.setProperty("intersects", value.intersects); obj.setProperty("accurate", value.accurate); @@ -781,6 +802,8 @@ QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, c } void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, RayToEntityIntersectionResult& value) { + PROFILE_RANGE(script_entities, __FUNCTION__); + value.intersects = object.property("intersects").toVariant().toBool(); value.accurate = object.property("accurate").toVariant().toBool(); QScriptValue entityIDValue = object.property("entityID"); @@ -818,6 +841,8 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra bool EntityScriptingInterface::setVoxels(QUuid entityID, std::function actor) { + PROFILE_RANGE(script_entities, __FUNCTION__); + if (!_entityTree) { return false; } @@ -842,6 +867,8 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, } bool EntityScriptingInterface::setPoints(QUuid entityID, std::function actor) { + PROFILE_RANGE(script_entities, __FUNCTION__); + if (!_entityTree) { return false; } @@ -881,18 +908,24 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::function& points) { + PROFILE_RANGE(script_entities, __FUNCTION__); + EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; @@ -924,6 +961,8 @@ bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; @@ -999,6 +1038,8 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID, QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, const QUuid& entityID, const QVariantMap& arguments) { + PROFILE_RANGE(script_entities, __FUNCTION__); + QUuid actionID = QUuid::createUuid(); auto actionFactory = DependencyManager::get(); bool success = false; @@ -1030,6 +1071,8 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& actionID, const QVariantMap& arguments) { + PROFILE_RANGE(script_entities, __FUNCTION__); + return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { bool success = entity->updateAction(simulation, actionID, arguments); if (success) { @@ -1040,6 +1083,8 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& } bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& actionID) { + PROFILE_RANGE(script_entities, __FUNCTION__); + bool success = false; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { success = entity->removeAction(simulation, actionID); @@ -1053,6 +1098,8 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& } QVector EntityScriptingInterface::getActionIDs(const QUuid& entityID) { + PROFILE_RANGE(script_entities, __FUNCTION__); + QVector result; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { QList actionIDs = entity->getActionIDs(); @@ -1063,6 +1110,8 @@ QVector EntityScriptingInterface::getActionIDs(const QUuid& entityID) { } QVariantMap EntityScriptingInterface::getActionArguments(const QUuid& entityID, const QUuid& actionID) { + PROFILE_RANGE(script_entities, __FUNCTION__); + QVariantMap result; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { result = entity->getActionArguments(actionID); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 7f5931b1e7..ec83ea2ba9 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -64,6 +64,8 @@ #include "ScriptEngines.h" #include "TabletScriptingInterface.h" +#include + #include "MIDIEvent.h" static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3"; @@ -927,7 +929,10 @@ void ScriptEngine::run() { bool processedEvents = false; while (!_isFinished && clock::now() < sleepUntil) { - QCoreApplication::processEvents(); // before we sleep again, give events a chance to process + { + PROFILE_RANGE(script, "processEvents-sleep"); + QCoreApplication::processEvents(); // before we sleep again, give events a chance to process + } processedEvents = true; // If after processing events, we're past due, exit asap @@ -942,6 +947,8 @@ void ScriptEngine::run() { std::this_thread::sleep_until(smallSleepUntil); } + PROFILE_RANGE(script, "ScriptMainLoop"); + #ifdef SCRIPT_DELAY_DEBUG { auto actuallySleptUntil = clock::now(); @@ -965,6 +972,7 @@ void ScriptEngine::run() { // Only call this if we didn't processEvents as part of waiting for next frame if (!processedEvents) { + PROFILE_RANGE(script, "processEvents"); QCoreApplication::processEvents(); } @@ -989,7 +997,10 @@ void ScriptEngine::run() { float deltaTime = (float) (now - _lastUpdate) / (float) USECS_PER_SECOND; if (!_isFinished) { auto preUpdate = clock::now(); - emit update(deltaTime); + { + PROFILE_RANGE(script, "ScriptUpdate"); + emit update(deltaTime); + } auto postUpdate = clock::now(); auto elapsed = (postUpdate - preUpdate); totalUpdates += std::chrono::duration_cast(elapsed); diff --git a/libraries/shared/src/Profile.cpp b/libraries/shared/src/Profile.cpp index b4f7ed8509..7a8a8f0570 100644 --- a/libraries/shared/src/Profile.cpp +++ b/libraries/shared/src/Profile.cpp @@ -19,6 +19,8 @@ Q_LOGGING_CATEGORY(trace_render_gpu, "trace.render.gpu") Q_LOGGING_CATEGORY(trace_resource, "trace.resource") Q_LOGGING_CATEGORY(trace_resource_network, "trace.resource.network") Q_LOGGING_CATEGORY(trace_resource_parse, "trace.resource.parse") +Q_LOGGING_CATEGORY(trace_script, "trace.script") +Q_LOGGING_CATEGORY(trace_script_entities, "trace.script.entities") Q_LOGGING_CATEGORY(trace_simulation, "trace.simulation") Q_LOGGING_CATEGORY(trace_simulation_detail, "trace.simulation.detail") Q_LOGGING_CATEGORY(trace_simulation_animation, "trace.simulation.animation") diff --git a/libraries/shared/src/Profile.h b/libraries/shared/src/Profile.h index bbba240840..ee09298deb 100644 --- a/libraries/shared/src/Profile.h +++ b/libraries/shared/src/Profile.h @@ -24,6 +24,8 @@ Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu) Q_DECLARE_LOGGING_CATEGORY(trace_resource) Q_DECLARE_LOGGING_CATEGORY(trace_resource_parse) Q_DECLARE_LOGGING_CATEGORY(trace_resource_network) +Q_DECLARE_LOGGING_CATEGORY(trace_script) +Q_DECLARE_LOGGING_CATEGORY(trace_script_entities) Q_DECLARE_LOGGING_CATEGORY(trace_simulation) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_detail) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation) From aba441ee14e223d5bc152f01c86adff599aa7a68 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 31 Jan 2017 13:15:45 -0800 Subject: [PATCH 25/79] Fix compilation issues --- libraries/entities/src/EntityScriptingInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 2a8dcf5b78..2904a2d18f 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -27,6 +27,7 @@ #include "ZoneEntityItem.h" #include "WebEntityItem.h" #include +#include EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) : From 56911bdf1becc2a368e087f9c775252cade1187e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 3 Feb 2017 11:14:40 -0800 Subject: [PATCH 26/79] sliding texture caps for models --- libraries/fbx/src/FBXReader.cpp | 27 +++++++++++++ libraries/fbx/src/FBXReader.h | 8 +++- libraries/fbx/src/FBXReader_Material.cpp | 50 ++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 42922ce226..917009956e 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1465,6 +1465,33 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS // Create the Material Library consolidateFBXMaterials(mapping); + + // HACK: until we get proper LOD management we're going to cap model textures + // according to how many unique textures the model uses: + // 1 - 7 textures --> 2048 + // 8 - 31 textures --> 1024 + // 32 - 127 textures --> 512 + // etc... + QSet uniqueTextures; + for (auto& material : _fbxMaterials) { + material.getTextureNames(uniqueTextures); + } + int numTextures = uniqueTextures.size(); + const int MAX_NUM_TEXTURES_AT_MAX_RESOLUTION = 7; + if (numTextures > MAX_NUM_TEXTURES_AT_MAX_RESOLUTION) { + int maxWidth = sqrt(MAX_NUM_PIXELS_FOR_FBX_TEXTURE + 1); + int t = numTextures; + t /= MAX_NUM_TEXTURES_AT_MAX_RESOLUTION; + while (t > 0) { + maxWidth /= 2; + t /= 4; + } + qCDebug(modelformat) << "max square texture width =" << maxWidth << " for model" << url; + for (auto& material : _fbxMaterials) { + material.setMaxNumPixelsPerTexture(maxWidth * maxWidth); + } + } + geometry.materials = _fbxMaterials; // see if any materials have texture children diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 5b4d3ec3bf..b0e34dd674 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -13,6 +13,7 @@ #define hifi_FBXReader_h #include +#include #include #include #include @@ -105,7 +106,7 @@ public: glm::mat4 inverseBindMatrix; }; -const int MAX_FBX_TEXTURE_NUM_PIXELS = 1024 * 1024; +const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048; /// A texture map in an FBX document. class FBXTexture { @@ -115,7 +116,7 @@ public: QByteArray content; Transform transform; - int maxNumPixels { MAX_FBX_TEXTURE_NUM_PIXELS }; + int maxNumPixels { MAX_NUM_PIXELS_FOR_FBX_TEXTURE }; int texcoordSet; QString texcoordSetName; @@ -146,6 +147,9 @@ public: shininess(shininess), opacity(opacity) {} + void getTextureNames(QSet& textureList) const; + void setMaxNumPixelsPerTexture(int maxNumPixels); + glm::vec3 diffuseColor{ 1.0f }; float diffuseFactor{ 1.0f }; glm::vec3 specularColor{ 0.02f }; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index f3d0c30a41..ca2ec557b4 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -27,6 +27,56 @@ #include "ModelFormatLogging.h" +void FBXMaterial::getTextureNames(QSet& textureList) const { + if (!normalTexture.isNull()) { + textureList.insert(normalTexture.name); + } + if (!albedoTexture.isNull()) { + textureList.insert(albedoTexture.name); + } + if (!opacityTexture.isNull()) { + textureList.insert(opacityTexture.name); + } + if (!glossTexture.isNull()) { + textureList.insert(glossTexture.name); + } + if (!roughnessTexture.isNull()) { + textureList.insert(roughnessTexture.name); + } + if (!specularTexture.isNull()) { + textureList.insert(specularTexture.name); + } + if (!metallicTexture.isNull()) { + textureList.insert(metallicTexture.name); + } + if (!emissiveTexture.isNull()) { + textureList.insert(emissiveTexture.name); + } + if (!occlusionTexture.isNull()) { + textureList.insert(occlusionTexture.name); + } + if (!scatteringTexture.isNull()) { + textureList.insert(scatteringTexture.name); + } + if (!lightmapTexture.isNull()) { + textureList.insert(lightmapTexture.name); + } +} + +void FBXMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) { + normalTexture.maxNumPixels = maxNumPixels; + albedoTexture.maxNumPixels = maxNumPixels; + opacityTexture.maxNumPixels = maxNumPixels; + glossTexture.maxNumPixels = maxNumPixels; + roughnessTexture.maxNumPixels = maxNumPixels; + specularTexture.maxNumPixels = maxNumPixels; + metallicTexture.maxNumPixels = maxNumPixels; + emissiveTexture.maxNumPixels = maxNumPixels; + occlusionTexture.maxNumPixels = maxNumPixels; + scatteringTexture.maxNumPixels = maxNumPixels; + lightmapTexture.maxNumPixels = maxNumPixels; +} + bool FBXMaterial::needTangentSpace() const { return !normalTexture.isNull(); } From 27dab5c4baabcfae54a79e90f0b00747d2a9e68c Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 3 Feb 2017 12:03:59 -0800 Subject: [PATCH 27/79] COmbining more intrumentation, mip generation on cpu and an improved blit for the derez case --- .../gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 2 + .../src/gpu/gl45/GL45BackendTexture.cpp | 65 +++++++++++++------ libraries/model/src/model/TextureMap.cpp | 2 +- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index df9153d43e..179297069f 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -113,6 +113,7 @@ void GLTextureTransferHelper::queueExecution(VoidLambda lambda) { #define MAX_TRANSFERS_PER_PASS 2 bool GLTextureTransferHelper::process() { + PROFILE_RANGE(render_gpu_gl, __FUNCTION__) // Take any new textures or commands off the queue VoidLambdaList pendingCommands; TextureList newTransferTextures; @@ -151,6 +152,7 @@ bool GLTextureTransferHelper::process() { #endif return true; } + PROFILE_COUNTER_IF_CHANGED(render_gpu_gl, "transferringTextures", size_t, _transferringTextures.size()) static auto lastReport = usecTimestampNow(); auto now = usecTimestampNow(); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index b540a403c7..37d238f95c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -297,6 +297,7 @@ void GL45Texture::startTransfer() { } bool GL45Texture::continueTransfer() { + PROFILE_RANGE(render_gpu_gl, "continueTransfer") size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1; for (uint8_t face = 0; face < maxFace; ++face) { for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) { @@ -306,6 +307,8 @@ bool GL45Texture::continueTransfer() { _sparseInfo.allocatedPages += _sparseInfo.getPageCount(size); } if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { + PROFILE_RANGE_EX(render_gpu_gl, "texSubImage", 0x0000ffff, (size.x * size.y * maxFace / 1024)); + auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); if (GL_TEXTURE_2D == _target) { @@ -379,6 +382,8 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { return; } + PROFILE_RANGE(render_gpu_gl, "GL45Texture::stripToMip"); + auto mipLevels = usedMipLevels(); { Lock lock(texturesByMipCountsMutex); @@ -420,29 +425,51 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { auto newLevels = usedMipLevels(); // Create and setup the new texture (allocate) - glCreateTextures(_target, 1, &const_cast(_id)); - glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); - glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); - Vec3u newDimensions = _gpuObject.evalMipDimensions(_mipOffset); - glTextureStorage2D(_id, newLevels, _internalFormat, newDimensions.x, newDimensions.y); + { + Vec3u newDimensions = _gpuObject.evalMipDimensions(_mipOffset); + PROFILE_RANGE_EX(render_gpu_gl, "Re-Allocate", 0xff0000ff, (newDimensions.x * newDimensions.y)); + + glCreateTextures(_target, 1, &const_cast(_id)); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); + glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); + glTextureStorage2D(_id, newLevels, _internalFormat, newDimensions.x, newDimensions.y); + } // Copy the contents of the old texture to the new - GLuint fbo { 0 }; - glCreateFramebuffers(1, &fbo); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); - for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { - uint16 sourceMip = targetMip + mipDelta; - Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); - for (GLenum target : getFaceTargets(_target)) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, oldId, sourceMip); - (void)CHECK_GL_ERROR(); - glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, mipDimensions.x, mipDimensions.y); - (void)CHECK_GL_ERROR(); + { + PROFILE_RANGE(render_gpu_gl, "Blit"); + /* + GLuint fbo { 0 }; + glCreateFramebuffers(1, &fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { + uint16 sourceMip = targetMip + mipDelta; + Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); + for (GLenum target : getFaceTargets(_target)) { + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, oldId, sourceMip); + (void)CHECK_GL_ERROR(); + glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, mipDimensions.x, mipDimensions.y); + (void)CHECK_GL_ERROR(); + } } + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &fbo); + */ + for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { + uint16 sourceMip = targetMip + mipDelta; + Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); + for (GLenum target : getFaceTargets(_target)) { + glCopyImageSubData( + oldId, target, sourceMip, 0, 0, 0, + _id, target, targetMip, 0, 0, 0, + mipDimensions.x, mipDimensions.y, 1 + ); + (void)CHECK_GL_ERROR(); + } + } + + glDeleteTextures(1, &oldId); } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &fbo); - glDeleteTextures(1, &oldId); } // Re-sync the sampler to force access to the new mip level diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 5903be11d3..e4fc8420da 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -200,7 +200,7 @@ const QImage& image, bool isLinear, bool doCompress) { } } -#define CPU_MIPMAPS 0 +#define CPU_MIPMAPS 1 void generateMips(gpu::Texture* texture, QImage& image, gpu::Element formatMip) { #if CPU_MIPMAPS From e8cdee71ed5eef4b0e9106d38d27f0467a1dc4d7 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 3 Feb 2017 22:49:41 -0800 Subject: [PATCH 28/79] avoid assertion on mac --- interface/src/avatar/CauterizedModel.cpp | 4 ++-- libraries/fbx/src/FBXReader_Node.cpp | 4 +++- libraries/gpu/src/gpu/Image.cpp | 4 ++-- libraries/gpu/src/gpu/Image.h | 6 +++--- libraries/model/src/model/TextureMap.cpp | 4 ++-- libraries/render-utils/src/Model.cpp | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/CauterizedModel.cpp b/interface/src/avatar/CauterizedModel.cpp index 02107e9d24..f6b470f024 100644 --- a/interface/src/avatar/CauterizedModel.cpp +++ b/interface/src/avatar/CauterizedModel.cpp @@ -116,7 +116,7 @@ void CauterizedModel::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig->getJointTransform(cluster.jointIndex); -#if GLM_ARCH & GLM_ARCH_SSE2 +#if (GLM_ARCH & GLM_ARCH_SSE2) && !(defined Q_OS_MACOS) glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); state.clusterMatrices[j] = out; @@ -155,7 +155,7 @@ void CauterizedModel::updateClusterMatrices() { if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) { jointMatrix = cauterizeMatrix; } -#if GLM_ARCH & GLM_ARCH_SSE2 +#if (GLM_ARCH & GLM_ARCH_SSE2) && !(defined Q_OS_MACOS) glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); state.clusterMatrices[j] = out; diff --git a/libraries/fbx/src/FBXReader_Node.cpp b/libraries/fbx/src/FBXReader_Node.cpp index 435c4d830b..61bd3321cb 100644 --- a/libraries/fbx/src/FBXReader_Node.cpp +++ b/libraries/fbx/src/FBXReader_Node.cpp @@ -62,7 +62,9 @@ template QVariant readBinaryArray(QDataStream& in, int& position) { position += sizeof(T) * arrayLength; in.readRawData(arrayData.data(), arrayData.size()); } - memcpy(&values[0], arrayData.constData(), arrayData.size()); + if (!arrayData.isEmpty()) { + memcpy(&values[0], arrayData.constData(), arrayData.size()); + } } else { values.reserve(arrayLength); const unsigned int DEFLATE_ENCODING = 1; diff --git a/libraries/gpu/src/gpu/Image.cpp b/libraries/gpu/src/gpu/Image.cpp index 5de1008d8f..4d08307fbb 100644 --- a/libraries/gpu/src/gpu/Image.cpp +++ b/libraries/gpu/src/gpu/Image.cpp @@ -27,7 +27,7 @@ template <> void uncompress(const CB_BC1& src, PB_RGB32& dst) { auto c0 = bc1.color0.val; auto c1 = bc1.color1.val; - for (int i = 0; i < PB_RGB32::SIZE; ++i) { + for (int i = 0; i < PB_RGB32::LENGTH; ++i) { //dst.pixels[i] = ; auto r = pixel::mix( c0, @@ -44,4 +44,4 @@ template <> void uncompress(const CB_BC4& src, PB_RGBA32& dst) { } -} \ No newline at end of file +} diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h index 67d2071c4a..e6dc944b3b 100644 --- a/libraries/gpu/src/gpu/Image.h +++ b/libraries/gpu/src/gpu/Image.h @@ -99,8 +99,8 @@ namespace image { using Format = typename P::Format; using Storage = typename P::Storage; - constexpr uint16_t getLength() const { return length; } - uint32_t getSize() const { return length * sizeof(P); } + static const uint32_t LENGTH { length }; + static const uint32_t SIZE { length * sizeof(P) }; P pixels[length]; @@ -112,7 +112,7 @@ namespace image { } void setPixels(const P* srcPixels) { - memcpy(pixels, srcPixels, getSize()); + memcpy(pixels, srcPixels, SIZE); } const Storage* getStorage() const { return static_cast (&pixels->raw); } diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 9f62c9abbc..7436306f3c 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -255,7 +255,7 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); - image::PixRGB32 pix0; + /* image::PixRGB32 pix0; image::PixRGBA32 pix1; @@ -280,7 +280,7 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag image::uncompress(cb, pb1); image::Grid grid; - grid. + grid.*/ if (generateMips) { ::generateMips(theTexture, image, formatMip); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 018a7e6954..5da21f0487 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1183,7 +1183,7 @@ void Model::updateClusterMatrices() { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig->getJointTransform(cluster.jointIndex); -#if GLM_ARCH & GLM_ARCH_SSE2 +#if (GLM_ARCH & GLM_ARCH_SSE2) && !(defined Q_OS_MACOS) glm::mat4 out, inverseBindMatrix = cluster.inverseBindMatrix; glm_mat4_mul((glm_vec4*)&jointMatrix, (glm_vec4*)&inverseBindMatrix, (glm_vec4*)&out); state.clusterMatrices[j] = out; From 534d3c581c03d9750e7a95d870142fea1440de6d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 7 Feb 2017 11:50:44 -0800 Subject: [PATCH 29/79] Update EntityEditSender PPS to be 3000 in ESS --- assignment-client/src/scripts/EntityScriptServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 7f4593910e..8790f0eccb 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -30,6 +30,7 @@ int EntityScriptServer::_entitiesScriptEngineCount = 0; EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) { + _entityEditSender.setPacketsPerSecond(3000); DependencyManager::get()->setPacketSender(&_entityEditSender); ResourceManager::init(); From e7244b47a9e9b6f96e66390f5194af847dd5a307 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Tue, 7 Feb 2017 21:55:55 +0000 Subject: [PATCH 30/79] increase LETTER_OFFSET value allow more room for characters, could be improved by detecting each one --- scripts/system/nameTag.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/system/nameTag.js b/scripts/system/nameTag.js index 88f7ab1f89..e25db69064 100644 --- a/scripts/system/nameTag.js +++ b/scripts/system/nameTag.js @@ -21,7 +21,7 @@ const TTL = 2; // time to live in seconds if script is not running const HEIGHT_ABOVE_HEAD = 0.2; const HEAD_OFFSET = -0.025; const SIZE_Y = 0.075; -const LETTER_OFFSET = 0.0225; +const LETTER_OFFSET = 0.03; // arbitrary value to dynamically change width, could be more accurate by detecting characters const LINE_HEIGHT = 0.05; var nameTagEntityID = NULL_UUID; @@ -35,7 +35,7 @@ Script.setTimeout(function() { function addNameTag() { var nameTagPosition = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(HEAD_OFFSET, Quat.getFront(MyAvatar.orientation))); nameTagPosition.y += HEIGHT_ABOVE_HEAD; - var modelNameTagProperties = { + var nameTagProperties = { name: MyAvatar.displayName + ' Name Tag', type: 'Text', text: MyAvatar.displayName, @@ -44,7 +44,7 @@ function addNameTag() { dimensions: dimensionsFromName(), position: nameTagPosition } - nameTagEntityID = Entities.addEntity(modelNameTagProperties, CLIENTONLY); + nameTagEntityID = Entities.addEntity(nameTagProperties, CLIENTONLY); } function updateNameTag() { @@ -73,7 +73,7 @@ function dimensionsFromName() { x: LETTER_OFFSET * MyAvatar.displayName.length, y: SIZE_Y, z: 0.0 - }; + } }; // cleanup on ending From 7b49f548ed191ab2a878fe80a0adfc2b3ad5f22e Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 7 Feb 2017 18:06:49 -0800 Subject: [PATCH 31/79] trying to remove the 24bits formats --- .../gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 1 - libraries/model/src/model/TextureMap.cpp | 29 ++++++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index 179297069f..14c0a3923a 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -113,7 +113,6 @@ void GLTextureTransferHelper::queueExecution(VoidLambda lambda) { #define MAX_TRANSFERS_PER_PASS 2 bool GLTextureTransferHelper::process() { - PROFILE_RANGE(render_gpu_gl, __FUNCTION__) // Take any new textures or commands off the queue VoidLambdaList pendingCommands; TextureList newTransferTextures; diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index feca360531..e71616ebf7 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -334,15 +334,20 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src PROFILE_RANGE(resource_parse, "createNormalTextureFromNormalImage"); QImage image = processSourceImage(srcImage, false); - if (image.format() != QImage::Format_RGB888) { + /* if (image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); + }*/ + if (image.format() != QImage::Format_ARGB32) { + image = image.convertToFormat(QImage::Format_ARGB32); } gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + // gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + // gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + gpu::Element formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + gpu::Element formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture->setSource(srcImageName); @@ -378,7 +383,8 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm const double pStrength = 2.0; int width = image.width(); int height = image.height(); - QImage result(width, height, QImage::Format_RGB888); + //QImage result(width, height, QImage::Format_RGB888); + QImage result(width, height, QImage::Format_ARGB32); for (int i = 0; i < width; i++) { const int iNextClamped = clampPixelCoordinate(i + 1, width - 1); @@ -426,8 +432,11 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + + // gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + // gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + gpu::Element formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + gpu::Element formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture->setSource(srcImageName); @@ -810,10 +819,14 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm gpu::Texture* theTexture = nullptr; if ((srcImage.width() > 0) && (srcImage.height() > 0)) { QImage image = processSourceImage(srcImage, true); - if (image.format() != QImage::Format_RGB888) { - image = image.convertToFormat(QImage::Format_RGB888); + if (image.format() != QImage::Format_ARGB32) { + image = image.convertToFormat(QImage::Format_ARGB32); } + /* if (image.format() != QImage::Format_RGB888) { + image = image.convertToFormat(QImage::Format_RGB888); + }*/ + gpu::Element formatGPU; gpu::Element formatMip; defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress); From 7db86204d191fbfa61e2950484cd689c9a6e709d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 8 Feb 2017 00:01:48 +0000 Subject: [PATCH 32/79] general function to load QML for javascript for tablet (cherry picked from commit b50e20c5457151368b7ead81bf44ce678de9dbe2) --- libraries/script-engine/src/TabletScriptingInterface.cpp | 8 ++++++++ libraries/script-engine/src/TabletScriptingInterface.h | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index 2414ec469f..e7f8ebe2cb 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -212,6 +212,14 @@ void TabletProxy::gotoMenuScreen() { } } +void TabletProxy::loadQMLSource(const QVariant& path) { + if (_qmlTabletRoot) { + if (_state != State::QML) { + QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, path)); + _state = State::QML; + } + } +} void TabletProxy::gotoHomeScreen() { if (_qmlTabletRoot) { if (_state != State::Home) { diff --git a/libraries/script-engine/src/TabletScriptingInterface.h b/libraries/script-engine/src/TabletScriptingInterface.h index 4fe2c44c10..a005152fa9 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.h +++ b/libraries/script-engine/src/TabletScriptingInterface.h @@ -89,6 +89,8 @@ public: Q_INVOKABLE void gotoWebScreen(const QString& url); Q_INVOKABLE void gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl); + Q_INVOKABLE void loadQMLSource(const QVariant& path); + /**jsdoc * Creates a new button, adds it to this and returns it. * @function TabletProxy#addButton @@ -149,7 +151,7 @@ protected: QQuickItem* _qmlTabletRoot { nullptr }; QObject* _qmlOffscreenSurface { nullptr }; - enum class State { Uninitialized, Home, Web, Menu }; + enum class State { Uninitialized, Home, Web, Menu, QML }; State _state { State::Uninitialized }; }; From a137659a35f0d94bbcb255b72ad7d8e795f288ad Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 8 Feb 2017 11:13:55 -0800 Subject: [PATCH 33/79] Cleaning up pr for simpler merge --- libraries/gpu/src/gpu/Image.cpp | 43 -- libraries/gpu/src/gpu/Image.h | 492 ----------------------- libraries/model/src/model/TextureMap.cpp | 54 +-- 3 files changed, 3 insertions(+), 586 deletions(-) delete mode 100644 libraries/gpu/src/gpu/Image.cpp delete mode 100644 libraries/gpu/src/gpu/Image.h diff --git a/libraries/gpu/src/gpu/Image.cpp b/libraries/gpu/src/gpu/Image.cpp deleted file mode 100644 index 825803a7d9..0000000000 --- a/libraries/gpu/src/gpu/Image.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "Image.h" - - -int image::BC::cpp { 0 }; - -namespace image { - - namespace pixel { - template <> const RGB16_565 mix(const RGB16_565 p0, const RGB16_565 p1, const Byte alpha) { - return RGB16_565( - mix5_4(p0.r, p1.r, alpha), - mix6_4(p0.g, p1.g, alpha), - mix5_4(p0.b, p1.b, alpha)); - } - } - -template <> void compress(const PB_RGB32& src, CB_BC1& dst) { -} - -template <> void uncompress(const CB_BC1& src, PB_RGB32& dst) { - auto bc1 = src.bc; - - auto c0 = bc1.color0.val; - auto c1 = bc1.color1.val; - - for (int i = 0; i < PB_RGB32::LENGTH; ++i) { - //dst.pixels[i] = ; - auto r = pixel::mix( - c0, - c1, - (Byte)bc1.table); - } -} - -template <> void compress(const PB_RGBA32& src, CB_BC4& dst) { - -} - -template <> void uncompress(const CB_BC4& src, PB_RGBA32& dst) { - -} - -} diff --git a/libraries/gpu/src/gpu/Image.h b/libraries/gpu/src/gpu/Image.h deleted file mode 100644 index fd59406975..0000000000 --- a/libraries/gpu/src/gpu/Image.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - Let s try compressing images - -*/ - -#include -#include "Forward.h" - - -namespace image { - - // Storage types - using Byte = uint8_t; - using Byte2 = uint16_t; - using Byte4 = uint32_t; - using Byte8 = uint64_t; - - // Storage type selector based on size (sizeof of a type) - template - struct storage { typedef T1 type; }; - - template - struct storage<2, T1, T2, T4, T8> { typedef T2 type; }; - - template - struct storage<4, T1, T2, T4, T8> { typedef T4 type; }; - - template - struct storage<8, T1, T2, T4, T8> { typedef T8 type; }; - - static const Byte BLACK8 { 0 }; - static const Byte WHITE8 { 255 }; - - template int bitVal() { return 1 << N; } - template int bitProduct() { return bitVal() * bitVal(); } - template T mix(const T x, const T y, const A a) { return T(((bitVal() - a) * x + a * y) / bitProduct()); } - - Byte mix5_4(const Byte x, const Byte y, const Byte a) { return mix<5, 4>(x, y, a); } - Byte mix6_4(const Byte x, const Byte y, const Byte a) { return mix<6, 4>(x, y, a); } - - - - // Coordinate and count types - using Coord = uint16_t; - using Coord2 = glm::u16vec2; - using Count = uint32_t; - using Index = uint32_t; - - // Maximum pixel along one direction coord is 32768 - static const Coord MAX_COORD { 32768 }; - // Maximum number of pixels in an image - static const Count MAX_COUNT { MAX_COORD * MAX_COORD }; - static const Index MAX_INDEX { MAX_COUNT }; - - - namespace pixel { - - struct RGB32 { - Byte r { BLACK8 }; - Byte g { BLACK8 }; - Byte b { BLACK8 }; - Byte x { WHITE8 }; - }; - - struct RGBA32 { - Byte r { BLACK8 }; - Byte g { BLACK8 }; - Byte b { BLACK8 }; - Byte a { WHITE8 }; - }; - - struct R10G10B12 { - Byte4 r : 10; - Byte4 g : 10; - Byte4 b : 12; - }; - - struct RGB16_565 { - Byte2 b : 5; - Byte2 g : 6; - Byte2 r : 5; - - RGB16_565() : b(BLACK8), g(BLACK8), r(BLACK8) {} - RGB16_565(Byte pR, Byte pG, Byte pB) : b(pB), g(pG), r(pR) {} - }; - - struct R8 { - Byte r { BLACK8 }; - }; - - - template const P mix(const P p0, const P p1, const S alpha) { return p0; } - template <> const RGB16_565 mix(const RGB16_565 p0, const RGB16_565 p1, const Byte alpha); - - template ::type > class Pixel { - public: - using This = Pixel; - using Format = F; - using Storage = S; - - static const uint32_t SIZE { sizeof(S) }; - - Format val { Format() }; - - Pixel() : val(Format()) {}; - Pixel(Format v) : val(v) {} - Pixel(Storage s) : val(*static_cast (&s)) {} - - const Storage* storage() const { return static_cast (&val); } - - static This* cast(Storage* s) { return reinterpret_cast(s); } - static const This* cast(const Storage* s) { return reinterpret_cast(s); } - }; - - template class PixelBlock { - public: - using Format = typename P::Format; - using Storage = typename P::Storage; - - static const uint16_t LENGTH { length }; - static const uint32_t SIZE { length * sizeof(P) }; - - P pixels[length]; - - PixelBlock() {} - - PixelBlock(const P* srcPixels) { - setPixels(srcPixels); - } - - void setPixels(const P* srcPixels) { - memcpy(pixels, srcPixels, SIZE); - } - - const Storage* storage() const { return pixels->storage(); } - }; - - template class Tile { - public: - using Format = typename P::Format; - using Storage = typename P::Storage; - - using Block = PixelBlock; - - uint16_t getWidth() const { return tileW; } - uint16_t getHeight() const { return tileH; } - - Block _block; - - Tile() {} - Tile(const P* srcPixels) : _block(srcPixels) {} - - - }; - }; - - - - using PixRGB565 = pixel::Pixel; - using PixRGB32 = pixel::Pixel; - using PixRGBA32 = pixel::Pixel; - using PixR10G10B12 = pixel::Pixel; - using PixR8 = pixel::Pixel; - - - class BC { - public: - static int cpp; - - struct BC1 { - PixRGB565 color0; - PixRGB565 color1; - Byte4 table; - }; - - struct BC4 { - PixRGB565 color0; - PixRGB565 color1; - Byte4 table; - }; - }; - - template ::type> class CompressedBlock { - public: - using Format = F; - using Storage = S; - - static const uint32_t SIZE { sizeof(F) }; - - Format bc; - - CompressedBlock() {} - - const Storage* storage() const { return static_cast (&bc); } - }; - - - template void compress(const PB& srcBlock, CB& dstBlock) { } - template void uncompress(const CB& srcBlock, PB& dstBlock) { } - - - using PB_RGB32 = pixel::PixelBlock; - using PB_RGBA32 = pixel::PixelBlock; - - using CB_BC1 = CompressedBlock; - using CB_BC4 = CompressedBlock; - - template <> void compress(const PB_RGB32& src, CB_BC1& dst); - template <> void compress(const PB_RGBA32& src, CB_BC4& dst); - - template <> void uncompress(const CB_BC1& src, PB_RGB32& dst); - template <> void uncompress(const CB_BC4& src, PB_RGBA32& dst); - - - template - class PixelArray { - public: - using This = PixelArray

; - using Pixel = P; - using Storage = typename P::Storage; - - static int evalNumPixels(size_t byteSize) { - size_t numPixels = byteSize / Pixel::SIZE; - if (byteSize > numPixels * Pixel::SIZE) { - numPixels++; - } - return (int)numPixels; - }; - static size_t evalByteSize(int numPixels) { - return numPixels * Pixel::SIZE; - }; - - struct Storages { - Storage* _bytes {nullptr}; - Count _count {0}; - - Storage* data() { - return _bytes; - } - const Storage* data() const { - return _bytes; - } - - Count count() const { return _count; } - - ~Storages() { if (_bytes) { delete _bytes; } } - Storages() {} - Storages(Count c) : _count(c) { if (_count) { _bytes = new Storage[_count]; } - - } - }; - - - - PixelArray() { - resetBytes(0, nullptr); - } - PixelArray(size_t byteSize, const void* bytes) { - resetBytes(byteSize, bytes); - } - PixelArray(const PixelArray& src) { - resetBytes(src.byteSize(), src.readBytes(0)); - } - PixelArray(PixelArray&& src) { - _buffer.reset(src._buffer.release()); - } - This& operator = (This&& src) { - _buffer.reset(src._buffer.release()); - } - - int numPixels() const { return _buffer->count(); } - size_t byteSize() const { return evalByteSize(_buffer->count()); } - - //access storage or pixel types at index in the buffer - const Storage* readBytes(const Index index) const { return _buffer->data() + index; } - const Pixel* readPixel(const Index index) const { return Pixel::cast(readBytes(index)); } - - Storage* editBytes(const Index index) { return _buffer->data() + index; } - Pixel* editPixel(const Index index) { return Pixel::cast(editBytes(index)); } - - private: - std::unique_ptr _buffer; - - void resetBytes(size_t byteSize, const void* bytes) { - _buffer.reset(new Storages(evalNumPixels(byteSize))); - if (bytes) { - memcpy(_buffer->data(), bytes, byteSize); - } - } - }; - - template - class PixelBlockArray { - public: - using Block = B; - using Blocks = std::vector; - - static int evalNumBlocks(size_t byteSize) { - size_t numBlocks = byteSize / Block::SIZE; - if (byteSize > numBlocks * Block::SIZE) { - numBlocks++; - } - return (int) numBlocks; - }; - static size_t evalByteSize(int numBlocks) { - return numBlocks * Block::SIZE; - }; - - PixelBlockArray(size_t byteSize, const void* bytes) { - setBytes(byteSize, bytes); - } - - int numBlocks() const { return evalByteSize(_blocks.size()); } - size_t byteSize() const { return evalByteSize(_blocks.size()); } - - Blocks _blocks; - - private: - void setBytes(size_t byteSize, const void* bytes) { - _blocks = Blocks(evalNumBlocks(byteSize)); - if (bytes) { - memcpy(_blocks.data(), bytes, byteSize); - } - } - }; - - class Grid { - public: - using Coord = uint16_t; - using Coord2 = glm::u16vec2; - using Size = uint32_t; - - static const Coord2 TILE_PIXEL; - static const Coord2 TILE_QUAD; - static const Coord2 TILE_DEFAULT; - - Grid(const Coord2& surface, const Coord2& tile = TILE_DEFAULT) : _surface(surface), _tile(tile) {} - Grid(Coord width, Coord height, const Coord2& tile = TILE_DEFAULT) : _surface(width, height), _tile(tile) {} - - Coord2 _surface { 1, 1 }; - Coord2 _tile { TILE_DEFAULT }; - - Coord width() const { return _surface.x; } - Coord height() const { return _surface.y; } - const Coord2& size() const { return _surface; } - - Coord tileWidth() const { return evalNumTiles(_surface.x, _tile.x); } - Coord tileHeight() const { return evalNumTiles(_surface.y, _tile.y); } - Coord2 tileSize() const { return Coord2(tileWidth(), tileHeight()); } - - - Coord2 toTile(const Coord2& pixel) const { return pixel / _tile; } - Coord2 toTileSubpix(const Coord2& pixel) const { return pixel % _tile; } - Coord2 toTile(const Coord2& pixel, Coord2& subpix) const { - subpix = toTileSubpix(pixel); - return toTile(pixel); - } - - Coord2 toPixel(const Coord2& tile) const { return tile * _tile; } - Coord2 toPixel(const Coord2& tile, const Coord2& subpix) const { return tile * _tile + subpix; } - - - static Coord evalNumTiles(Coord pixelLength, Coord tileLength) { - auto tilePos = pixelLength / tileLength; - if (tilePos * tileLength < pixelLength) { - tilePos++; - } - return tilePos; - } - }; - - template - class Tilemap { - public: - using Tile = T; - using Block = typename T::Block; - - Grid _grid; - PixelBlockArray _blocks; - - void resize(const Grid::Coord2& widthHeight) { - _grid = Grid(widthHeight, Coord2(Tile::getWidth(), Tile::getHeight())); - - } - - }; - - class Dim { - public: - - Coord2 _dims { 0 }; - - static Coord cap(Coord c) { return (c < MAX_COORD ? c : MAX_COORD); } - static Coord2 cap(const Coord2& dims) { return Coord2(cap(dims.x), cap(dims.y)); } - - static Count numPixels(const Coord2& dims) { return Count(cap(dims.x)) * Count(cap(dims.y)); } - - - static Coord nextMip(Coord c) { return (c > 1 ? (c >> 1) : c); } - static Coord2 nextMip(const Coord2& dims) { return Coord2(nextMip(dims.x), nextMip(dims.y)); } - - Dim(Coord w, Coord h) : _dims(w, h) {} - Dim(const Coord2& dims) : _dims(dims) {} - - Count numPixels() const { return Dim::numPixels(_dims); } - Dim nextMip() const { return Dim(nextMip(_dims)); } - - int maxLevel() const { - int level = 0; - auto dim = (*this); - while (dim._dims.x > 1 || dim._dims.y > 1) { - level++; - dim = dim.nextMip(); - } - return level; - } - - Index indexAt(Coord x, Coord y) const { return (Index) y * (Index) _dims.x + (Index) x; } - }; - - template < typename P > class Surface { - public: - using This = Surface

; - using Pixel = P; - using Format = typename P::Format; - using Pixels = PixelArray

; - - Dim _dim { 0, 0 }; - Pixels _pixels; - - /* Surface(This&& src) { - _dim = src._dim; - _pixels = src._pixels; - - }*/ - Surface(Coord width, Coord height, size_t byteSize = 0, const void* bytes = nullptr) : - _dim(width, height), - _pixels((byteSize ? byteSize : Pixels::evalByteSize(width * height)), bytes) - {} - - This nextMip() const { - Dim subDim = _dim.nextMip(); - auto sub = Surface

(subDim._dims.x, subDim._dims.y); - - for (int y = 0; y < subDim._dims.y; y++) { - for (int x = 0; x < subDim._dims.x; x++) { - - // get pixels from source at 2x, 2x +1 2y, 2y +1 - auto srcIndex0 = _dim.indexAt(2 * x, 2 * y); - auto srcIndex1 = _dim.indexAt(2 * x, 2 * y + 1); - - auto srcP0 = (*_pixels.readPixel(srcIndex0)); - auto srcP01 = (*_pixels.readPixel(srcIndex0 + 1)); - auto srcP1 = (*_pixels.readPixel(srcIndex1)); - auto srcP11 = (*_pixels.readPixel(srcIndex1 + 1)); - - // and filter - auto destIndex = subDim.indexAt(x, y); - auto destP = sub._pixels.editPixel(destIndex); - - // assign to dest - *destP = srcP0; - } - } - return sub; - } - - void downsample(std::vector& mips, int num) const { - if (num == 0) { - return; - } - auto maxLevel = _dim.maxLevel(); - - if (num == -1 || num > maxLevel) { - num = maxLevel; - } - else if (num < -1) { - return; - } - - - mips.emplace_back(nextMip()); - - for (int i = 1; i < num; i++) { - mips.emplace_back(mips.back().nextMip()); - } - - } - - }; -} - diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index e71616ebf7..97005b2b01 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -17,7 +17,6 @@ #include #include "ModelLogging.h" -#include using namespace model; using namespace gpu; @@ -142,7 +141,7 @@ const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& val validAlpha = (numOpaques != NUM_PIXELS); } - //if (!validAlpha && image.format() != QImage::Format_RGB888) { + // Force all the color images to be rgba32bits if (image.format() != QImage::Format_ARGB32) { image = image.convertToFormat(QImage::Format_ARGB32); } @@ -255,57 +254,10 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag } theTexture->setUsage(usage.build()); - - /* image::PixRGB32 pix0; - - image::PixRGBA32 pix1; - - image::PixR8 pix2; - - image::PixRGB565 pix3; - - image::PB_RGB32 pb0; - image::PB_RGB32 pb1; - - auto pix0_s = sizeof(pix0); - auto pix1_s = sizeof(pix1); - auto pix2_s = sizeof(pix2); - auto pix3_s = sizeof(pix3); - - auto pb0_s = sizeof(pb0); - -*/ - - bool check = false; - if (image.width() == 2048) { - check = true; - } - image::Surface surface(image.width(), image.height(), image.byteCount(), image.constBits()); - - - theTexture->assignStoredMip(0, formatMip, surface._pixels.byteSize(), (const Byte *) surface._pixels.readBytes(0)); - - - // theMap(image.width(), image.height(), image.byteCount(), image.constBits()); + theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); if (generateMips) { - - { - - PROFILE_RANGE(resource_parse, "generateMipsSAM"); - auto numMips = theTexture->evalNumMips(); - - std::vector> mips; - - surface.downsample(mips, numMips); - - for (uint16 level = 1; level < numMips && (mips.size() <= level); ++level) { - - const auto& m = mips[level - 1]; - theTexture->assignStoredMip(level, formatMip, m._pixels.byteSize(), (const Byte *) m._pixels.readBytes(0)); - } - } - // ::generateMips(theTexture, image, formatMip); + ::generateMips(theTexture, image, formatMip); } } From 8a40e951ac21dc7cd2f349ae5db0f2866d015096 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 8 Feb 2017 11:35:50 -0800 Subject: [PATCH 34/79] clean the usage of glCopyImageSubData and provide a fall back for 4.2) --- .../src/gpu/gl45/GL45BackendTexture.cpp | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 37d238f95c..8ba90f447e 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -438,34 +438,36 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { // Copy the contents of the old texture to the new { PROFILE_RANGE(render_gpu_gl, "Blit"); - /* - GLuint fbo { 0 }; - glCreateFramebuffers(1, &fbo); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); - for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { - uint16 sourceMip = targetMip + mipDelta; - Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); - for (GLenum target : getFaceTargets(_target)) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, oldId, sourceMip); - (void)CHECK_GL_ERROR(); - glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, mipDimensions.x, mipDimensions.y); - (void)CHECK_GL_ERROR(); + // Preferred path only available in 4.3 + if (GLEW_VERSION_4_3) { + for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { + uint16 sourceMip = targetMip + mipDelta; + Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); + for (GLenum target : getFaceTargets(_target)) { + glCopyImageSubData( + oldId, target, sourceMip, 0, 0, 0, + _id, target, targetMip, 0, 0, 0, + mipDimensions.x, mipDimensions.y, 1 + ); + (void)CHECK_GL_ERROR(); + } } - } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &fbo); - */ - for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { - uint16 sourceMip = targetMip + mipDelta; - Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); - for (GLenum target : getFaceTargets(_target)) { - glCopyImageSubData( - oldId, target, sourceMip, 0, 0, 0, - _id, target, targetMip, 0, 0, 0, - mipDimensions.x, mipDimensions.y, 1 - ); - (void)CHECK_GL_ERROR(); + } else { + GLuint fbo { 0 }; + glCreateFramebuffers(1, &fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { + uint16 sourceMip = targetMip + mipDelta; + Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); + for (GLenum target : getFaceTargets(_target)) { + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, oldId, sourceMip); + (void)CHECK_GL_ERROR(); + glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, mipDimensions.x, mipDimensions.y); + (void)CHECK_GL_ERROR(); + } } + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &fbo); } glDeleteTextures(1, &oldId); From 9e959441954412746af577a3d57f9d2e174402dd Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 8 Feb 2017 11:36:34 -0800 Subject: [PATCH 35/79] clean the usage of glCopyImageSubData and provide a fall back for 4.2) --- .../src/gpu/gl45/GL45BackendTexture.cpp | 38 +++++-------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 8ba90f447e..6948a045a2 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -439,35 +439,17 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { { PROFILE_RANGE(render_gpu_gl, "Blit"); // Preferred path only available in 4.3 - if (GLEW_VERSION_4_3) { - for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { - uint16 sourceMip = targetMip + mipDelta; - Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); - for (GLenum target : getFaceTargets(_target)) { - glCopyImageSubData( - oldId, target, sourceMip, 0, 0, 0, - _id, target, targetMip, 0, 0, 0, - mipDimensions.x, mipDimensions.y, 1 - ); - (void)CHECK_GL_ERROR(); - } + for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { + uint16 sourceMip = targetMip + mipDelta; + Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); + for (GLenum target : getFaceTargets(_target)) { + glCopyImageSubData( + oldId, target, sourceMip, 0, 0, 0, + _id, target, targetMip, 0, 0, 0, + mipDimensions.x, mipDimensions.y, 1 + ); + (void)CHECK_GL_ERROR(); } - } else { - GLuint fbo { 0 }; - glCreateFramebuffers(1, &fbo); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); - for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { - uint16 sourceMip = targetMip + mipDelta; - Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); - for (GLenum target : getFaceTargets(_target)) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, oldId, sourceMip); - (void)CHECK_GL_ERROR(); - glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, mipDimensions.x, mipDimensions.y); - (void)CHECK_GL_ERROR(); - } - } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &fbo); } glDeleteTextures(1, &oldId); From 267d553c2639c190f3a123d7bab2441d3ea4cfb5 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 8 Feb 2017 11:42:23 -0800 Subject: [PATCH 36/79] Cleaning comments and pixel format assignments --- libraries/model/src/model/TextureMap.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 97005b2b01..839a704e54 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -286,18 +286,14 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src PROFILE_RANGE(resource_parse, "createNormalTextureFromNormalImage"); QImage image = processSourceImage(srcImage, false); - /* if (image.format() != QImage::Format_RGB888) { - image = image.convertToFormat(QImage::Format_RGB888); - }*/ + // Make sure the normal map source image is RGBA32 if (image.format() != QImage::Format_ARGB32) { image = image.convertToFormat(QImage::Format_ARGB32); } gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - - // gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); - // gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + gpu::Element formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); gpu::Element formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); @@ -335,7 +331,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm const double pStrength = 2.0; int width = image.width(); int height = image.height(); - //QImage result(width, height, QImage::Format_RGB888); + // THe end result image for normal map is RGBA32 even though the A is not used QImage result(width, height, QImage::Format_ARGB32); for (int i = 0; i < width; i++) { @@ -384,9 +380,6 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - - // gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); - // gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); gpu::Element formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); gpu::Element formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); @@ -775,10 +768,6 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm image = image.convertToFormat(QImage::Format_ARGB32); } - /* if (image.format() != QImage::Format_RGB888) { - image = image.convertToFormat(QImage::Format_RGB888); - }*/ - gpu::Element formatGPU; gpu::Element formatMip; defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress); From a871613f841e97c3c8ebb5518517bc9dd70b3ad5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 8 Feb 2017 11:49:40 -0800 Subject: [PATCH 37/79] make Settings::remove() work for groups --- libraries/shared/src/SettingHandle.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp index a04a7c3f61..2bfc904c0a 100644 --- a/libraries/shared/src/SettingHandle.cpp +++ b/libraries/shared/src/SettingHandle.cpp @@ -28,9 +28,10 @@ QString Settings::fileName() const { } void Settings::remove(const QString& key) { - if (key == "" || _manager->contains(key)) { - _manager->remove(key); - } + // NOTE: you can't check _manager->contains(key) here because it will return 'false' + // when the key is a valid child group with child keys. + // However, calling remove() without checking will do the right thing. + _manager->remove(key); } QStringList Settings::childGroups() const { @@ -46,6 +47,7 @@ QStringList Settings::allKeys() const { } bool Settings::contains(const QString& key) const { + // NOTE: this will return 'false' if key is a valid child group with child keys. return _manager->contains(key); } From cc301d1c1aaf7fb138a1f18682888c209eaa9ffa Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 8 Feb 2017 11:50:15 -0800 Subject: [PATCH 38/79] remove legacy empty avatarEntityData settings --- interface/src/avatar/MyAvatar.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d4815b35c6..120e626b9a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -931,6 +931,10 @@ void MyAvatar::loadData() { updateAvatarEntity(entityID, properties); } settings.endArray(); + if (avatarEntityCount == 0) { + // HACK: manually remove empty 'avatarEntityData' else legacy data may persist in settings file + settings.remove("avatarEntityData"); + } setAvatarEntityDataChanged(true); setDisplayName(settings.value("displayName").toString()); From eedfc4fd38435bc361fea1a38823a2190feb80a9 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 12:19:36 -0800 Subject: [PATCH 39/79] fix various bot related bugs --- assignment-client/src/Agent.cpp | 38 ++++++++++-- interface/src/avatar/Avatar.cpp | 1 - interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 1 - libraries/avatars/src/AvatarData.cpp | 83 ++++++++++++++++++++++++-- libraries/avatars/src/AvatarData.h | 32 ++++++++-- libraries/fbx/src/FBXReader.cpp | 2 + libraries/fbx/src/FBXReader.h | 1 + 8 files changed, 142 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 0ba83864c4..32076b60e3 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -138,7 +138,6 @@ void Agent::handleJurisdictionPacket(QSharedPointer message, Sh void Agent::handleAudioPacket(QSharedPointer message) { _receivedAudioStream.parseData(*message); - _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness(); _receivedAudioStream.clearBuffer(); } @@ -323,12 +322,14 @@ void Agent::scriptRequestFinished() { request->deleteLater(); } + void Agent::executeScript() { _scriptEngine = std::unique_ptr(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload)); _scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do // setup an Avatar for the script to use auto scriptedAvatar = DependencyManager::get(); + connect(_scriptEngine.get(), SIGNAL(update(float)), scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection); scriptedAvatar->setForceFaceTrackerConnected(true); @@ -338,11 +339,33 @@ void Agent::executeScript() { // give this AvatarData object to the script engine _scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data()); + auto player = DependencyManager::get(); + connect(player.data(), &recording::Deck::playbackStateChanged, [=] { + if (player->isPlaying()) { + auto recordingInterface = DependencyManager::get(); + if (recordingInterface->getPlayFromCurrentLocation()) { + scriptedAvatar->setRecordingBasis(); + } + } else { + scriptedAvatar->clearRecordingBasis(); + } + }); using namespace recording; static const FrameType AVATAR_FRAME_TYPE = Frame::registerFrameType(AvatarData::FRAME_NAME); - // FIXME how to deal with driving multiple avatars locally? Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [this, scriptedAvatar](Frame::ConstPointer frame) { + + auto recordingInterface = DependencyManager::get(); + bool useFrameSkeleton = recordingInterface->getPlayerUseSkeletonModel(); + + // FIXME - the ability to switch the avatar URL is not actually supported when playing back from a recording + if (!useFrameSkeleton) { + static std::once_flag warning; + std::call_once(warning, [] { + qWarning() << "Recording.setPlayerUseSkeletonModel(false) is not currently supported."; + }); + } + AvatarData::fromFrame(frame->data, *scriptedAvatar); }); @@ -352,8 +375,12 @@ void Agent::executeScript() { const QByteArray& audio = frame->data; static quint16 audioSequenceNumber{ 0 }; Transform audioTransform; + + auto avatarOrientation = scriptedAvatar->getOrientation(); + glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); // FIXME - should we be using head orientation of avatar orientation? audioTransform.setTranslation(scriptedAvatar->getPosition()); - audioTransform.setRotation(scriptedAvatar->getOrientation()); + audioTransform.setRotation(avatarOrientation); + QByteArray encodedBuffer; if (_encoder) { _encoder->encode(audio, encodedBuffer); @@ -537,7 +564,10 @@ void Agent::encodeFrameOfZeros(QByteArray& encodedZeros) { } void Agent::processAgentAvatarAudio() { - if (_isAvatar && (_isListeningToAudioStream || _avatarSound)) { + auto recordingInterface = DependencyManager::get(); + bool isPlayingRecording = recordingInterface->isPlaying(); + + if (_isAvatar && ((_isListeningToAudioStream && !isPlayingRecording) || _avatarSound)) { // if we have an avatar audio stream then send it out to our audio-mixer auto scriptedAvatar = DependencyManager::get(); bool silentFrame = true; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 64e82f63da..b8dea58cf1 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1010,7 +1010,6 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { void Avatar::setModelURLFinished(bool success) { if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) { - qDebug() << "Using default after failing to load Avatar model: " << _skeletonModelURL; // call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that // we don't redo this every time we receive an identity packet from the avatar with the bad url. QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index df3164e6fc..7906b654c3 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -134,7 +134,7 @@ Q_LOGGING_CATEGORY(trace_simulation_avatar, "trace.simulation.avatar"); float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& rateName) { auto avatar = getAvatarBySessionID(sessionID); - return avatar->getDataRate(rateName); + return avatar ? avatar->getDataRate(rateName) : 0.0f; } class AvatarPriority { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d4815b35c6..0174423ee9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1165,7 +1165,6 @@ void MyAvatar::clearJointsData() { } void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { - Avatar::setSkeletonModelURL(skeletonModelURL); render::ScenePointer scene = qApp->getMain3DScene(); _skeletonModel->setVisibleInScene(true, scene); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b25140d0a8..ce495494a8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -283,14 +283,20 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent destinationBuffer += sizeof(packetStateFlags); if (hasAvatarGlobalPosition) { + auto startSection = destinationBuffer; auto data = reinterpret_cast(destinationBuffer); data->globalPosition[0] = _globalPosition.x; data->globalPosition[1] = _globalPosition.y; data->globalPosition[2] = _globalPosition.z; destinationBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition); + + int numBytes = destinationBuffer - startSection; + + _globalPositionRateOutbound.increment(numBytes); } if (hasAvatarBoundingBox) { + auto startSection = destinationBuffer; auto data = reinterpret_cast(destinationBuffer); data->avatarDimensions[0] = _globalBoundingBoxDimensions.x; @@ -302,36 +308,56 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent data->boundOriginOffset[2] = _globalBoundingBoxOffset.z; destinationBuffer += sizeof(AvatarDataPacket::AvatarBoundingBox); + + int numBytes = destinationBuffer - startSection; + _avatarBoundingBoxRateOutbound.increment(numBytes); } if (hasAvatarOrientation) { + auto startSection = destinationBuffer; auto localOrientation = getLocalOrientation(); destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, localOrientation); + + int numBytes = destinationBuffer - startSection; + _avatarOrientationRateOutbound.increment(numBytes); } if (hasAvatarScale) { + auto startSection = destinationBuffer; auto data = reinterpret_cast(destinationBuffer); auto scale = getDomainLimitedScale(); packFloatRatioToTwoByte((uint8_t*)(&data->scale), scale); destinationBuffer += sizeof(AvatarDataPacket::AvatarScale); + + int numBytes = destinationBuffer - startSection; + _avatarScaleRateOutbound.increment(numBytes); } if (hasLookAtPosition) { + auto startSection = destinationBuffer; auto data = reinterpret_cast(destinationBuffer); auto lookAt = _headData->getLookAtPosition(); data->lookAtPosition[0] = lookAt.x; data->lookAtPosition[1] = lookAt.y; data->lookAtPosition[2] = lookAt.z; destinationBuffer += sizeof(AvatarDataPacket::LookAtPosition); + + int numBytes = destinationBuffer - startSection; + _lookAtPositionRateOutbound.increment(numBytes); } if (hasAudioLoudness) { + auto startSection = destinationBuffer; auto data = reinterpret_cast(destinationBuffer); data->audioLoudness = packFloatGainToByte(_headData->getAudioLoudness() / AUDIO_LOUDNESS_SCALE); destinationBuffer += sizeof(AvatarDataPacket::AudioLoudness); + + int numBytes = destinationBuffer - startSection; + _audioLoudnessRateOutbound.increment(numBytes); } if (hasSensorToWorldMatrix) { + auto startSection = destinationBuffer; auto data = reinterpret_cast(destinationBuffer); glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix(); packOrientationQuatToSixBytes(data->sensorToWorldQuat, glmExtractRotation(sensorToWorldMatrix)); @@ -341,9 +367,13 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent data->sensorToWorldTrans[1] = sensorToWorldMatrix[3][1]; data->sensorToWorldTrans[2] = sensorToWorldMatrix[3][2]; destinationBuffer += sizeof(AvatarDataPacket::SensorToWorldMatrix); + + int numBytes = destinationBuffer - startSection; + _sensorToWorldRateOutbound.increment(numBytes); } if (hasAdditionalFlags) { + auto startSection = destinationBuffer; auto data = reinterpret_cast(destinationBuffer); uint8_t flags { 0 }; @@ -370,27 +400,39 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent } data->flags = flags; destinationBuffer += sizeof(AvatarDataPacket::AdditionalFlags); + + int numBytes = destinationBuffer - startSection; + _additionalFlagsRateOutbound.increment(numBytes); } if (hasAvatarLocalPosition) { + auto startSection = destinationBuffer; auto data = reinterpret_cast(destinationBuffer); auto localPosition = getLocalPosition(); data->localPosition[0] = localPosition.x; data->localPosition[1] = localPosition.y; data->localPosition[2] = localPosition.z; destinationBuffer += sizeof(AvatarDataPacket::AvatarLocalPosition); + + int numBytes = destinationBuffer - startSection; + _localPositionRateOutbound.increment(numBytes); } if (hasParentInfo) { + auto startSection = destinationBuffer; auto parentInfo = reinterpret_cast(destinationBuffer); QByteArray referentialAsBytes = parentID.toRfc4122(); memcpy(parentInfo->parentUUID, referentialAsBytes.data(), referentialAsBytes.size()); parentInfo->parentJointIndex = _parentJointIndex; destinationBuffer += sizeof(AvatarDataPacket::ParentInfo); + + int numBytes = destinationBuffer - startSection; + _parentInfoRateOutbound.increment(numBytes); } // If it is connected, pack up the data if (hasFaceTrackerInfo) { + auto startSection = destinationBuffer; auto faceTrackerInfo = reinterpret_cast(destinationBuffer); faceTrackerInfo->leftEyeBlink = _headData->_leftEyeBlink; @@ -403,10 +445,14 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent // followed by a variable number of float coefficients memcpy(destinationBuffer, _headData->_blendshapeCoefficients.data(), _headData->_blendshapeCoefficients.size() * sizeof(float)); destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float); + + int numBytes = destinationBuffer - startSection; + _faceTrackerRateOutbound.increment(numBytes); } // If it is connected, pack up the data if (hasJointData) { + auto startSection = destinationBuffer; QReadLocker readLock(&_jointDataLock); // joint rotation data @@ -554,6 +600,9 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent << (destinationBuffer - startPosition); } #endif + + int numBytes = destinationBuffer - startSection; + _jointDataRateOutbound.increment(numBytes); } int avatarDataSize = destinationBuffer - startPosition; @@ -1028,6 +1077,30 @@ float AvatarData::getDataRate(const QString& rateName) { return _faceTrackerRate.rate() / BYTES_PER_KILOBIT; } else if (rateName == "jointData") { return _jointDataRate.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "globalPositionOutbound") { + return _globalPositionRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "localPositionOutbound") { + return _localPositionRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "avatarBoundingBoxOutbound") { + return _avatarBoundingBoxRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "avatarOrientationOutbound") { + return _avatarOrientationRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "avatarScaleOutbound") { + return _avatarScaleRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "lookAtPositionOutbound") { + return _lookAtPositionRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "audioLoudnessOutbound") { + return _audioLoudnessRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "sensorToWorkMatrixOutbound") { + return _sensorToWorldRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "additionalFlagsOutbound") { + return _additionalFlagsRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "parentInfoOutbound") { + return _parentInfoRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "faceTrackerOutbound") { + return _faceTrackerRateOutbound.rate() / BYTES_PER_KILOBIT; + } else if (rateName == "jointDataOutbound") { + return _jointDataRateOutbound.rate() / BYTES_PER_KILOBIT; } return 0.0f; } @@ -1842,8 +1915,7 @@ QJsonObject AvatarData::toJson() const { return root; } -void AvatarData::fromJson(const QJsonObject& json) { - +void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { int version; if (json.contains(JSON_AVATAR_VERSION)) { version = json[JSON_AVATAR_VERSION].toInt(); @@ -1865,7 +1937,7 @@ void AvatarData::fromJson(const QJsonObject& json) { if (json.contains(JSON_AVATAR_BODY_MODEL)) { auto bodyModelURL = json[JSON_AVATAR_BODY_MODEL].toString(); - if (bodyModelURL != getSkeletonModelURL().toString()) { + if (useFrameSkeleton && bodyModelURL != getSkeletonModelURL().toString()) { setSkeletonModelURL(bodyModelURL); } } @@ -1958,8 +2030,9 @@ QByteArray AvatarData::toFrame(const AvatarData& avatar) { } -void AvatarData::fromFrame(const QByteArray& frameData, AvatarData& result) { +void AvatarData::fromFrame(const QByteArray& frameData, AvatarData& result, bool useFrameSkeleton) { QJsonDocument doc = QJsonDocument::fromBinaryData(frameData); + #ifdef WANT_JSON_DEBUG { QJsonObject obj = doc.object(); @@ -1967,7 +2040,7 @@ void AvatarData::fromFrame(const QByteArray& frameData, AvatarData& result) { qCDebug(avatars).noquote() << QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Indented); } #endif - result.fromJson(doc.object()); + result.fromJson(doc.object(), useFrameSkeleton); } float AvatarData::getBodyYaw() const { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 52cf81798e..cd97a726bf 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -329,7 +329,7 @@ public: static const QString FRAME_NAME; - static void fromFrame(const QByteArray& frameData, AvatarData& avatar); + static void fromFrame(const QByteArray& frameData, AvatarData& avatar, bool useFrameSkeleton = true); static QByteArray toFrame(const AvatarData& avatar); AvatarData(); @@ -380,8 +380,13 @@ public: void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. virtual void updateAttitude() {} // Tell skeleton mesh about changes - glm::quat getHeadOrientation() const { return _headData->getOrientation(); } - void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); } + glm::quat getHeadOrientation() { + lazyInitHeadData(); + return _headData->getOrientation(); + } + void setHeadOrientation(const glm::quat& orientation) { if (_headData) _headData->setOrientation(orientation); } + void setLookAtPosition(const glm::vec3& lookAtPosition) { if (_headData) _headData->setLookAtPosition(lookAtPosition); } + void setBlendshapeCoefficients(const QVector& blendshapeCoefficients) { if (_headData) _headData->setBlendshapeCoefficients(blendshapeCoefficients); } // access to Head().set/getMousePitch (degrees) float getHeadPitch() const { return _headData->getBasePitch(); } @@ -513,7 +518,7 @@ public: TransformPointer getRecordingBasis() const; void setRecordingBasis(TransformPointer recordingBasis = TransformPointer()); QJsonObject toJson() const; - void fromJson(const QJsonObject& json); + void fromJson(const QJsonObject& json, bool useFrameSkeleton = true); glm::vec3 getClientGlobalPosition() { return _globalPosition; } glm::vec3 getGlobalBoundingBoxCorner() { return _globalPosition + _globalBoundingBoxOffset - _globalBoundingBoxDimensions; } @@ -528,7 +533,7 @@ public: Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const; Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const; - float getDataRate(const QString& rateName = QString("")); + Q_INVOKABLE float getDataRate(const QString& rateName = QString("")); int getJointCount() { return _jointData.size(); } @@ -596,7 +601,7 @@ protected: bool _forceFaceTrackerConnected; bool _hasNewJointData; // set in AvatarData, cleared in Avatar - HeadData* _headData; + HeadData* _headData { nullptr }; QUrl _skeletonModelURL; bool _firstSkeletonCheck { true }; @@ -659,6 +664,21 @@ protected: RateCounter<> _faceTrackerRate; RateCounter<> _jointDataRate; + // Some rate data for outgoing data + RateCounter<> _globalPositionRateOutbound; + RateCounter<> _localPositionRateOutbound; + RateCounter<> _avatarBoundingBoxRateOutbound; + RateCounter<> _avatarOrientationRateOutbound; + RateCounter<> _avatarScaleRateOutbound; + RateCounter<> _lookAtPositionRateOutbound; + RateCounter<> _audioLoudnessRateOutbound; + RateCounter<> _sensorToWorldRateOutbound; + RateCounter<> _additionalFlagsRateOutbound; + RateCounter<> _parentInfoRateOutbound; + RateCounter<> _faceTrackerRateOutbound; + RateCounter<> _jointDataRateOutbound; + + glm::vec3 _globalBoundingBoxDimensions; glm::vec3 _globalBoundingBoxOffset; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 42922ce226..71a8419091 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -537,6 +537,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS FBXGeometry* geometryPtr = new FBXGeometry; FBXGeometry& geometry = *geometryPtr; + geometry.originalURL = url; + float unitScaleFactor = 1.0f; glm::vec3 ambientColor; QString hifiGlobalNodeID; diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index cd1dbc5c4f..e2e6a8c004 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -281,6 +281,7 @@ class FBXGeometry { public: using Pointer = std::shared_ptr; + QString originalURL; QString author; QString applicationName; ///< the name of the application that generated the model From 42e9fed64ab3dc091be9fff55ee71a14978657ee Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 12:36:13 -0800 Subject: [PATCH 40/79] improved version of random recording bot script --- .../BetterClientSimulationBotFromRecording.js | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 script-archive/acScripts/BetterClientSimulationBotFromRecording.js diff --git a/script-archive/acScripts/BetterClientSimulationBotFromRecording.js b/script-archive/acScripts/BetterClientSimulationBotFromRecording.js new file mode 100644 index 0000000000..4ea26c3570 --- /dev/null +++ b/script-archive/acScripts/BetterClientSimulationBotFromRecording.js @@ -0,0 +1,186 @@ +// +// BetterClientSimulationBotFromRecording.js +// examples +// +// Created by Brad Hefta-Gaub on 2/6/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +var WANT_DEBUGGING = false; + +randFloat = function(low, high) { + return low + Math.random() * (high - low); +} + +var AVATARS_ARRAY = [ + "http://mpassets.highfidelity.com/0c2c264b-2fd2-46a4-bf80-de681881f66b-v1/F_MotRac.fst", + "http://mpassets.highfidelity.com/bd80a6d7-7173-489e-87c6-f7ee56e65530-v1/M_RetFut.fst", + "http://mpassets.highfidelity.com/47c8d706-d486-4c2d-afcc-70d4e1e25117-v1/M_RetSpaSuit.fst", + "http://mpassets.highfidelity.com/548d0792-0bac-4933-bbfc-57d71912d77e-v1/M_OutMer.fst", + "http://mpassets.highfidelity.com/13277c09-892f-4a5e-b9a5-8994a37d68bf-v1/F_WasWar.fst", + "http://mpassets.highfidelity.com/2d384111-0f0e-42e2-b800-66bfcab4aefb-v1/F_VooQue.fst", + "http://mpassets.highfidelity.com/57e4d1cd-9f52-4c95-9051-326f9bb114ea-v1/F_SteAvi.fst", + "http://mpassets.highfidelity.com/da2ad4cd-47d4-41da-b764-41f39ff77e30-v1/F_JerGir.fst", + "http://mpassets.highfidelity.com/96c747ab-f71b-44ee-8eb9-d19fc9593dda-v1/F_CatBur.fst", + "http://mpassets.highfidelity.com/ede82c38-c66e-4f67-9e0b-0bb0782db18f-v1/M_WesOut.fst", + "http://mpassets.highfidelity.com/8872ae86-a763-4db3-8373-d27514c1481e-v1/M_VinAvi.fst", + "http://mpassets.highfidelity.com/faf505f1-4fd1-4ed2-8909-816af246c48f-v1/M_VicGen.fst", + "http://mpassets.highfidelity.com/d807a7d2-5122-4436-a6f9-3173c94d1c49-v1/M_SuaGen.fst", + "http://mpassets.highfidelity.com/1dd41735-06f4-45a3-9ec0-d05215ace77b-v1/M_MarSen.fst", + "http://mpassets.highfidelity.com/2cad3894-8ab3-4ba5-a723-0234f93fbd6a-v1/M_BowBea.fst", + "http://mpassets.highfidelity.com/cf0eb1be-9ec7-4756-8eaf-ac8f3ec09eba-v1/F_ClaDef.fst", + "http://mpassets.highfidelity.com/0cedeca3-c1a4-4be9-9fd5-dad716afcc7e-v1/F_Cyria.fst", + "http://mpassets.highfidelity.com/dc55803b-9215-47dd-9408-eb835dac4082-v1/F_ParGir.fst", + "http://mpassets.highfidelity.com/775a8fb3-cfe7-494d-b603-a0a2d6910e55-v1/F_VinCov.fst", + "http://mpassets.highfidelity.com/eba0d8f8-aa72-4a6b-ab64-4d3fd4695b20-v1/F_VogHei.fst", + "http://mpassets.highfidelity.com/4f400c78-38f9-42af-b03b-11b5451d41b9-v1/M_MidRog.fst", + "http://mpassets.highfidelity.com/ad774d79-13f1-46e2-87c9-de49a261b264-v1/F_GunSli.fst", + "http://mpassets.highfidelity.com/5acbaefa-5455-49a2-8d40-89d12aa393ca-v1/M_KniWol.fst", + "http://mpassets.highfidelity.com/aaa1b0a8-3e1b-492a-9aee-600e5dc907db-v1/F_RetSciSuit.fst", + "http://mpassets.highfidelity.com/d8da10b6-25c1-40e2-9a66-369316c722d7-v1/F_AniSuit.fst", + "http://mpassets.highfidelity.com/f3fbb9f4-e159-49ed-ac32-03af9056b17e-v1/matthew.fst", + "http://mpassets.highfidelity.com/0c954ba0-4d87-4353-b65e-c45509f85658-v1/priscilla.fst", + "http://mpassets.highfidelity.com/e76946cc-c272-4adf-9bb6-02cde0a4b57d-v1/9e8c5c42a0cbd436962d6bd36f032ab3.fst", + "http://mpassets.highfidelity.com/72e083ee-194d-4113-9c61-0591d8257493-v1/skeleton_Rigged.fst", + "http://mpassets.highfidelity.com/f14bf7c9-49a1-4249-988a-0a577ed78957-v1/beingOfLight.fst", + "http://mpassets.highfidelity.com/1b7e1e7c-6c0b-4f20-9cd0-1d5ccedae620-v1/bb64e937acf86447f6829767e958073c.fst", + "http://mpassets.highfidelity.com/67d7c7aa-c300-4d03-85f4-86480130eaa5-v1/F_StarCrew.fst", + "http://mpassets.highfidelity.com/d293ef06-c659-467a-9288-c3cbaff0372a-v1/arya_avatar.fst", + "http://mpassets.highfidelity.com/faf249d5-12a8-48e2-a08e-fb0c33087011-v1/F_Ranger.fst", + "http://mpassets.highfidelity.com/b4502145-15eb-4023-b7d6-a81c5cbf6abf-v1/F_FitTra.fst", + "http://mpassets.highfidelity.com/548d0792-0bac-4933-bbfc-57d71912d77e-v1/M_OutMer.fst", + "http://mpassets.highfidelity.com/caa61e5d-5629-4165-81d8-6a7eb55e942d-v1/F_DeaSur.fst", + "http://mpassets.highfidelity.com/2cad3894-8ab3-4ba5-a723-0234f93fbd6a-v1/M_BowBea.fst", + "http://mpassets.highfidelity.com/fd4fa45a-9d2a-463e-a484-f9d1b3bba724-v1/M_BeaWar.fst", + "http://mpassets.highfidelity.com/367a5b60-8a92-4d56-a152-a00f3086f02b-v1/M_Espio.fst", + "http://mpassets.highfidelity.com/ab466729-31da-4b4c-a33c-366f7c1d38e5-v1/M_MMAFig.fst", + "http://mpassets.highfidelity.com/b0795a0c-493d-4abd-b4cc-5f32e6d6df46-v1/M_SalMer.fst", + "http://mpassets.highfidelity.com/0a1d44bf-a988-4199-b29e-a532ab85a2e8-v1/M_StaShi.fst", + "http://mpassets.highfidelity.com/d807a7d2-5122-4436-a6f9-3173c94d1c49-v1/M_SuaGen.fst", + "http://mpassets.highfidelity.com/cb20212c-36f2-4d41-bdad-132361ca6ff4-v1/M_TreTee.fst", + "http://mpassets.highfidelity.com/830988dc-619a-4e88-96e1-a19fa0aaa30f-v1/M_UrbEnf.fst", + "http://mpassets.highfidelity.com/faf505f1-4fd1-4ed2-8909-816af246c48f-v1/M_VicGen.fst", + "http://mpassets.highfidelity.com/883ac86f-dd29-4676-8bda-7dd52fb6465f-v1/M_WasWan.fst", + "http://mpassets.highfidelity.com/ede82c38-c66e-4f67-9e0b-0bb0782db18f-v1/M_WesOut.fst", + "http://mpassets.highfidelity.com/04c9a1e9-0390-4a7f-b6c6-5f135c19e3fb-v1/F_ArmTro.fst", + "http://mpassets.highfidelity.com/e863348f-a777-4f36-86e6-af6e65ffa161-v1/F_BloSam.fst", + "http://mpassets.highfidelity.com/cf0eb1be-9ec7-4756-8eaf-ac8f3ec09eba-v1/F_ClaDef.fst", + "http://mpassets.highfidelity.com/0cedeca3-c1a4-4be9-9fd5-dad716afcc7e-v1/F_Cyria.fst", + "http://mpassets.highfidelity.com/da2ad4cd-47d4-41da-b764-41f39ff77e30-v1/F_JerGir.fst", + "http://mpassets.highfidelity.com/534d42f8-ec13-4145-929f-5c8facac2fb7-v1/F_LegFig.fst", + "http://mpassets.highfidelity.com/dc55803b-9215-47dd-9408-eb835dac4082-v1/F_ParGir.fst", + "http://mpassets.highfidelity.com/f823e831-d8c4-4191-a3bd-427e406e69f9-v1/F_Shinjuku.fst", + "http://mpassets.highfidelity.com/eba0d8f8-aa72-4a6b-ab64-4d3fd4695b20-v1/F_VogHei.fst", + "http://mpassets.highfidelity.com/13277c09-892f-4a5e-b9a5-8994a37d68bf-v1/F_WasWar.fst", + "http://mpassets.highfidelity.com/9b589fbb-59e4-47a9-8b3f-bf8d3a0bd1d8-v1/M_LawSur.fst", + "http://mpassets.highfidelity.com/4f400c78-38f9-42af-b03b-11b5451d41b9-v1/M_MidRog.fst", + "http://mpassets.highfidelity.com/c90d755d-0456-48fd-b98c-09c4d85cd481-v1/M_MouOff.fst", + "http://mpassets.highfidelity.com/c2ed3b9a-b3a9-4424-9fd2-8a798209f32b-v1/M_PerTra.fst", + "http://mpassets.highfidelity.com/c48928ac-7657-41f4-bbdc-9b47385736ab-v1/M_SpaMar.fst", + "http://mpassets.highfidelity.com/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73-v1/4618d52e711fbb34df442b414da767bb.fst", + "http://mpassets.highfidelity.com/c85c497d-c87b-42b1-9bbf-5405e05a0ad3-v1/M_ArmSol.fst", + "http://mpassets.highfidelity.com/1dd41735-06f4-45a3-9ec0-d05215ace77b-v1/M_MarSen.fst", + "http://mpassets.highfidelity.com/bd80a6d7-7173-489e-87c6-f7ee56e65530-v1/M_RetFut.fst", + "http://mpassets.highfidelity.com/8872ae86-a763-4db3-8373-d27514c1481e-v1/M_VinAvi.fst", + "http://mpassets.highfidelity.com/f798d926-9a9e-481a-b298-af0e45451252-v1/F_Assassin.fst", + "http://mpassets.highfidelity.com/ad774d79-13f1-46e2-87c9-de49a261b264-v1/F_GunSli.fst", + "http://mpassets.highfidelity.com/aaa1b0a8-3e1b-492a-9aee-600e5dc907db-v1/F_RetSciSuit.fst" + ]; + + +var AVATAR_URL = AVATARS_ARRAY[Math.floor(Math.random() * AVATARS_ARRAY.length)]; +print("RANDOM AVATAR SELECTED:" + AVATAR_URL); + +var RECORDINGS_ARRAY = [ + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting1.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting2.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting3.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting4.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting5.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting6.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting7.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting8.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting9.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting10.hfr", + ]; + +var RECORDING_URL = RECORDINGS_ARRAY[Math.floor(Math.random() * RECORDINGS_ARRAY.length)]; +print("RANDOM RECORDING SELECTED:" + RECORDING_URL); + +// not quite what I want... +var LOCATIONS_ARRAY = [ + { min_x: 97.0, max_x: 103.0, y:-0.6, min_z: 30.8, max_z: 40 }, + { min_x: 92.7, max_x: 106.6, y:-0.3, min_z: 43 , max_z: 43 }, + { min_x: 92.7, max_x: 106.6, y: 0.3, min_z: 45 , max_z: 45 }, + { min_x: 92.7, max_x: 106.6, y: 1 , min_z: 47 , max_z: 47 }, + { min_x: 92.7, max_x: 106.6, y: 1.7, min_z: 51.9, max_z: 51.9 }, +]; + +var LOCATION_PARAMS = LOCATIONS_ARRAY[Math.floor(Math.random() * LOCATIONS_ARRAY.length)]; + +var LOCATION = { x: randFloat(LOCATION_PARAMS.min_x, LOCATION_PARAMS.max_x), y: LOCATION_PARAMS.y, z: randFloat(LOCATION_PARAMS.min_z, LOCATION_PARAMS.max_z) }; + +Vec3.print("RANDOM LOCATION SELECTED:", LOCATION); + +var playFromCurrentLocation = true; +var loop = true; + + +// Set position here if playFromCurrentLocation is true +Avatar.position = LOCATION; +Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); +Avatar.scale = 1.0; +Agent.isAvatar = true; + +// make the agent "listen" to the audio stream to cause additional audio-mixer load, technically this isn't needed when you're playing a recording +// but if you switch to a non-recording bot, you will need this, so we can leave this. +Agent.isListeningToAudioStream = true; +Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored + +Recording.loadRecording(RECORDING_URL); + +count = 300; // This is necessary to wait for the audio mixer to connect +function update(event) { + if (count > 0) { + count--; + return; + } + if (count == 0) { + Recording.setPlayFromCurrentLocation(playFromCurrentLocation); + Recording.setPlayerLoop(loop); + Recording.setPlayerUseDisplayName(true); + Recording.setPlayerUseAttachments(true); + Recording.setPlayerUseHeadModel(false); + Recording.setPlayerUseSkeletonModel(false); // FIXME - this would allow you to override the recording avatar, but that's not currently working + Recording.startPlaying(); + Vec3.print("Playing from ", Avatar.position); + count--; + } else if (WANT_DEBUGGING) { + count = 100; + Vec3.print("Avatar at: ", Avatar.position); + Quat.print("Avatar head orientation: ", Avatar.headOrientation); + print("outbound:" + +" GP: " + Avatar.getDataRate("globalPositionOutbound").toFixed(2) + "\n" + +" LP: " + Avatar.getDataRate("localPositionOutbound").toFixed(2) + "\n" + +" BB: " + Avatar.getDataRate("avatarBoundingBoxOutbound").toFixed(2) + "\n" + +" AO: " + Avatar.getDataRate("avatarOrientationOutbound").toFixed(2) + "\n" + +" AS: " + Avatar.getDataRate("avatarScaleOutbound").toFixed(2) + "\n" + +" LA: " + Avatar.getDataRate("lookAtPositionOutbound").toFixed(2) + "\n" + +" AL: " + Avatar.getDataRate("audioLoudnessOutbound").toFixed(2) + "\n" + +" SW: " + Avatar.getDataRate("sensorToWorkMatrixOutbound").toFixed(2) + "\n" + +" AF: " + Avatar.getDataRate("additionalFlagsOutbound").toFixed(2) + "\n" + +" PI: " + Avatar.getDataRate("parentInfoOutbound").toFixed(2) + "\n" + +" FT: " + Avatar.getDataRate("faceTrackerOutbound").toFixed(2) + "\n" + +" JD: " + Avatar.getDataRate("jointDataOutbound").toFixed(2)); + } + + if (!Recording.isPlaying()) { + Script.update.disconnect(update); + } +} + +Script.update.connect(update); From 89368afd68d3d87d9eafd7824462f05e56de7e19 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 12:52:17 -0800 Subject: [PATCH 41/79] add back accidentally removed line --- interface/src/avatar/Avatar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b8dea58cf1..5a059b318f 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1010,6 +1010,7 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { void Avatar::setModelURLFinished(bool success) { if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) { + qWarning(interfaceapp) << "Using default after failing to load Avatar model: " << _skeletonModelURL; // call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that // we don't redo this every time we receive an identity packet from the avatar with the bad url. QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", From f75eceda65c8d4fb956fd4e78ecc81157ff1d8ff Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 8 Feb 2017 13:11:18 -0800 Subject: [PATCH 42/79] Add entity PPS per script configuration --- .../src/scripts/EntityScriptServer.cpp | 52 ++++++++++++++++++- .../src/scripts/EntityScriptServer.h | 9 ++++ .../resources/describe-settings.json | 25 ++++++++- libraries/script-engine/src/ScriptEngine.cpp | 17 ++++++ libraries/script-engine/src/ScriptEngine.h | 5 ++ 5 files changed, 106 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 8790f0eccb..bd79d0fc04 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -30,7 +30,6 @@ int EntityScriptServer::_entitiesScriptEngineCount = 0; EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) { - _entityEditSender.setPacketsPerSecond(3000); DependencyManager::get()->setPacketSender(&_entityEditSender); ResourceManager::init(); @@ -101,6 +100,52 @@ void EntityScriptServer::handleEntityScriptGetStatusPacket(QSharedPointer(); + + auto& domainHandler = nodeList->getDomainHandler(); + const QJsonObject& settingsObject = domainHandler.getSettingsObject(); + + static const QString ENTITY_SCRIPT_SERVER_SETTINGS_KEY = "entity_script_server"; + + if (!settingsObject.contains(ENTITY_SCRIPT_SERVER_SETTINGS_KEY)) { + qWarning() << "Received settings from the domain-server with no entity_script_server section."; + return; + } + + auto entityScriptServerSettings = settingsObject[ENTITY_SCRIPT_SERVER_SETTINGS_KEY].toObject(); + + static const QString MAX_ENTITY_PPS_OPTION = "max_total_entity_pps"; + static const QString ENTITY_PPS_PER_SCRIPT = "entity_pps_per_script"; + + if (!entityScriptServerSettings.contains(MAX_ENTITY_PPS_OPTION) || !entityScriptServerSettings.contains(ENTITY_PPS_PER_SCRIPT)) { + qWarning() << "Received settings from the domain-server with no max_total_entity_pps or entity_pps_per_script properties."; + return; + } + + _maxEntityPPS = std::max(0, entityScriptServerSettings[MAX_ENTITY_PPS_OPTION].toInt()); + _entityPPSPerScript = std::max(0, entityScriptServerSettings[ENTITY_PPS_PER_SCRIPT].toInt()); + + qDebug() << QString("Received entity script server settings, Max Entity PPS: %1, Entity PPS Per Entity Script: %2") + .arg(_maxEntityPPS).arg(_entityPPSPerScript); +} + +void EntityScriptServer::updateEntityPPS() { + int numRunningScripts = _entitiesScriptEngine->getNumRunningEntityScripts(); + int pps; + if (std::numeric_limits::max() / _entityPPSPerScript < numRunningScripts) { + qWarning() << QString("Integer multiplaction would overflow, clamping to maxint: %1 * %2").arg(numRunningScripts).arg(_entityPPSPerScript); + pps = std::numeric_limits::max(); + pps = std::min(_maxEntityPPS, pps); + } else { + pps = _entityPPSPerScript * numRunningScripts; + pps = std::min(_maxEntityPPS, pps); + } + _entityEditSender.setPacketsPerSecond(pps); + qDebug() << QString("Updating entity PPS to: %1 @ %2 PPS per script = %3 PPS").arg(numRunningScripts).arg(_entityPPSPerScript).arg(pps); +} + void EntityScriptServer::run() { // make sure we request our script once the agent connects to the domain auto nodeList = DependencyManager::get(); @@ -115,6 +160,9 @@ void EntityScriptServer::run() { connect(messagesThread, &QThread::started, messagesClient.data(), &MessagesClient::init); messagesThread->start(); + DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); + connect(&domainHandler, &DomainHandler::settingsReceived, this, &EntityScriptServer::handleSettings); + // make sure we hear about connected nodes so we can grab an ATP script if a request is pending connect(nodeList.data(), &LimitedNodeList::nodeActivated, this, &EntityScriptServer::nodeActivated); connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &EntityScriptServer::nodeKilled); @@ -233,7 +281,9 @@ void EntityScriptServer::resetEntitiesScriptEngine() { newEngine->runInThread(); DependencyManager::get()->setEntitiesScriptEngine(newEngine.data()); + disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS); _entitiesScriptEngine.swap(newEngine); + connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS); } diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index 9ea2d43aec..70f03977f8 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -20,6 +20,9 @@ #include #include +static const int DEFAULT_MAX_ENTITY_PPS = 9000; +static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900; + class EntityScriptServer : public ThreadedAssignment { Q_OBJECT @@ -42,6 +45,9 @@ private slots: void handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode); void handleEntityScriptGetStatusPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleSettings(); + void updateEntityPPS(); + private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); @@ -62,6 +68,9 @@ private: EntityEditPacketSender _entityEditSender; EntityTreeHeadlessViewer _entityViewer; + int _maxEntityPPS { DEFAULT_MAX_ENTITY_PPS }; + int _entityPPSPerScript { DEFAULT_ENTITY_PPS_PER_SCRIPT }; + QString _selectedCodecName; CodecPluginPointer _codec; Encoder* _encoder { nullptr }; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 20d2711743..dd894ecb32 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -390,7 +390,7 @@ { "name": "maximum_user_capacity_redirect_location", "label": "Redirect to Location on Maximum Capacity", - "help": "Is there another domain, you'd like to redirect clients to when the maximum number of avatars are connected.", + "help": "The location to redirect users to when the maximum number of avatars are connected.", "placeholder": "", "default": "", "advanced": false @@ -1034,6 +1034,29 @@ } ] }, + { + "name": "entity_script_server", + "label": "Entity Script Server (ESS)", + "assignment-types": [5], + "settings": [ + { + "name": "entity_pps_per_script", + "label": "Entity PPS per script", + "help": "The number of packets per second (PPS) that can be sent to the entity server for each server entity script. This contributes to a total overall amount.
Example: 1000 PPS with 5 entites gives a total PPS of 5000 that is shared among the entity scripts. A single could use 4000 PPS, leaving 1000 for the rest, for example.", + "default": 900, + "type": "int", + "advanced": true + }, + { + "name": "max_total_entity_pps", + "label": "Maximum Total Entity PPS", + "help": "The maximum total packets per seconds (PPS) that can be sent to the entity server.
Example: 5 scripts @ 1000 PPS per script = 5000 total PPS. A maximum total PPS of 4000 would cap this 5000 total PPS to 4000.", + "default": 9000, + "type": "int", + "advanced": true + } + ] + }, { "name": "avatars", "label": "Avatars", diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2191d45d45..aa2817cc1f 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1393,6 +1393,16 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin } } +int ScriptEngine::getNumRunningEntityScripts() const { + int sum = 0; + for (auto& st : _entityScripts) { + if (st.status == RUNNING) { + ++sum; + } + } + return sum; +} + bool ScriptEngine::getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const { auto it = _entityScripts.constFind(entityID); if (it == _entityScripts.constEnd()) { @@ -1456,6 +1466,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co newDetails.status = ERROR_LOADING_SCRIPT; newDetails.errorInfo = "Failed to load script"; _entityScripts[entityID] = newDetails; + emit entityScriptDetailsUpdated(); return; } @@ -1467,6 +1478,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co newDetails.status = ERROR_RUNNING_SCRIPT; newDetails.errorInfo = "Bad syntax"; _entityScripts[entityID] = newDetails; + emit entityScriptDetailsUpdated(); return; // done processing script } @@ -1497,6 +1509,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co newDetails.status = ERROR_RUNNING_SCRIPT; newDetails.errorInfo = exceptionMessage; _entityScripts[entityID] = newDetails; + emit entityScriptDetailsUpdated(); return; } @@ -1523,6 +1536,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co newDetails.status = ERROR_RUNNING_SCRIPT; newDetails.errorInfo = "Could not find constructor"; _entityScripts[entityID] = newDetails; + emit entityScriptDetailsUpdated(); return; // done processing script } @@ -1544,6 +1558,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co newDetails.lastModified = lastModified; newDetails.definingSandboxURL = sandboxURL; _entityScripts[entityID] = newDetails; + emit entityScriptDetailsUpdated(); if (isURL) { setParentURL(""); @@ -1575,6 +1590,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { } _entityScripts.remove(entityID); stopAllTimersForEntityScript(entityID); + emit entityScriptDetailsUpdated(); } } @@ -1596,6 +1612,7 @@ void ScriptEngine::unloadAllEntityScripts() { } } _entityScripts.clear(); + emit entityScriptDetailsUpdated(); #ifdef DEBUG_ENGINE_STATE qCDebug(scriptengine) << "---- CURRENT STATE OF ENGINE: --------------------------"; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 32d81b9511..3fc79aca9c 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -199,6 +199,7 @@ public: void scriptWarningMessage(const QString& message); void scriptInfoMessage(const QString& message); + int getNumRunningEntityScripts() const; bool getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const; public slots: @@ -222,6 +223,10 @@ signals: void reloadScript(const QString& scriptName, bool isUserLoaded); void doneRunning(); + // Emitted when an entity script is added or removed, or when the status of an entity + // script is updated (goes from RUNNING to ERROR_RUNNING_SCRIPT, for example) + void entityScriptDetailsUpdated(); + protected: void init(); From 202e430adb216851758be863c8f5d615a8a01f9d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 13:38:55 -0800 Subject: [PATCH 43/79] added 4 more recordings to the script --- .../acScripts/BetterClientSimulationBotFromRecording.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/script-archive/acScripts/BetterClientSimulationBotFromRecording.js b/script-archive/acScripts/BetterClientSimulationBotFromRecording.js index 4ea26c3570..106b885d81 100644 --- a/script-archive/acScripts/BetterClientSimulationBotFromRecording.js +++ b/script-archive/acScripts/BetterClientSimulationBotFromRecording.js @@ -106,6 +106,10 @@ var RECORDINGS_ARRAY = [ "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting8.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting9.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting10.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot1.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot2.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot3.hfr", + "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot4.hfr" ]; var RECORDING_URL = RECORDINGS_ARRAY[Math.floor(Math.random() * RECORDINGS_ARRAY.length)]; From 9d3c674271a43d6e6f4c6f81be5faddc40b64ce4 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 13:41:09 -0800 Subject: [PATCH 44/79] fix warning --- assignment-client/src/Agent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 32076b60e3..2cae3dad64 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -377,7 +377,7 @@ void Agent::executeScript() { Transform audioTransform; auto avatarOrientation = scriptedAvatar->getOrientation(); - glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); // FIXME - should we be using head orientation of avatar orientation? + //glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); // FIXME - should we be using head orientation of avatar orientation? audioTransform.setTranslation(scriptedAvatar->getPosition()); audioTransform.setRotation(avatarOrientation); From 82e4b1c690510964e6de9e1a3f406afb443c3d89 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 13:41:20 -0800 Subject: [PATCH 45/79] only recordings with audio --- .../acScripts/BetterClientSimulationBotFromRecording.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/script-archive/acScripts/BetterClientSimulationBotFromRecording.js b/script-archive/acScripts/BetterClientSimulationBotFromRecording.js index 106b885d81..fafb761729 100644 --- a/script-archive/acScripts/BetterClientSimulationBotFromRecording.js +++ b/script-archive/acScripts/BetterClientSimulationBotFromRecording.js @@ -96,15 +96,8 @@ var AVATAR_URL = AVATARS_ARRAY[Math.floor(Math.random() * AVATARS_ARRAY.length)] print("RANDOM AVATAR SELECTED:" + AVATAR_URL); var RECORDINGS_ARRAY = [ - "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting1.hfr", - "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting2.hfr", - "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting3.hfr", - "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting4.hfr", - "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting5.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting6.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting7.hfr", - "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting8.hfr", - "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting9.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/waiting10.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot1.hfr", "http://hifi-content.s3.amazonaws.com/DomainContent/Event%20/NPC%27s/bot2.hfr", From e02810458b328305f05f97239b04c7d30001bef2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 8 Feb 2017 14:14:48 -0800 Subject: [PATCH 46/79] clear old avatarEntityData when saving settings --- interface/src/avatar/MyAvatar.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 120e626b9a..73c807d6d4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -795,6 +795,11 @@ void MyAvatar::saveData() { } settings.endArray(); + if (_avatarEntityData.size() == 0) { + // HACK: manually remove empty 'avatarEntityData' else deleted avatarEntityData may show up in settings file + settings.remove("avatarEntityData"); + } + settings.beginWriteArray("avatarEntityData"); int avatarEntityIndex = 0; auto hmdInterface = DependencyManager::get(); From 357cc052e10541c0b3b420978438f3952a1e839a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 15:32:48 -0800 Subject: [PATCH 47/79] first cut at simulation stats --- interface/src/avatar/Avatar.cpp | 18 ++++++++++++++++++ interface/src/avatar/Avatar.h | 8 ++++++++ interface/src/avatar/AvatarManager.cpp | 7 +++++++ interface/src/avatar/AvatarManager.h | 2 ++ .../developer/debugging/debugAvatarMixer.js | 9 +++++++-- 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 64e82f63da..f8105eca16 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -306,13 +306,18 @@ bool Avatar::shouldDie() const { } void Avatar::simulate(float deltaTime, bool inView) { + _simulationRate.increment(); + PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); { PROFILE_RANGE(simulation, "updateJoints"); if (inView && _hasNewJointData) { _skeletonModel->getRig()->copyJointsFromJointData(_jointData); + _jointDataSimulationRate.increment(); + _skeletonModel->simulate(deltaTime, true); + _skeletonModelSimulationRate.increment(); locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointData = false; @@ -328,6 +333,7 @@ void Avatar::simulate(float deltaTime, bool inView) { } else { // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. _skeletonModel->simulate(deltaTime, false); + _skeletonModelSimulationRate.increment(); } } @@ -357,6 +363,18 @@ void Avatar::simulate(float deltaTime, bool inView) { } } +float Avatar::getSimulationRate(const QString& rateName) { + if (rateName == "") { + return _simulationRate.rate(); + } else if (rateName == "avatar") { + return _simulationRate.rate(); + } else if (rateName == "skeletonModel") { + return _skeletonModelSimulationRate.rate(); + } else if (rateName == "jointData") { + return _jointDataSimulationRate.rate(); + } +} + bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { const float HEAD_SPHERE_RADIUS = 0.1f; glm::vec3 theirLookAt = dynamic_pointer_cast(avatar)->getHead()->getLookAtPosition(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 8f2b0817c1..e0d19fcbc1 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -182,6 +182,8 @@ public: void animateScaleChanges(float deltaTime); void setTargetScale(float targetScale) override; + Q_INVOKABLE float getSimulationRate(const QString& rateName = QString("")); + public slots: // FIXME - these should be migrated to use Pose data instead @@ -259,6 +261,12 @@ protected: void addToScene(AvatarSharedPointer self); void ensureInScene(AvatarSharedPointer self); + // Some rate tracking support + RateCounter<> _simulationRate; + RateCounter<> _skeletonModelSimulationRate; + RateCounter<> _jointDataSimulationRate; + + private: uint64_t _lastRenderUpdateTime { 0 }; int _leftPointerGeometryID { 0 }; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index df3164e6fc..136d7cc016 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -137,6 +137,13 @@ float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& ra return avatar->getDataRate(rateName); } +float AvatarManager::getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName) { + auto avatar = std::static_pointer_cast(getAvatarBySessionID(sessionID)); + return avatar ? avatar->getSimulationRate(rateName) : 0.0f; +} + + + class AvatarPriority { public: AvatarPriority(AvatarSharedPointer a, float p) : avatar(a), priority(p) {} diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 787d6f2d83..c80fd14def 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -70,6 +70,8 @@ public: void handleCollisionEvents(const CollisionEvents& collisionEvents); Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString("")); + Q_INVOKABLE float getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName = QString("")); + Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), const QScriptValue& avatarIdsToDiscard = QScriptValue()); diff --git a/scripts/developer/debugging/debugAvatarMixer.js b/scripts/developer/debugging/debugAvatarMixer.js index 6c0a935b70..1c11d308b8 100644 --- a/scripts/developer/debugging/debugAvatarMixer.js +++ b/scripts/developer/debugging/debugAvatarMixer.js @@ -60,7 +60,8 @@ function updateOverlays() { var overlayPosition = avatar.getJointPosition("Head"); overlayPosition.y += 1.05; - var text = " All: " + AvatarManager.getAvatarDataRate(avatarID).toFixed(2) + "\n" + var text = "--- Data from Mixer ----------------------\n" + +"All: " + AvatarManager.getAvatarDataRate(avatarID).toFixed(2) + "\n" +" GP: " + AvatarManager.getAvatarDataRate(avatarID,"globalPosition").toFixed(2) + "\n" +" LP: " + AvatarManager.getAvatarDataRate(avatarID,"localPosition").toFixed(2) + "\n" +" BB: " + AvatarManager.getAvatarDataRate(avatarID,"avatarBoundingBox").toFixed(2) + "\n" @@ -72,7 +73,11 @@ function updateOverlays() { +" AF: " + AvatarManager.getAvatarDataRate(avatarID,"additionalFlags").toFixed(2) + "\n" +" PI: " + AvatarManager.getAvatarDataRate(avatarID,"parentInfo").toFixed(2) + "\n" +" FT: " + AvatarManager.getAvatarDataRate(avatarID,"faceTracker").toFixed(2) + "\n" - +" JD: " + AvatarManager.getAvatarDataRate(avatarID,"jointData").toFixed(2); + +" JD: " + AvatarManager.getAvatarDataRate(avatarID,"jointData").toFixed(2) + +"--- Simulation ----------------------\n" + +"All: " + AvatarManager.getAvatarSimulationRate(avatarID,"avatar").toFixed(2) + "\n" + +" SM: " + AvatarManager.getAvatarSimulationRate(avatarID,"skeletonModel").toFixed(2) + "\n" + +" JS: " + AvatarManager.getAvatarSimulationRate(avatarID,"jointData").toFixed(2) + "\n" if (avatarID in debugOverlays) { // keep the overlay above the current position of this avatar From fe92d38b6052a77552863d0a6442687ca28ecd56 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 8 Feb 2017 15:42:10 -0800 Subject: [PATCH 48/79] Fixed scaling of self --- .../system/controllers/handControllerGrab.js | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 087460deab..f59d0da2f9 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -26,6 +26,7 @@ Script.include("/~/system/libraries/controllers.js"); // // add lines where the hand ray picking is happening // + var WANT_DEBUG = false; var WANT_DEBUG_STATE = false; var WANT_DEBUG_SEARCH_NAME = null; @@ -752,6 +753,7 @@ function MyController(hand) { this.previouslyUnhooked = {}; this.shouldScale = false; + this.isScalingAvatar = false; // handPosition is where the avatar's hand appears to be, in-world. this.getHandPosition = function () { @@ -825,10 +827,10 @@ function MyController(hand) { this.update = function(deltaTime, timestamp) { this.updateSmoothedTrigger(); // If both trigger and grip buttons squeezed and nothing is held, rescale my avatar! - if (this.hand === RIGHT_HAND && this.state === STATE_SEARCHING && - this.getOtherHandController().state === STATE_SEARCHING) { - this.maybeScaleMyAvatar(); - } + //if (this.hand === RIGHT_HAND && this.state === STATE_SEARCHING && + // this.getOtherHandController().state === STATE_SEARCHING) { + this.maybeScaleMyAvatar(); + //} if (this.ignoreInput()) { @@ -2595,25 +2597,34 @@ function MyController(hand) { }; this.maybeScaleMyAvatar = function() { - if (!myAvatarScalingEnabled) { + if (!myAvatarScalingEnabled || this.shouldScale || this.hand === LEFT_HAND) { + // If scaling disabled, or if we are currently scaling an entity, don't scale avatar + // and only rescale avatar for one hand (so we're not doing it twice) return; } - if (!this.shouldScale) { + // Only scale avatar if both triggers and grips are squeezed + var tryingToScale = this.secondarySqueezed() && this.getOtherHandController().secondarySqueezed() && + this.triggerSmoothedSqueezed() && this.getOtherHandController().triggerSmoothedSqueezed(); + + + if (!this.isScalingAvatar) { // If both secondary triggers squeezed, start scaling - if (this.secondarySqueezed() && this.getOtherHandController().secondarySqueezed()) { + if (tryingToScale) { this.scalingStartDistance = Vec3.length(Vec3.subtract(this.getHandPosition(), this.getOtherHandController().getHandPosition())); this.scalingStartAvatarScale = MyAvatar.scale; - this.shouldScale = true; + this.isScalingAvatar = true; } - } else if (!this.secondarySqueezed() || !this.getOtherHandController().secondarySqueezed()) { - this.shouldScale = false; + } else if (!tryingToScale) { + this.isScalingAvatar = false; } - if (this.shouldScale) { + if (this.isScalingAvatar) { var scalingCurrentDistance = Vec3.length(Vec3.subtract(this.getHandPosition(), this.getOtherHandController().getHandPosition())); var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale; + if (MyAvatar.scale != newAvatarScale) { + } MyAvatar.scale = newAvatarScale; } }; From b39942019028b011238dbf641dd8870efe9cce31 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 15:42:59 -0800 Subject: [PATCH 49/79] CR --- assignment-client/src/Agent.cpp | 5 ++--- interface/src/avatar/Avatar.cpp | 2 +- libraries/avatars/src/AvatarData.h | 20 +++++++++++++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2cae3dad64..bea677aeb6 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -376,10 +376,9 @@ void Agent::executeScript() { static quint16 audioSequenceNumber{ 0 }; Transform audioTransform; - auto avatarOrientation = scriptedAvatar->getOrientation(); - //glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); // FIXME - should we be using head orientation of avatar orientation? + auto headOrientation = scriptedAvatar->getHeadOrientation(); audioTransform.setTranslation(scriptedAvatar->getPosition()); - audioTransform.setRotation(avatarOrientation); + audioTransform.setRotation(headOrientation); QByteArray encodedBuffer; if (_encoder) { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5a059b318f..1235145fe8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1010,7 +1010,7 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { void Avatar::setModelURLFinished(bool success) { if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) { - qWarning(interfaceapp) << "Using default after failing to load Avatar model: " << _skeletonModelURL; + qCWarning(interfaceapp) << "Using default after failing to load Avatar model: " << _skeletonModelURL; // call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that // we don't redo this every time we receive an identity packet from the avatar with the bad url. QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cd97a726bf..54bb5edbca 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -384,9 +384,23 @@ public: lazyInitHeadData(); return _headData->getOrientation(); } - void setHeadOrientation(const glm::quat& orientation) { if (_headData) _headData->setOrientation(orientation); } - void setLookAtPosition(const glm::vec3& lookAtPosition) { if (_headData) _headData->setLookAtPosition(lookAtPosition); } - void setBlendshapeCoefficients(const QVector& blendshapeCoefficients) { if (_headData) _headData->setBlendshapeCoefficients(blendshapeCoefficients); } + void setHeadOrientation(const glm::quat& orientation) { + if (_headData) { + _headData->setOrientation(orientation); + } + } + + void setLookAtPosition(const glm::vec3& lookAtPosition) { + if (_headData) { + _headData->setLookAtPosition(lookAtPosition); + } + } + + void setBlendshapeCoefficients(const QVector& blendshapeCoefficients) { + if (_headData) { + _headData->setBlendshapeCoefficients(blendshapeCoefficients); + } + } // access to Head().set/getMousePitch (degrees) float getHeadPitch() const { return _headData->getBasePitch(); } From dc957d09d86e867e119fb03f68203cf105a1bad8 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 8 Feb 2017 15:45:29 -0800 Subject: [PATCH 50/79] remove comment --- scripts/system/controllers/handControllerGrab.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index f59d0da2f9..508b396d57 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -826,11 +826,7 @@ function MyController(hand) { this.update = function(deltaTime, timestamp) { this.updateSmoothedTrigger(); - // If both trigger and grip buttons squeezed and nothing is held, rescale my avatar! - //if (this.hand === RIGHT_HAND && this.state === STATE_SEARCHING && - // this.getOtherHandController().state === STATE_SEARCHING) { this.maybeScaleMyAvatar(); - //} if (this.ignoreInput()) { From 6957ac5f8b6435bc0e563f2f042da9d5f7f5e1fd Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 9 Feb 2017 01:31:07 +0100 Subject: [PATCH 51/79] Fixes cursor being hidden while Window.browse(), Window.save() are being called from the defaultScript.js thread --- .../src/scripting/WindowScriptingInterface.cpp | 13 +++++++++++++ interface/src/scripting/WindowScriptingInterface.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 52f7d723eb..9c1aedf7a0 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -16,6 +16,8 @@ #include +#include + #include "Application.h" #include "DomainHandler.h" #include "MainWindow.h" @@ -147,6 +149,15 @@ void WindowScriptingInterface::setPreviousBrowseLocation(const QString& location Setting::Handle(LAST_BROWSE_LOCATION_SETTING).set(location); } +/// Makes sure that the reticle is visible, use this in blocking forms that require a reticle and +/// might be in same thread as a script that sets the reticle to invisible +void WindowScriptingInterface::ensureReticleVisible() const { + auto compositorHelper = DependencyManager::get(); + if (!compositorHelper->getReticleVisible()) { + compositorHelper->setReticleVisible(true); + } +} + /// Display an open file dialog. If `directory` is an invalid file or directory the browser will start at the current /// working directory. /// \param const QString& title title of the window @@ -154,6 +165,7 @@ void WindowScriptingInterface::setPreviousBrowseLocation(const QString& location /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` /// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue` QScriptValue WindowScriptingInterface::browse(const QString& title, const QString& directory, const QString& nameFilter) { + ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { path = getPreviousBrowseLocation(); @@ -175,6 +187,7 @@ QScriptValue WindowScriptingInterface::browse(const QString& title, const QStrin /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` /// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue` QScriptValue WindowScriptingInterface::save(const QString& title, const QString& directory, const QString& nameFilter) { + ensureReticleVisible(); QString path = directory; if (path.isEmpty()) { path = getPreviousBrowseLocation(); diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 6cc6c7b715..60d24d50df 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -83,6 +83,8 @@ private: QString getPreviousBrowseLocation() const; void setPreviousBrowseLocation(const QString& location); + void ensureReticleVisible() const; + int createMessageBox(QString title, QString text, int buttons, int defaultButton); QHash _messageBoxes; int _lastMessageBoxID{ -1 }; From 6c41a2503246e2e8ab3278963261433ed0c7e6db Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 16:51:00 -0800 Subject: [PATCH 52/79] more stats --- interface/src/avatar/Avatar.cpp | 1 + interface/src/avatar/AvatarManager.cpp | 7 ++- interface/src/avatar/AvatarManager.h | 1 + libraries/avatars/src/AvatarData.cpp | 46 ++++++++++++++++++- libraries/avatars/src/AvatarData.h | 20 +++++++- .../developer/debugging/debugAvatarMixer.js | 36 +++++++-------- 6 files changed, 89 insertions(+), 22 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f8105eca16..cb381024ba 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -373,6 +373,7 @@ float Avatar::getSimulationRate(const QString& rateName) { } else if (rateName == "jointData") { return _jointDataSimulationRate.rate(); } + return 0.0f; } bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 136d7cc016..aff9ec3add 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -134,7 +134,12 @@ Q_LOGGING_CATEGORY(trace_simulation_avatar, "trace.simulation.avatar"); float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& rateName) { auto avatar = getAvatarBySessionID(sessionID); - return avatar->getDataRate(rateName); + return avatar ? avatar->getDataRate(rateName) : 0.0f; +} + +float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName) { + auto avatar = getAvatarBySessionID(sessionID); + return avatar ? avatar->getUpdateRate(rateName) : 0.0f; } float AvatarManager::getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index c80fd14def..00ae745c98 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -70,6 +70,7 @@ public: void handleCollisionEvents(const CollisionEvents& collisionEvents); Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString("")); + Q_INVOKABLE float getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName = QString("")); Q_INVOKABLE float getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName = QString("")); Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b25140d0a8..146b193a69 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -670,6 +670,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { sourceBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition); int numBytesRead = sourceBuffer - startSection; _globalPositionRate.increment(numBytesRead); + _globalPositionUpdateRate.increment(); // if we don't have a parent, make sure to also set our local position if (!hasParent()) { @@ -698,6 +699,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { sourceBuffer += sizeof(AvatarDataPacket::AvatarBoundingBox); int numBytesRead = sourceBuffer - startSection; _avatarBoundingBoxRate.increment(numBytesRead); + _avatarBoundingBoxUpdateRate.increment(); } if (hasAvatarOrientation) { @@ -713,6 +715,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } int numBytesRead = sourceBuffer - startSection; _avatarOrientationRate.increment(numBytesRead); + _avatarOrientationUpdateRate.increment(); } if (hasAvatarScale) { @@ -732,6 +735,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { sourceBuffer += sizeof(AvatarDataPacket::AvatarScale); int numBytesRead = sourceBuffer - startSection; _avatarScaleRate.increment(numBytesRead); + _avatarScaleUpdateRate.increment(); } if (hasLookAtPosition) { @@ -750,6 +754,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { sourceBuffer += sizeof(AvatarDataPacket::LookAtPosition); int numBytesRead = sourceBuffer - startSection; _lookAtPositionRate.increment(numBytesRead); + _lookAtPositionUpdateRate.increment(); } if (hasAudioLoudness) { @@ -770,6 +775,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { _headData->setAudioLoudness(audioLoudness); int numBytesRead = sourceBuffer - startSection; _audioLoudnessRate.increment(numBytesRead); + _audioLoudnessUpdateRate.increment(); } if (hasSensorToWorldMatrix) { @@ -790,6 +796,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { sourceBuffer += sizeof(AvatarDataPacket::SensorToWorldMatrix); int numBytesRead = sourceBuffer - startSection; _sensorToWorldRate.increment(numBytesRead); + _sensorToWorldUpdateRate.increment(); } if (hasAdditionalFlags) { @@ -833,6 +840,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } int numBytesRead = sourceBuffer - startSection; _additionalFlagsRate.increment(numBytesRead); + _additionalFlagsUpdateRate.increment(); } // FIXME -- make sure to handle the existance of a parent vs a change in the parent... @@ -855,7 +863,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { int numBytesRead = sourceBuffer - startSection; _parentInfoRate.increment(numBytesRead); - } else { + _parentInfoUpdateRate.increment(); + } + else { // FIXME - this aint totally right, for switching to parent/no-parent _parentID = QUuid(); } @@ -877,6 +887,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { sourceBuffer += sizeof(AvatarDataPacket::AvatarLocalPosition); int numBytesRead = sourceBuffer - startSection; _localPositionRate.increment(numBytesRead); + _localPositionUpdateRate.increment(); } if (hasFaceTrackerInfo) { @@ -899,6 +910,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { sourceBuffer += coefficientsSize; int numBytesRead = sourceBuffer - startSection; _faceTrackerRate.increment(numBytesRead); + _faceTrackerUpdateRate.increment(); } if (hasJointData) { @@ -991,12 +1003,14 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { int numBytesRead = sourceBuffer - startSection; _jointDataRate.increment(numBytesRead); + _jointDataUpdateRate.increment(); } int numBytesRead = sourceBuffer - startPosition; _averageBytesReceived.updateAverage(numBytesRead); _parseBufferRate.increment(numBytesRead); + _parseBufferUpdateRate.increment(); return numBytesRead; } @@ -1032,6 +1046,36 @@ float AvatarData::getDataRate(const QString& rateName) { return 0.0f; } +float AvatarData::getUpdateRate(const QString& rateName) { + if (rateName == "") { + return _parseBufferUpdateRate.rate(); + } else if (rateName == "globalPosition") { + return _globalPositionUpdateRate.rate(); + } else if (rateName == "localPosition") { + return _localPositionUpdateRate.rate(); + } else if (rateName == "avatarBoundingBox") { + return _avatarBoundingBoxUpdateRate.rate(); + } else if (rateName == "avatarOrientation") { + return _avatarOrientationUpdateRate.rate(); + } else if (rateName == "avatarScale") { + return _avatarScaleUpdateRate.rate(); + } else if (rateName == "lookAtPosition") { + return _lookAtPositionUpdateRate.rate(); + } else if (rateName == "audioLoudness") { + return _audioLoudnessUpdateRate.rate(); + } else if (rateName == "sensorToWorkMatrix") { + return _sensorToWorldUpdateRate.rate(); + } else if (rateName == "additionalFlags") { + return _additionalFlagsUpdateRate.rate(); + } else if (rateName == "parentInfo") { + return _parentInfoUpdateRate.rate(); + } else if (rateName == "faceTracker") { + return _faceTrackerUpdateRate.rate(); + } else if (rateName == "jointData") { + return _jointDataUpdateRate.rate(); + } + return 0.0f; +} int AvatarData::getAverageBytesReceivedPerSecond() const { return lrint(_averageBytesReceived.getAverageSampleValuePerSecond()); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 52cf81798e..4c24cf6ea6 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -528,7 +528,8 @@ public: Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const; Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const; - float getDataRate(const QString& rateName = QString("")); + Q_INVOKABLE float getDataRate(const QString& rateName = QString("")); + Q_INVOKABLE float getUpdateRate(const QString& rateName = QString("")); int getJointCount() { return _jointData.size(); } @@ -644,7 +645,7 @@ protected: quint64 _lastToByteArray { 0 }; // tracks the last time we did a toByteArray - // Some rate data for incoming data + // Some rate data for incoming data in bytes RateCounter<> _parseBufferRate; RateCounter<> _globalPositionRate; RateCounter<> _localPositionRate; @@ -659,6 +660,21 @@ protected: RateCounter<> _faceTrackerRate; RateCounter<> _jointDataRate; + // Some rate data for incoming data updates + RateCounter<> _parseBufferUpdateRate; + RateCounter<> _globalPositionUpdateRate; + RateCounter<> _localPositionUpdateRate; + RateCounter<> _avatarBoundingBoxUpdateRate; + RateCounter<> _avatarOrientationUpdateRate; + RateCounter<> _avatarScaleUpdateRate; + RateCounter<> _lookAtPositionUpdateRate; + RateCounter<> _audioLoudnessUpdateRate; + RateCounter<> _sensorToWorldUpdateRate; + RateCounter<> _additionalFlagsUpdateRate; + RateCounter<> _parentInfoUpdateRate; + RateCounter<> _faceTrackerUpdateRate; + RateCounter<> _jointDataUpdateRate; + glm::vec3 _globalBoundingBoxDimensions; glm::vec3 _globalBoundingBoxOffset; diff --git a/scripts/developer/debugging/debugAvatarMixer.js b/scripts/developer/debugging/debugAvatarMixer.js index 1c11d308b8..fadab96f89 100644 --- a/scripts/developer/debugging/debugAvatarMixer.js +++ b/scripts/developer/debugging/debugAvatarMixer.js @@ -60,24 +60,24 @@ function updateOverlays() { var overlayPosition = avatar.getJointPosition("Head"); overlayPosition.y += 1.05; - var text = "--- Data from Mixer ----------------------\n" - +"All: " + AvatarManager.getAvatarDataRate(avatarID).toFixed(2) + "\n" - +" GP: " + AvatarManager.getAvatarDataRate(avatarID,"globalPosition").toFixed(2) + "\n" - +" LP: " + AvatarManager.getAvatarDataRate(avatarID,"localPosition").toFixed(2) + "\n" - +" BB: " + AvatarManager.getAvatarDataRate(avatarID,"avatarBoundingBox").toFixed(2) + "\n" - +" AO: " + AvatarManager.getAvatarDataRate(avatarID,"avatarOrientation").toFixed(2) + "\n" - +" AS: " + AvatarManager.getAvatarDataRate(avatarID,"avatarScale").toFixed(2) + "\n" - +" LA: " + AvatarManager.getAvatarDataRate(avatarID,"lookAtPosition").toFixed(2) + "\n" - +" AL: " + AvatarManager.getAvatarDataRate(avatarID,"audioLoudness").toFixed(2) + "\n" - +" SW: " + AvatarManager.getAvatarDataRate(avatarID,"sensorToWorkMatrix").toFixed(2) + "\n" - +" AF: " + AvatarManager.getAvatarDataRate(avatarID,"additionalFlags").toFixed(2) + "\n" - +" PI: " + AvatarManager.getAvatarDataRate(avatarID,"parentInfo").toFixed(2) + "\n" - +" FT: " + AvatarManager.getAvatarDataRate(avatarID,"faceTracker").toFixed(2) + "\n" - +" JD: " + AvatarManager.getAvatarDataRate(avatarID,"jointData").toFixed(2) - +"--- Simulation ----------------------\n" + var text = "--- Data from Mixer ---\n" + +"All: " + AvatarManager.getAvatarDataRate(avatarID).toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID).toFixed(2) + "hz)" + "\n" + +" GP: " + AvatarManager.getAvatarDataRate(avatarID,"globalPosition").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"globalPosition").toFixed(2) + "hz)" + "\n" + +" LP: " + AvatarManager.getAvatarDataRate(avatarID,"localPosition").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"localPosition").toFixed(2) + "hz)" + "\n" + +" BB: " + AvatarManager.getAvatarDataRate(avatarID,"avatarBoundingBox").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"avatarBoundingBox").toFixed(2) + "hz)" + "\n" + +" AO: " + AvatarManager.getAvatarDataRate(avatarID,"avatarOrientation").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"avatarOrientation").toFixed(2) + "hz)" + "\n" + +" AS: " + AvatarManager.getAvatarDataRate(avatarID,"avatarScale").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"avatarScale").toFixed(2) + "hz)" + "\n" + +" LA: " + AvatarManager.getAvatarDataRate(avatarID,"lookAtPosition").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"lookAtPosition").toFixed(2) + "hz)" + "\n" + +" AL: " + AvatarManager.getAvatarDataRate(avatarID,"audioLoudness").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"audioLoudness").toFixed(2) + "hz)" + "\n" + +" SW: " + AvatarManager.getAvatarDataRate(avatarID,"sensorToWorkMatrix").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"sensorToWorkMatrix").toFixed(2) + "hz)" + "\n" + +" AF: " + AvatarManager.getAvatarDataRate(avatarID,"additionalFlags").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"additionalFlags").toFixed(2) + "hz)" + "\n" + +" PI: " + AvatarManager.getAvatarDataRate(avatarID,"parentInfo").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"parentInfo").toFixed(2) + "hz)" + "\n" + +" FT: " + AvatarManager.getAvatarDataRate(avatarID,"faceTracker").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"faceTracker").toFixed(2) + "hz)" + "\n" + +" JD: " + AvatarManager.getAvatarDataRate(avatarID,"jointData").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"jointData").toFixed(2) + "hz)" + "\n" + +"--- Simulation ---\n" +"All: " + AvatarManager.getAvatarSimulationRate(avatarID,"avatar").toFixed(2) + "\n" +" SM: " + AvatarManager.getAvatarSimulationRate(avatarID,"skeletonModel").toFixed(2) + "\n" - +" JS: " + AvatarManager.getAvatarSimulationRate(avatarID,"jointData").toFixed(2) + "\n" + +" JD: " + AvatarManager.getAvatarSimulationRate(avatarID,"jointData").toFixed(2) + "\n" if (avatarID in debugOverlays) { // keep the overlay above the current position of this avatar @@ -90,8 +90,8 @@ function updateOverlays() { var newOverlay = Overlays.addOverlay("text3d", { position: overlayPosition, dimensions: { - x: 1, - y: 13 * 0.13 + x: 1.25, + y: 18 * 0.13 }, lineHeight: 0.1, font:{size:0.1}, From e11d10f5d4bdf8219fe3dde27ba17c13ff31946e Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 8 Feb 2017 16:56:59 -0800 Subject: [PATCH 53/79] Reparing broken normals and also fixing the ambient lighting bug --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 4 ++-- .../gpu-gl/src/gpu/gl/GLBackendPipeline.cpp | 2 +- .../gpu-gl/src/gpu/gl/GLBackendState.cpp | 24 +++++++++++++++---- .../gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 2 +- libraries/model/src/model/TextureMap.cpp | 20 ++++++++-------- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index dbfe8fe730..c51f468908 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -328,12 +328,12 @@ void GLBackend::render(const Batch& batch) { void GLBackend::syncCache() { + PROFILE_RANGE(render_gpu_gl_detail, __FUNCTION__); + syncTransformStateCache(); syncPipelineStateCache(); syncInputStateCache(); syncOutputStateCache(); - - glEnable(GL_LINE_SMOOTH); } #ifdef GPU_STEREO_DRAWCALL_DOUBLED diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp index 81d38c3339..8aab6abaa9 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp @@ -1,4 +1,4 @@ -// +// // GLBackendPipeline.cpp // libraries/gpu/src/gpu // diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp index 6f8c229184..a7d4a7ff7c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp @@ -28,11 +28,8 @@ void GLBackend::resetPipelineState(State::Signature nextSignature) { } } } -} - -void GLBackend::syncPipelineStateCache() { - State::Data state; + // force a few states regardless glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Point size is always on @@ -43,6 +40,25 @@ void GLBackend::syncPipelineStateCache() { // Default line width accross the board glLineWidth(1.0f); + glEnable(GL_LINE_SMOOTH); + +} + +void GLBackend::syncPipelineStateCache() { + State::Data state; + + // force a few states regardless + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + + // Point size is always on + // FIXME CORE + //glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + glEnable(GL_PROGRAM_POINT_SIZE_EXT); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + + // Default line width accross the board + glLineWidth(1.0f); + glEnable(GL_LINE_SMOOTH); getCurrentGLState(state); State::Signature signature = State::evalSignature(state); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index 14c0a3923a..9dac2986e3 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -151,7 +151,7 @@ bool GLTextureTransferHelper::process() { #endif return true; } - PROFILE_COUNTER_IF_CHANGED(render_gpu_gl, "transferringTextures", size_t, _transferringTextures.size()) + PROFILE_COUNTER_IF_CHANGED(render_gpu_gl, "transferringTextures", int, (int) _transferringTextures.size()) static auto lastReport = usecTimestampNow(); auto now = usecTimestampNow(); diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 839a704e54..db87950e5a 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -143,7 +143,7 @@ const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& val // Force all the color images to be rgba32bits if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); + image = image.convertToFormat(QImage::Format_ARGB32); } return image; @@ -287,8 +287,8 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src QImage image = processSourceImage(srcImage, false); // Make sure the normal map source image is RGBA32 - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); + if (image.format() != QImage::Format_RGBA8888) { + image = image.convertToFormat(QImage::Format_RGBA8888); } gpu::Texture* theTexture = nullptr; @@ -332,7 +332,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm int width = image.width(); int height = image.height(); // THe end result image for normal map is RGBA32 even though the A is not used - QImage result(width, height, QImage::Format_ARGB32); + QImage result(width, height, QImage::Format_RGBA8888); for (int i = 0; i < width; i++) { const int iNextClamped = clampPixelCoordinate(i + 1, width - 1); @@ -400,8 +400,8 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma image = image.convertToFormat(QImage::Format_RGB888); } } else { - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); + if (image.format() != QImage::Format_RGBA8888) { + image = image.convertToFormat(QImage::Format_RGBA8888); } } @@ -435,8 +435,8 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s image = image.convertToFormat(QImage::Format_RGB888); } } else { - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); + if (image.format() != QImage::Format_RGBA8888) { + image = image.convertToFormat(QImage::Format_RGBA8888); } } @@ -474,8 +474,8 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag image = image.convertToFormat(QImage::Format_RGB888); } } else { - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); + if (image.format() != QImage::Format_RGBA8888) { + image = image.convertToFormat(QImage::Format_RGBA8888); } } From a209d0372a1a5ec587371351d2b7690cba065977 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 8 Feb 2017 17:27:19 -0800 Subject: [PATCH 54/79] First cut of pal on tablet. --- interface/resources/qml/hifi/Pal.qml | 6 +- .../resources/qml/hifi/tablet/TabletRoot.qml | 13 ++++ interface/src/ui/overlays/Web3DOverlay.cpp | 7 ++ libraries/gl/src/gl/OffscreenQmlSurface.cpp | 12 ++++ libraries/gl/src/gl/OffscreenQmlSurface.h | 5 ++ .../src/TabletScriptingInterface.cpp | 23 +++++++ .../src/TabletScriptingInterface.h | 23 +++++++ scripts/system/pal.js | 66 ++++++++++++++----- 8 files changed, 138 insertions(+), 17 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 923b09b9ef..20376d3fc0 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -16,6 +16,8 @@ import QtQuick.Controls 1.4 import "../styles-uit" import "../controls-uit" as HifiControls +// references HMD, Users, UserActivityLogger from root context + Rectangle { id: pal // Size @@ -35,7 +37,9 @@ Rectangle { // Keep a local list of per-avatar gainSliderValueDBs. Far faster than fetching this data from the server. // NOTE: if another script modifies the per-avatar gain, this value won't be accurate! property var gainSliderValueDB: ({}); - + + HifiConstants { id: hifi } + // The letterbox used for popup messages LetterboxMessage { id: letterboxMessage diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index cfda92e774..0260bd6a01 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -18,6 +18,16 @@ Item { loader.item.scriptURL = injectedJavaScriptUrl; } + // used to send a message from qml to interface script. + signal sendToScript(var message); + + // used to receive messages from interface script + function fromScript(message) { + if (loader.item.hasOwnProperty("fromScript")) { + loader.item.fromScript(message); + } + } + SoundEffect { id: buttonClickSound volume: 0.1 @@ -55,6 +65,9 @@ Item { } }); } + if (loader.item.hasOwnProperty("sendToScript")) { + loader.item.sendToScript.connect(tabletRoot.sendToScript); + } loader.item.forceActiveFocus(); } } diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index f33ef24c0d..a381b90bfb 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -23,11 +23,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -149,6 +152,10 @@ void Web3DOverlay::loadSourceURL() { _webSurface->load(_url, [&](QQmlContext* context, QObject* obj) {}); _webSurface->resume(); + _webSurface->getRootContext()->setContextProperty("Users", DependencyManager::get().data()); + _webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get().data()); + _webSurface->getRootContext()->setContextProperty("UserActivityLogger", DependencyManager::get().data()); + if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") { auto tabletScriptingInterface = DependencyManager::get(); auto flags = tabletScriptingInterface->getFlags(); diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 8af115ebcb..447b9d56aa 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -604,6 +604,9 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::functionsetParentItem(_quickWindow->contentItem()); @@ -952,4 +955,13 @@ void OffscreenQmlSurface::emitWebEvent(const QVariant& message) { } } +void OffscreenQmlSurface::sendToQml(const QVariant& message) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "emitQmlEvent", Qt::QueuedConnection, Q_ARG(QVariant, message)); + } else if (_rootItem) { + // call fromScript method on qml root + QMetaObject::invokeMethod(_rootItem, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message)); + } +} + #include "OffscreenQmlSurface.moc" diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.h b/libraries/gl/src/gl/OffscreenQmlSurface.h index f6168e7b6d..efd35fce8b 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.h +++ b/libraries/gl/src/gl/OffscreenQmlSurface.h @@ -107,6 +107,11 @@ signals: void scriptEventReceived(const QVariant& message); void webEventReceived(const QVariant& message); + // qml event bridge +public slots: + void sendToQml(const QVariant& message); +signals: + void fromQml(QVariant message); protected: bool filterEnabled(QObject* originalDestination, QEvent* event) const; diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index e7f8ebe2cb..616d751bf7 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -183,6 +183,18 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr _qmlTabletRoot = qmlTabletRoot; if (_qmlTabletRoot && _qmlOffscreenSurface) { QObject::connect(_qmlOffscreenSurface, SIGNAL(webEventReceived(QVariant)), this, SIGNAL(webEventReceived(QVariant))); + + // forward qml surface events to interface js + connect(dynamic_cast(_qmlOffscreenSurface), &OffscreenQmlSurface::fromQml, [this](QVariant message) { + if (message.canConvert()) { + emit fromQml(qvariant_cast(message).toVariant()); + } else if (message.canConvert()) { + emit fromQml(message.toString()); + } else { + qWarning() << "fromQml: Unsupported message type " << message; + } + }); + gotoHomeScreen(); QMetaObject::invokeMethod(_qmlTabletRoot, "setUsername", Q_ARG(const QVariant&, QVariant(getUsername()))); @@ -197,6 +209,7 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr } else { removeButtonsFromHomeScreen(); _state = State::Uninitialized; + emit screenChanged(QVariant("Closed"), QVariant("")); } } @@ -208,6 +221,7 @@ void TabletProxy::gotoMenuScreen() { QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen()), Qt::DirectConnection); QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL))); _state = State::Menu; + emit screenChanged(QVariant("Menu"), QVariant(VRMENU_SOURCE_URL)); } } } @@ -217,6 +231,7 @@ void TabletProxy::loadQMLSource(const QVariant& path) { if (_state != State::QML) { QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, path)); _state = State::QML; + emit screenChanged(QVariant("QML"), path); } } } @@ -228,6 +243,7 @@ void TabletProxy::gotoHomeScreen() { QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL))); QMetaObject::invokeMethod(_qmlTabletRoot, "playButtonClickSound"); _state = State::Home; + emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL)); } } } @@ -244,6 +260,7 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS if (_state != State::Web) { QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL))); _state = State::Web; + emit screenChanged(QVariant("Web"), QVariant(url)); } QMetaObject::invokeMethod(_qmlTabletRoot, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl))); @@ -306,6 +323,12 @@ void TabletProxy::emitScriptEvent(QVariant msg) { } } +void TabletProxy::sendToQml(QVariant msg) { + if (_qmlOffscreenSurface) { + QMetaObject::invokeMethod(_qmlOffscreenSurface, "sendToQml", Qt::AutoConnection, Q_ARG(QVariant, msg)); + } +} + void TabletProxy::addButtonsToHomeScreen() { auto tablet = getQmlTablet(); if (!tablet) { diff --git a/libraries/script-engine/src/TabletScriptingInterface.h b/libraries/script-engine/src/TabletScriptingInterface.h index a005152fa9..93f5bcf6ba 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.h +++ b/libraries/script-engine/src/TabletScriptingInterface.h @@ -122,6 +122,13 @@ public: */ Q_INVOKABLE void emitScriptEvent(QVariant msg); + /**jsdoc + * Used to send an event to the qml embedded in the tablet + * @function TabletProxy#sendToQml + * @param msg {object|string} + */ + Q_INVOKABLE void sendToQml(QVariant msg); + Q_INVOKABLE bool onHomeScreen(); QObject* getTabletSurface(); @@ -139,6 +146,22 @@ signals: */ void webEventReceived(QVariant msg); + /**jsdoc + * Signaled when this tablet receives an event from the qml embedded in the tablet + * @function TabletProxy#fromQml + * @param msg {object|string} + * @returns {Signal} + */ + void fromQml(QVariant msg); + + /**jsdoc + * Signales when this tablet screen changes. + * @function TabletProxy#screenChanged + * @param type {string} - "Home", "Web", "Menu", "QML", "Closed" + * @param url {string} - only valid for Web and QML. + */ + void screenChanged(QVariant type, QVariant url); + private slots: void addButtonsToHomeScreen(); void addButtonsToMenuScreen(); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index adbde0ef5c..5f02be83e5 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -203,8 +203,8 @@ var pal = new OverlayWindow({ height: 640, visible: false }); -pal.fromQml.connect(function (message) { // messages are {method, params}, like json-rpc. See also sendToQml. - print('From PAL QML:', JSON.stringify(message)); +function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. + print('AJT: From PAL QML:', JSON.stringify(message)); switch (message.method) { case 'selected': selectedIds = message.params; @@ -234,6 +234,7 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like } break; case 'refresh': + print("AJT: REFRESH!"); removeOverlays(); populateUserList(message.params); UserActivityLogger.palAction("refresh", ""); @@ -259,7 +260,15 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like default: print('Unrecognized message from Pal.qml:', JSON.stringify(message)); } -}); +} + +function sendToQml(message) { + if (Settings.getValue("HUDUIEnabled")) { + pal.sendToQml(message); + } else { + tablet.sendToQml(message); + } +} // // Main operations. @@ -298,10 +307,10 @@ function populateUserList(selectData) { data.push(avatarPalDatum); print('PAL data:', JSON.stringify(avatarPalDatum)); }); - pal.sendToQml({ method: 'users', params: data }); + sendToQml({ method: 'users', params: data }); if (selectData) { selectData[2] = true; - pal.sendToQml({ method: 'select', params: selectData }); + sendToQml({ method: 'select', params: selectData }); } } @@ -322,7 +331,7 @@ function usernameFromIDReply(id, username, machineFingerprint, isAdmin) { } print('Username Data:', JSON.stringify(data)); // Ship the data off to QML - pal.sendToQml({ method: 'updateUsername', params: data }); + sendToQml({ method: 'updateUsername', params: data }); } var pingPong = true; @@ -396,7 +405,7 @@ function handleClick(pickRay) { ExtendedOverlay.applyPickRay(pickRay, function (overlay) { // Don't select directly. Tell qml, who will give us back a list of ids. var message = {method: 'select', params: [[overlay.key], !overlay.selected, false]}; - pal.sendToQml(message); + sendToQml(message); return true; }); } @@ -492,6 +501,7 @@ if (Settings.getValue("HUDUIEnabled")) { visible: true, alpha: 0.9 }); + pal.fromQml.connect(fromQml); } else { tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ @@ -499,7 +509,9 @@ if (Settings.getValue("HUDUIEnabled")) { icon: "icons/tablet-icons/people-i.svg", sortOrder: 7 }); + tablet.fromQml.connect(fromQml); } + var isWired = false; var audioTimer; var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too) @@ -518,10 +530,26 @@ function off() { Users.requestsDomainListData = false; } function onClicked() { - if (!pal.visible) { + if (Settings.getValue("HUDUIEnabled")) { + if (!pal.visible) { + Users.requestsDomainListData = true; + populateUserList(); + pal.raise(); + isWired = true; + Script.update.connect(updateOverlays); + Controller.mousePressEvent.connect(handleMouseEvent); + Controller.mouseMoveEvent.connect(handleMouseMoveEvent); + triggerMapping.enable(); + triggerPressMapping.enable(); + audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); + } else { + off(); + } + pal.setVisible(!pal.visible); + } else { + tablet.loadQMLSource("../Pal.qml"); Users.requestsDomainListData = true; populateUserList(); - pal.raise(); isWired = true; Script.update.connect(updateOverlays); Controller.mousePressEvent.connect(handleMouseEvent); @@ -529,10 +557,7 @@ function onClicked() { triggerMapping.enable(); triggerPressMapping.enable(); audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); - } else { - off(); } - pal.setVisible(!pal.visible); } // @@ -550,7 +575,7 @@ function receiveMessage(channel, messageString, senderID) { if (!pal.visible) { onClicked(); } - pal.sendToQml(message); // Accepts objects, not just strings. + sendToQml(message); // Accepts objects, not just strings. break; default: print('Unrecognized PAL message', messageString); @@ -607,13 +632,13 @@ function createAudioInterval(interval) { var userId = id || 0; param[userId] = level; }); - pal.sendToQml({method: 'updateAudioLevel', params: param}); + sendToQml({method: 'updateAudioLevel', params: param}); }, interval); } function avatarDisconnected(nodeID) { // remove from the pal list - pal.sendToQml({method: 'avatarDisconnected', params: [nodeID]}); + sendToQml({method: 'avatarDisconnected', params: [nodeID]}); } // // Button state. @@ -624,11 +649,20 @@ function onVisibleChanged() { button.clicked.connect(onClicked); pal.visibleChanged.connect(onVisibleChanged); pal.closed.connect(off); + +if (!Settings.getValue("HUDUIEnabled")) { + tablet.screenChanged.connect(function (type, url) { + if (type !== "QML" || url !== "../Pal.qml") { + off(); + } + }); +} + Users.usernameFromIDReply.connect(usernameFromIDReply); Users.avatarDisconnected.connect(avatarDisconnected); function clearLocalQMLDataAndClosePAL() { - pal.sendToQml({ method: 'clearLocalQMLData' }); + sendToQml({ method: 'clearLocalQMLData' }); if (pal.visible) { onClicked(); // Close the PAL } From 7cc30793289ba178d49e1a5ec2cccf064fe1d505 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 8 Feb 2017 17:58:24 -0800 Subject: [PATCH 55/79] Tightened up margins for the tablet. --- interface/resources/qml/hifi/Pal.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 20376d3fc0..29f0146608 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -28,7 +28,7 @@ Rectangle { // Properties property int myCardHeight: 90 property int rowHeight: 70 - property int actionButtonWidth: 75 + property int actionButtonWidth: 55 property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth property var myData: ({displayName: "", userName: "", audioLevel: 0.0, admin: true}) // valid dummy until set property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. @@ -58,8 +58,8 @@ Rectangle { property bool punctuationMode: false id: palContainer // Size - width: pal.width - 50 - height: pal.height - 50 + width: pal.width - 10 + height: pal.height - 10 // Style color: pal.color // Anchors @@ -401,7 +401,7 @@ Rectangle { width: 20 height: 28 anchors.right: adminTab.right - anchors.rightMargin: 31 + hifi.dimensions.scrollbarBackgroundWidth + anchors.rightMargin: 10 + hifi.dimensions.scrollbarBackgroundWidth anchors.top: adminTab.top anchors.topMargin: 2 RalewayRegular { From e94e41698ea1578abd2b477bcf64f2702f88f324 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 8 Feb 2017 18:04:55 -0800 Subject: [PATCH 56/79] remove debug --- scripts/system/controllers/handControllerGrab.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 508b396d57..527a9cfc2b 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -2619,8 +2619,6 @@ function MyController(hand) { var scalingCurrentDistance = Vec3.length(Vec3.subtract(this.getHandPosition(), this.getOtherHandController().getHandPosition())); var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale; - if (MyAvatar.scale != newAvatarScale) { - } MyAvatar.scale = newAvatarScale; } }; From 090f6321899f8f57c8ecb6dc39d08d87d4d83b38 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 8 Feb 2017 18:16:48 -0800 Subject: [PATCH 57/79] Pal: Moved keyboard tray to be flush with bottom of window. --- interface/resources/qml/hifi/Pal.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 29f0146608..0c7104fba5 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -426,6 +426,8 @@ Rectangle { onExited: adminHelpText.color = hifi.colors.redHighlight } } + } + HifiControls.Keyboard { id: keyboard raised: myCard.currentlyEditingDisplayName && HMD.active @@ -436,7 +438,7 @@ Rectangle { right: parent.right } } - } + // Timer used when selecting table rows that aren't yet present in the model // (i.e. when selecting avatars using edit.js or sphere overlays) Timer { From 41dc4988884cc83b9f57026802f0f5df6775a89d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 8 Feb 2017 18:32:39 -0800 Subject: [PATCH 58/79] add inView simulation stats --- interface/src/avatar/Avatar.cpp | 5 +++++ interface/src/avatar/Avatar.h | 1 + scripts/developer/debugging/debugAvatarMixer.js | 7 ++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a881bb960b..509f6c794a 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -307,6 +307,9 @@ bool Avatar::shouldDie() const { void Avatar::simulate(float deltaTime, bool inView) { _simulationRate.increment(); + if (inView) { + _simulationInViewRate.increment(); + } PROFILE_RANGE(simulation, "simulate"); PerformanceTimer perfTimer("simulate"); @@ -368,6 +371,8 @@ float Avatar::getSimulationRate(const QString& rateName) { return _simulationRate.rate(); } else if (rateName == "avatar") { return _simulationRate.rate(); + } else if (rateName == "avatarInView") { + return _simulationInViewRate.rate(); } else if (rateName == "skeletonModel") { return _skeletonModelSimulationRate.rate(); } else if (rateName == "jointData") { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index e0d19fcbc1..a1c081e327 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -263,6 +263,7 @@ protected: // Some rate tracking support RateCounter<> _simulationRate; + RateCounter<> _simulationInViewRate; RateCounter<> _skeletonModelSimulationRate; RateCounter<> _jointDataSimulationRate; diff --git a/scripts/developer/debugging/debugAvatarMixer.js b/scripts/developer/debugging/debugAvatarMixer.js index fadab96f89..6b5b0d810e 100644 --- a/scripts/developer/debugging/debugAvatarMixer.js +++ b/scripts/developer/debugging/debugAvatarMixer.js @@ -75,9 +75,10 @@ function updateOverlays() { +" FT: " + AvatarManager.getAvatarDataRate(avatarID,"faceTracker").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"faceTracker").toFixed(2) + "hz)" + "\n" +" JD: " + AvatarManager.getAvatarDataRate(avatarID,"jointData").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"jointData").toFixed(2) + "hz)" + "\n" +"--- Simulation ---\n" - +"All: " + AvatarManager.getAvatarSimulationRate(avatarID,"avatar").toFixed(2) + "\n" - +" SM: " + AvatarManager.getAvatarSimulationRate(avatarID,"skeletonModel").toFixed(2) + "\n" - +" JD: " + AvatarManager.getAvatarSimulationRate(avatarID,"jointData").toFixed(2) + "\n" + +"All: " + AvatarManager.getAvatarSimulationRate(avatarID,"avatar").toFixed(2) + "hz \n" + +" inView: " + AvatarManager.getAvatarSimulationRate(avatarID,"avatarInView").toFixed(2) + "hz \n" + +" SM: " + AvatarManager.getAvatarSimulationRate(avatarID,"skeletonModel").toFixed(2) + "hz \n" + +" JD: " + AvatarManager.getAvatarSimulationRate(avatarID,"jointData").toFixed(2) + "hz \n" if (avatarID in debugOverlays) { // keep the overlay above the current position of this avatar From c2b832fb9c6857f6178ad77bfa5078901b5e9275 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 8 Feb 2017 18:55:22 -0800 Subject: [PATCH 59/79] removed debug prints from pal.js --- scripts/system/pal.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 5f02be83e5..2e07a2d431 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -204,7 +204,6 @@ var pal = new OverlayWindow({ visible: false }); function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. - print('AJT: From PAL QML:', JSON.stringify(message)); switch (message.method) { case 'selected': selectedIds = message.params; @@ -234,7 +233,6 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See } break; case 'refresh': - print("AJT: REFRESH!"); removeOverlays(); populateUserList(message.params); UserActivityLogger.palAction("refresh", ""); From b3a46c3518c61f01c8f73d824788438671d52953 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 8 Feb 2017 18:56:16 -0800 Subject: [PATCH 60/79] Bug fix for TabletProxy::loadQMLSource() --- libraries/script-engine/src/TabletScriptingInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index 616d751bf7..71f0073ead 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -229,6 +229,7 @@ void TabletProxy::gotoMenuScreen() { void TabletProxy::loadQMLSource(const QVariant& path) { if (_qmlTabletRoot) { if (_state != State::QML) { + removeButtonsFromHomeScreen(); QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, path)); _state = State::QML; emit screenChanged(QVariant("QML"), path); From e25ad0f332837b7594cdd62b3fa1fbf1222c6f26 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 8 Feb 2017 18:56:58 -0800 Subject: [PATCH 61/79] Fix debug assert in FBXReader. --- libraries/fbx/src/FBXReader_Node.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXReader_Node.cpp b/libraries/fbx/src/FBXReader_Node.cpp index 435c4d830b..fb5f6ce893 100644 --- a/libraries/fbx/src/FBXReader_Node.cpp +++ b/libraries/fbx/src/FBXReader_Node.cpp @@ -62,7 +62,9 @@ template QVariant readBinaryArray(QDataStream& in, int& position) { position += sizeof(T) * arrayLength; in.readRawData(arrayData.data(), arrayData.size()); } - memcpy(&values[0], arrayData.constData(), arrayData.size()); + if (arrayData.size() > 0) { + memcpy(&values[0], arrayData.constData(), arrayData.size()); + } } else { values.reserve(arrayLength); const unsigned int DEFLATE_ENCODING = 1; From 5c5ace7c7b60d6f9b283ae1ff5c0817eae931dbb Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 8 Feb 2017 21:37:42 +0000 Subject: [PATCH 62/79] goto in tablet --- interface/resources/qml/hifi/Card.qml | 2 +- .../qml/hifi/tablet/TabletAddressDialog.qml | 557 ++++++++++++++++++ interface/src/ui/overlays/Web3DOverlay.cpp | 6 + scripts/system/goto.js | 7 +- 4 files changed, 568 insertions(+), 4 deletions(-) create mode 100644 interface/resources/qml/hifi/tablet/TabletAddressDialog.qml diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 876be740cd..7dd7c63da9 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -129,7 +129,7 @@ Rectangle { property int dropSamples: 9; property int dropSpread: 0; DropShadow { - visible: showPlace && desktop.gradientsSupported; + visible: showPlace; //&& desktop.gradientsSupported; source: place; anchors.fill: place; horizontalOffset: dropHorizontalOffset; diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml new file mode 100644 index 0000000000..011b4928bd --- /dev/null +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -0,0 +1,557 @@ +// +// TabletAddressDialog.qml +// +// Created by Dante Ruiz on 2016/07/16 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import Hifi 1.0 +import QtQuick 2.4 +import QtGraphicalEffects 1.0 +import "../../controls" +import "../../styles" +import "../../windows" +import "../" +import "../toolbars" +import "../../styles-uit" as HifiStyles +import "../../controls-uit" as HifiControls + +Item { + id: root + HifiConstants { id: hifi } + HifiStyles.HifiConstants { id: hifiStyleConstants } + + width: parent.width + height: parent.height + + property var allStories: []; + property int cardWidth: 370; + property int cardHeight: 320; + property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/"; + + + Component.onCompleted: { + fillDestinations(); + updateLocationText(); + root.parentChanged.connect(center); + center(); + } + Component.onDestruction: { + root.parentChanged.disconnect(center); + } + + function center() { + // Explicitly center in order to avoid warnings at shutdown + anchors.centerIn = parent; + } + + + function resetAfterTeleport() { + //storyCardFrame.shown = root.shown = false; + } + function goCard(targetString) { + if (0 !== targetString.indexOf('hifi://')) { + return; + } + addressLine.text = targetString; + toggleOrGo(true); + clearAddressLineTimer.start(); + } + + property bool isCursorVisible: false // Override default cursor visibility. + + + AddressBarDialog { + id: addressBarDialog + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + width: parent.width + height: parent.height + + anchors { + right: parent.right + left: parent.left + top: parent.top + bottom: parent.bottom + } + + onMetaverseServerUrlChanged: updateLocationTextTimer.start(); + Rectangle { + id: topBar + height: 90 + gradient: Gradient { + GradientStop { + position: 0 + color: "#2b2b2b" + + } + + GradientStop { + position: 1 + color: "#1e1e1e" + } + } + + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.topMargin: 0 + anchors.top: parent.top + + Row { + id: thing + spacing: 2 * hifi.layout.spacing + + anchors { + top: parent.top; + left: parent.left + } + + TextButton { + id: allTab; + text: "ALL"; + property string includeActions: 'snapshot, concurrency'; + selected: allTab === selectedTab; + action: tabSelect; + } + + TextButton { + id: placeTab; + text: "PLACES"; + property string includeActions: 'concurrency'; + selected: placeTab === selectedTab; + action: tabSelect; + + } + + TextButton { + id: snapTab; + text: "SNAP"; + property string includeActions: 'snapshot'; + selected: snapTab === selectedTab; + action: tabSelect; + } + } + + } + + Rectangle { + id: bgMain + gradient: Gradient { + GradientStop { + position: 0 + color: "#2b2b2b" + + } + + GradientStop { + position: 1 + color: "#0f212e" + } + } + + + anchors.bottom: backgroundImage.top + anchors.bottomMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.top: topBar.bottom + anchors.topMargin: 0 + + ListModel { id: suggestions } + + ListView { + id: scroll + + property int stackedCardShadowHeight: 10; + clip: true + spacing: 14 + anchors { + bottom: parent.bottom + top: parent.top + left: parent.left + right: parent.right + leftMargin: 50 + } + model: suggestions + orientation: ListView.Vertical + + delegate: Card { + width: cardWidth; + height: cardHeight; + goFunction: goCard; + userName: model.username; + placeName: model.place_name; + hifiUrl: model.place_name + model.path; + thumbnail: model.thumbnail_url; + imageUrl: model.image_url; + action: model.action; + timestamp: model.created_at; + onlineUsers: model.online_users; + storyId: model.metaverseId; + drillDownToPlace: model.drillDownToPlace; + shadowHeight: scroll.stackedCardShadowHeight; + hoverThunk: function () { scroll.currentIndex = index; } + unhoverThunk: function () { scroll.currentIndex = -1; } + } + + highlightMoveDuration: -1; + highlightMoveVelocity: -1; + highlight: Rectangle { color: "transparent"; border.width: 4; border.color: hifiStyleConstants.colors.blueHighlight; z: 1; } + } + } + + Rectangle { + id: backgroundImage + width: 480 + height: 70 + + gradient: Gradient { + GradientStop { + position: 0 + color: "#c2ced8" + + } + + GradientStop { + position: 1 + color: "#c2ced8" + } + } + + anchors { + bottom: parent.keyboardEnabled ? keyboard.top : parent.bottom + right: parent.right + left: parent.left + } + + + ToolbarButton { + id: homeButton + imageURL: "../../../images/home.svg" + onClicked: { + addressBarDialog.loadHome(); + root.shown = false; + } + anchors { + left: parent.left + leftMargin: homeButton.width / 2 + verticalCenter: parent.verticalCenter + } + } + property int inputAreaHeight: 70 + property int inputAreaStep: (height - inputAreaHeight) / 2 + + HifiStyles.RalewayLight { + id: notice; + font.pixelSize: hifi.fonts.pixelSize * 0.50; + anchors { + top: parent.top + topMargin: parent.inputAreaStep + 12 + left: addressLine.left + right: addressLine.right + } + } + HifiStyles.FiraSansRegular { + id: location; + font.pixelSize: addressLine.font.pixelSize; + color: "gray"; + clip: true; + anchors.fill: addressLine; + visible: addressLine.text.length === 0 + } + + TextInput { + id: addressLine + focus: true + anchors { + bottom: parent.bottom + left: homeButton.right + right: parent.right + leftMargin: homeButton.width + rightMargin: homeButton.width / 2 + topMargin: parent.inputAreaStep + (2 * hifi.layout.spacing) + bottomMargin: parent.inputAreaStep + } + font.pixelSize: hifi.fonts.pixelSize * 0.75 + cursorVisible: false + onTextChanged: { + filterChoicesByText(); + updateLocationText(text.length > 0); + if (!isCursorVisible && text.length > 0) { + isCursorVisible = true; + cursorVisible = true; + } + } + onAccepted: { + addressBarDialog.keyboardEnabled = false; + } + onActiveFocusChanged: { + cursorVisible = isCursorVisible && focus; + } + MouseArea { + // If user clicks in address bar show cursor to indicate ability to enter address. + anchors.fill: parent + onClicked: { + isCursorVisible = true; + //parent.cursorVisible = true; + parent.forceActiveFocus(); + addressBarDialog.keyboardEnabled = HMD.active + tabletRoot.playButtonClickSound(); + } + } + } + } + + Timer { + // Delay updating location text a bit to avoid flicker of content and so that connection status is valid. + id: updateLocationTextTimer + running: false + interval: 500 // ms + repeat: false + onTriggered: updateLocationText(false); + } + + Timer { + // Delay clearing address line so as to avoid flicker of "not connected" being displayed after entering an address. + id: clearAddressLineTimer + running: false + interval: 100 // ms + repeat: false + onTriggered: { + addressLine.text = ""; + isCursorVisible = false; + } + } + + + HifiControls.Keyboard { + id: keyboard + raised: parent.keyboardEnabled + numeric: parent.punctuationMode + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + + clickSound: tabletRoot.playButtonClickSound(); + } + + } + + function getRequest(url, cb) { // cb(error, responseOfCorrectContentType) of url. General for 'get' text/html/json, but without redirects. + // TODO: make available to other .qml. + var request = new XMLHttpRequest(); + // QT bug: apparently doesn't handle onload. Workaround using readyState. + request.onreadystatechange = function () { + var READY_STATE_DONE = 4; + var HTTP_OK = 200; + if (request.readyState >= READY_STATE_DONE) { + var error = (request.status !== HTTP_OK) && request.status.toString() + ':' + request.statusText, + response = !error && request.responseText, + contentType = !error && request.getResponseHeader('content-type'); + if (!error && contentType.indexOf('application/json') === 0) { + try { + response = JSON.parse(response); + } catch (e) { + error = e; + } + } + cb(error, response); + } + }; + request.open("GET", url, true); + request.send(); + } + + function identity(x) { + return x; + } + + function handleError(url, error, data, cb) { // cb(error) and answer truthy if needed, else falsey + if (!error && (data.status === 'success')) { + return; + } + if (!error) { // Create a message from the data + error = data.status + ': ' + data.error; + } + if (typeof(error) === 'string') { // Make a proper Error object + error = new Error(error); + } + error.message += ' in ' + url; // Include the url. + cb(error); + return true; + } + + + function resolveUrl(url) { + return (url.indexOf('/') === 0) ? (addressBarDialog.metaverseServerUrl + url) : url; + } + + function makeModelData(data) { // create a new obj from data + // ListModel elements will only ever have those properties that are defined by the first obj that is added. + // So here we make sure that we have all the properties we need, regardless of whether it is a place data or user story. + var name = data.place_name, + tags = data.tags || [data.action, data.username], + description = data.description || "", + thumbnail_url = data.thumbnail_url || ""; + return { + place_name: name, + username: data.username || "", + path: data.path || "", + created_at: data.created_at || "", + action: data.action || "", + thumbnail_url: resolveUrl(thumbnail_url), + image_url: resolveUrl(data.details.image_url), + + metaverseId: (data.id || "").toString(), // Some are strings from server while others are numbers. Model objects require uniformity. + + tags: tags, + description: description, + online_users: data.details.concurrency || 0, + drillDownToPlace: false, + + searchText: [name].concat(tags, description || []).join(' ').toUpperCase() + } + } + function suggestable(place) { + if (place.action === 'snapshot') { + return true; + } + return (place.place_name !== AddressManager.placename); // Not our entry, but do show other entry points to current domain. + } + property var selectedTab: allTab; + function tabSelect(textButton) { + selectedTab = textButton; + fillDestinations(); + } + property var placeMap: ({}); + function addToSuggestions(place) { + var collapse = allTab.selected && (place.action !== 'concurrency'); + if (collapse) { + var existing = placeMap[place.place_name]; + if (existing) { + existing.drillDownToPlace = true; + return; + } + } + suggestions.append(place); + if (collapse) { + placeMap[place.place_name] = suggestions.get(suggestions.count - 1); + } else if (place.action === 'concurrency') { + suggestions.get(suggestions.count - 1).drillDownToPlace = true; // Don't change raw place object (in allStories). + } + } + property int requestId: 0; + function getUserStoryPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model + var options = [ + 'now=' + new Date().toISOString(), + 'include_actions=' + selectedTab.includeActions, + 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), + 'require_online=true', + 'protocol=' + encodeURIComponent(AddressManager.protocolVersion()), + 'page=' + pageNumber + ]; + var url = metaverseBase + 'user_stories?' + options.join('&'); + var thisRequestId = ++requestId; + getRequest(url, function (error, data) { + if ((thisRequestId !== requestId) || handleError(url, error, data, cb)) { + return; + } + var stories = data.user_stories.map(function (story) { // explicit single-argument function + return makeModelData(story, url); + }); + allStories = allStories.concat(stories); + stories.forEach(makeFilteredPlaceProcessor()); + if ((data.current_page < data.total_pages) && (data.current_page <= 10)) { // just 10 pages = 100 stories for now + return getUserStoryPage(pageNumber + 1, cb); + } + cb(); + }); + } + function makeFilteredPlaceProcessor() { // answer a function(placeData) that adds it to suggestions if it matches + var words = addressLine.text.toUpperCase().split(/\s+/).filter(identity), + data = allStories; + function matches(place) { + if (!words.length) { + return suggestable(place); + } + return words.every(function (word) { + return place.searchText.indexOf(word) >= 0; + }); + } + return function (place) { + if (matches(place)) { + addToSuggestions(place); + } + }; + } + function filterChoicesByText() { + suggestions.clear(); + placeMap = {}; + allStories.forEach(makeFilteredPlaceProcessor()); + } + + function fillDestinations() { + allStories = []; + suggestions.clear(); + placeMap = {}; + getUserStoryPage(1, function (error) { + console.log('user stories query', error || 'ok', allStories.length); + }); + } + + function updateLocationText(enteringAddress) { + if (enteringAddress) { + notice.text = "Go to a place, @user, path or network address"; + notice.color = hifiStyleConstants.colors.baseGrayHighlight; + } else { + notice.text = AddressManager.isConnected ? "Your location:" : "Not Connected"; + notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.baseGrayHighlight : hifiStyleConstants.colors.redHighlight; + // Display hostname, which includes ip address, localhost, and other non-placenames. + location.text = (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''); + } + } + + onVisibleChanged: { + updateLocationText(false); + if (visible) { + addressLine.forceActiveFocus(); + fillDestinations(); + } + } + + function toggleOrGo(fromSuggestions) { + if (addressLine.text !== "") { + addressBarDialog.loadAddress(addressLine.text, fromSuggestions) + } + root.shown = false; + } + + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + root.shown = false + clearAddressLineTimer.start(); + event.accepted = true + break + case Qt.Key_Enter: + case Qt.Key_Return: + toggleOrGo() + clearAddressLineTimer.start(); + event.accepted = true + break + } + } +} diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index a381b90bfb..ddf380d0b2 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -34,6 +34,9 @@ #include #include #include +#include +#include "scripting/AccountScriptingInterface.h" +#include "scripting/HMDScriptingInterface.h" static const float DPI = 30.47f; static const float INCHES_TO_METERS = 1.0f / 39.3701f; @@ -160,6 +163,9 @@ void Web3DOverlay::loadSourceURL() { auto tabletScriptingInterface = DependencyManager::get(); auto flags = tabletScriptingInterface->getFlags(); _webSurface->getRootContext()->setContextProperty("offscreenFlags", flags); + _webSurface->getRootContext()->setContextProperty("AddressManager", DependencyManager::get().data()); + _webSurface->getRootContext()->setContextProperty("Account", AccountScriptingInterface::getInstance()); + _webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get().data()); tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data()); // Override min fps for tablet UI, for silky smooth scrolling diff --git a/scripts/system/goto.js b/scripts/system/goto.js index 092abd0369..9e6964b5f0 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -18,13 +18,14 @@ var button; var buttonName = "GOTO"; var toolBar = null; var tablet = null; - +var ADDRESS_DIALOG_QML_SOURCE = "TabletAddressDialog.qml"; function onAddressBarShown(visible) { - button.editProperties({isActive: visible}); + //button.editProperties({isActive: visible}); } function onClicked(){ - DialogsManager.toggleAddressBar(); + //DialogsManager.toggleAddressBar(); + tablet.loadQMLSource(ADDRESS_DIALOG_QML_SOURCE); } if (Settings.getValue("HUDUIEnabled")) { From 6bc685b02a039d0a394eedfdbfe5981e0050a93d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 8 Feb 2017 21:38:28 +0000 Subject: [PATCH 63/79] saving work --- interface/resources/qml/hifi/tablet/TabletAddressDialog.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 011b4928bd..952a1f7faa 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -343,8 +343,6 @@ Item { left: parent.left right: parent.right } - - clickSound: tabletRoot.playButtonClickSound(); } } From 580216c3d2d316f739a05eba52cc340a4476f8ab Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 8 Feb 2017 21:56:41 +0000 Subject: [PATCH 64/79] adding tablet-goto.js --- scripts/system/goto.js | 6 ++-- scripts/system/tablet-goto.js | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 scripts/system/tablet-goto.js diff --git a/scripts/system/goto.js b/scripts/system/goto.js index 9e6964b5f0..aea061fce4 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -18,14 +18,12 @@ var button; var buttonName = "GOTO"; var toolBar = null; var tablet = null; -var ADDRESS_DIALOG_QML_SOURCE = "TabletAddressDialog.qml"; function onAddressBarShown(visible) { - //button.editProperties({isActive: visible}); + button.editProperties({isActive: visible}); } function onClicked(){ - //DialogsManager.toggleAddressBar(); - tablet.loadQMLSource(ADDRESS_DIALOG_QML_SOURCE); + DialogsManager.toggleAddressBar(); } if (Settings.getValue("HUDUIEnabled")) { diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js new file mode 100644 index 0000000000..1a3fbab3ea --- /dev/null +++ b/scripts/system/tablet-goto.js @@ -0,0 +1,64 @@ +"use strict"; + +// +// goto.js +// scripts/system/ +// +// Created by Dante Ruiz on 8 February 2017 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { // BEGIN LOCAL_SCOPE + var gotoQmlSource = "TabletAddressDialog.qml"; + var button; + var buttonName = "GOTO"; + var toolBar = null; + var tablet = null; + function onAddressBarShown(visible) { + if (toolBar) { + button.editProperties({isActive: visible}); + } + } + + function onClicked(){ + if (toolBar) { + DialogsManager.toggleAddressBar(); + } else { + tablet.loadQMLSource(gotoQmlSource); + } + } + if (Settings.getValue("HUDUIEnabled")) { + toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); + button = toolBar.addButton({ + objectName: buttonName, + imageURL: Script.resolvePath("assets/images/tools/directory.svg"), + visible: true, + alpha: 0.9 + }); + } else { + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + button = tablet.addButton({ + icon: "icons/tablet-icons/goto-i.svg", + text: buttonName, + sortOrder: 8 + }); + } + + button.clicked.connect(onClicked); + DialogsManager.addressBarShown.connect(onAddressBarShown); + + Script.scriptEnding.connect(function () { + button.clicked.disconnect(onClicked); + if (tablet) { + tablet.removeButton(button); + } + if (toolBar) { + toolBar.removeButton(buttonName); + } + DialogsManager.addressBarShown.disconnect(onAddressBarShown); + }); + +}()); // END LOCAL_SCOPE From 0e83e5da0654606458756a0bb4a0b88bd1b52f38 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 8 Feb 2017 22:03:32 +0000 Subject: [PATCH 65/79] minimize diff --- scripts/system/goto.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/goto.js b/scripts/system/goto.js index aea061fce4..092abd0369 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -18,6 +18,7 @@ var button; var buttonName = "GOTO"; var toolBar = null; var tablet = null; + function onAddressBarShown(visible) { button.editProperties({isActive: visible}); } From ae071aec0d078df3a58d6d32ef19fdf79f3d13de Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 9 Feb 2017 09:52:09 -0800 Subject: [PATCH 66/79] add a bunch more stats for avatar processing --- interface/resources/qml/Stats.qml | 13 ++++++++++++- interface/src/avatar/AvatarManager.cpp | 12 ++++++++++++ interface/src/avatar/AvatarManager.h | 7 +++++++ interface/src/ui/Stats.cpp | 4 ++++ interface/src/ui/Stats.h | 6 ++++++ scripts/developer/debugging/debugAvatarMixer.js | 5 +++-- 6 files changed, 44 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 086c1d15d2..faf37d5366 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -105,6 +105,14 @@ Item { visible: root.expanded text: "Asset Mbps In/Out: " + root.assetMbpsIn.toFixed(2) + "/" + root.assetMbpsOut.toFixed(2) } + StatText { + visible: root.expanded + text: "Fully Simulated Avatars: " + root.fullySimulatedAvatarCount + } + StatText { + visible: root.expanded + text: "Partially Simulated Avatars: " + root.partiallySimulatedAvatarCount + } } } @@ -217,7 +225,10 @@ Item { text: " Batch: " + root.batchFrameTime.toFixed(1) + " ms" } StatText { - text: " GPU: " + root.gpuFrameTime.toFixed(1) + " ms" + text: " GPU: " + root.gpuFrameTime.toFixed(1) + " ms" + } + StatText { + text: " Avatar: " + root.avatarSimulationTime.toFixed(1) + " ms" } StatText { text: "Triangles: " + root.triangles + diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index aff9ec3add..bc5eda60e2 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -230,6 +230,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { const uint64_t MAX_UPDATE_BUDGET = 2000; // usec uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET; uint64_t maxExpiry = startTime + MAX_UPDATE_BUDGET; + + int fullySimulatedAvatars = 0; + int partiallySimulatedAvatars = 0; while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); @@ -258,6 +261,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { avatar->simulate(deltaTime, inView); avatar->updateRenderItem(pendingChanges); avatar->setLastRenderUpdateTime(startTime); + fullySimulatedAvatars++; } else if (now < maxExpiry) { // we've spent most of our time budget, but we still simulate() the avatar as it if were out of view // --> some avatars may freeze until their priority trickles up @@ -271,6 +275,14 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } sortedAvatars.pop(); } + + uint64_t endSimulation = usecTimestampNow(); + int elapsedTime = endSimulation - startTime; + float elapsedFloat = (float)elapsedTime / (float)USECS_PER_MSEC; + qDebug() << "elapsedTime:" << elapsedTime << "elapsedFloat:" << elapsedFloat; + _avatarSimulationTime = elapsedFloat; + _fullySimulatedAvatars = fullySimulatedAvatars; + _partiallySimulatedAvatars = partiallySimulatedAvatars; qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges); simulateAvatarFades(deltaTime); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 00ae745c98..098d8ec34d 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -43,6 +43,10 @@ public: std::shared_ptr getMyAvatar() { return _myAvatar; } AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) override; + int getFullySimulatedAvatars() { return _fullySimulatedAvatars; } + int getPartiallySimulatedAvatars() { return _partiallySimulatedAvatars; } + float getAvatarSimulationTime() { return _avatarSimulationTime; } + void updateMyAvatar(float deltaTime); void updateOtherAvatars(float deltaTime); @@ -112,6 +116,9 @@ private: VectorOfMotionStates _motionStatesToRemoveFromPhysics; RateCounter<> _myAvatarSendRate; + int _fullySimulatedAvatars { 0 }; + int _partiallySimulatedAvatars { 0 }; + float _avatarSimulationTime { 0.0f }; }; diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index ff0028322c..e82f99bed2 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -121,6 +121,8 @@ void Stats::updateStats(bool force) { auto avatarManager = DependencyManager::get(); // we need to take one avatar out so we don't include ourselves STAT_UPDATE(avatarCount, avatarManager->size() - 1); + STAT_UPDATE(fullySimulatedAvatarCount, avatarManager->getFullySimulatedAvatars()); + STAT_UPDATE(partiallySimulatedAvatarCount, avatarManager->getPartiallySimulatedAvatars()); STAT_UPDATE(serverCount, (int)nodeList->size()); STAT_UPDATE(framerate, qApp->getFps()); if (qApp->getActiveDisplayPlugin()) { @@ -306,6 +308,8 @@ void Stats::updateStats(bool force) { // Update Frame timing (in ms) STAT_UPDATE(gpuFrameTime, (float)gpuContext->getFrameTimerGPUAverage()); STAT_UPDATE(batchFrameTime, (float)gpuContext->getFrameTimerBatchAverage()); + STAT_UPDATE(avatarSimulationTime, (float)avatarManager->getAvatarSimulationTime()); + STAT_UPDATE(gpuBuffers, (int)gpu::Context::getBufferGPUCount()); STAT_UPDATE(gpuBufferMemory, (int)BYTES_TO_MB(gpu::Context::getBufferGPUMemoryUsage())); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 3fe851494c..f501f4b09a 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -49,6 +49,8 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, simrate, 0) STATS_PROPERTY(int, avatarSimrate, 0) STATS_PROPERTY(int, avatarCount, 0) + STATS_PROPERTY(int, fullySimulatedAvatarCount, 0) + STATS_PROPERTY(int, partiallySimulatedAvatarCount, 0) STATS_PROPERTY(int, packetInCount, 0) STATS_PROPERTY(int, packetOutCount, 0) STATS_PROPERTY(float, mbpsIn, 0) @@ -111,6 +113,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, gpuFreeMemory, 0) STATS_PROPERTY(float, gpuFrameTime, 0) STATS_PROPERTY(float, batchFrameTime, 0) + STATS_PROPERTY(float, avatarSimulationTime, 0) public: static Stats* getInstance(); @@ -156,6 +159,8 @@ signals: void simrateChanged(); void avatarSimrateChanged(); void avatarCountChanged(); + void fullySimulatedAvatarCountChanged(); + void partiallySimulatedAvatarCountChanged(); void packetInCountChanged(); void packetOutCountChanged(); void mbpsInChanged(); @@ -216,6 +221,7 @@ signals: void gpuFreeMemoryChanged(); void gpuFrameTimeChanged(); void batchFrameTimeChanged(); + void avatarSimulationTimeChanged(); void rectifiedTextureCountChanged(); void decimatedTextureCountChanged(); diff --git a/scripts/developer/debugging/debugAvatarMixer.js b/scripts/developer/debugging/debugAvatarMixer.js index 6b5b0d810e..ebd43fc2f0 100644 --- a/scripts/developer/debugging/debugAvatarMixer.js +++ b/scripts/developer/debugging/debugAvatarMixer.js @@ -60,7 +60,8 @@ function updateOverlays() { var overlayPosition = avatar.getJointPosition("Head"); overlayPosition.y += 1.05; - var text = "--- Data from Mixer ---\n" + var text = avatarID + "\n" + +"--- Data from Mixer ---\n" +"All: " + AvatarManager.getAvatarDataRate(avatarID).toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID).toFixed(2) + "hz)" + "\n" +" GP: " + AvatarManager.getAvatarDataRate(avatarID,"globalPosition").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"globalPosition").toFixed(2) + "hz)" + "\n" +" LP: " + AvatarManager.getAvatarDataRate(avatarID,"localPosition").toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID,"localPosition").toFixed(2) + "hz)" + "\n" @@ -92,7 +93,7 @@ function updateOverlays() { position: overlayPosition, dimensions: { x: 1.25, - y: 18 * 0.13 + y: 19 * 0.13 }, lineHeight: 0.1, font:{size:0.1}, From ff60058cbe219a59d55286975f48b62a0d570fc3 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 9 Feb 2017 17:54:41 +0000 Subject: [PATCH 67/79] checking if desktop exists --- interface/resources/qml/hifi/Card.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 7dd7c63da9..f6f7e88d0c 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -129,7 +129,7 @@ Rectangle { property int dropSamples: 9; property int dropSpread: 0; DropShadow { - visible: showPlace; //&& desktop.gradientsSupported; + visible: showPlace && (desktop ? desktop.gradientsSupported : false) source: place; anchors.fill: place; horizontalOffset: dropHorizontalOffset; From dd2ddcc291831c01d7734551f48715c707c23ebc Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 9 Feb 2017 09:57:32 -0800 Subject: [PATCH 68/79] cleanup --- interface/src/avatar/AvatarManager.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index bc5eda60e2..5a1fb7056f 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -276,11 +276,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { sortedAvatars.pop(); } - uint64_t endSimulation = usecTimestampNow(); - int elapsedTime = endSimulation - startTime; - float elapsedFloat = (float)elapsedTime / (float)USECS_PER_MSEC; - qDebug() << "elapsedTime:" << elapsedTime << "elapsedFloat:" << elapsedFloat; - _avatarSimulationTime = elapsedFloat; + _avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC; _fullySimulatedAvatars = fullySimulatedAvatars; _partiallySimulatedAvatars = partiallySimulatedAvatars; qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges); From 57e0dadd65927aef0071840bed23a2b6e9472d09 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 9 Feb 2017 11:35:00 -0800 Subject: [PATCH 69/79] CR --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/Avatar.h | 2 +- interface/src/avatar/AvatarManager.cpp | 9 +++++---- interface/src/avatar/AvatarManager.h | 14 +++++++------- libraries/avatars/src/AvatarData.cpp | 4 ++-- libraries/avatars/src/AvatarData.h | 4 ++-- libraries/avatars/src/AvatarHashMap.cpp | 2 +- libraries/avatars/src/AvatarHashMap.h | 6 +++--- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 509f6c794a..aa7221f4f0 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -366,7 +366,7 @@ void Avatar::simulate(float deltaTime, bool inView) { } } -float Avatar::getSimulationRate(const QString& rateName) { +float Avatar::getSimulationRate(const QString& rateName) const { if (rateName == "") { return _simulationRate.rate(); } else if (rateName == "avatar") { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index a1c081e327..5c05702e92 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -182,7 +182,7 @@ public: void animateScaleChanges(float deltaTime); void setTargetScale(float targetScale) override; - Q_INVOKABLE float getSimulationRate(const QString& rateName = QString("")); + Q_INVOKABLE float getSimulationRate(const QString& rateName = QString("")) const; public slots: diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 5a1fb7056f..c3fc974365 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -132,17 +132,17 @@ void AvatarManager::updateMyAvatar(float deltaTime) { Q_LOGGING_CATEGORY(trace_simulation_avatar, "trace.simulation.avatar"); -float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& rateName) { +float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& rateName) const { auto avatar = getAvatarBySessionID(sessionID); return avatar ? avatar->getDataRate(rateName) : 0.0f; } -float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName) { +float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName) const { auto avatar = getAvatarBySessionID(sessionID); return avatar ? avatar->getUpdateRate(rateName) : 0.0f; } -float AvatarManager::getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName) { +float AvatarManager::getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName) const { auto avatar = std::static_pointer_cast(getAvatarBySessionID(sessionID)); return avatar ? avatar->getSimulationRate(rateName) : 0.0f; } @@ -267,6 +267,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { // --> some avatars may freeze until their priority trickles up const bool inView = false; avatar->simulate(deltaTime, inView); + partiallySimulatedAvatars++; } else { // we've spent ALL of our time budget --> bail on the rest of the avatar updates // --> some scale or fade animations may glitch @@ -512,7 +513,7 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { } -AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) { +AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) const { if (sessionID == AVATAR_SELF_ID || sessionID == _myAvatar->getSessionUUID()) { return _myAvatar; } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 098d8ec34d..4d503842b9 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -41,11 +41,11 @@ public: void init(); std::shared_ptr getMyAvatar() { return _myAvatar; } - AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) override; + AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) const override; - int getFullySimulatedAvatars() { return _fullySimulatedAvatars; } - int getPartiallySimulatedAvatars() { return _partiallySimulatedAvatars; } - float getAvatarSimulationTime() { return _avatarSimulationTime; } + int getFullySimulatedAvatars() const { return _fullySimulatedAvatars; } + int getPartiallySimulatedAvatars() const { return _partiallySimulatedAvatars; } + float getAvatarSimulationTime() const { return _avatarSimulationTime; } void updateMyAvatar(float deltaTime); void updateOtherAvatars(float deltaTime); @@ -73,9 +73,9 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString("")); - Q_INVOKABLE float getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName = QString("")); - Q_INVOKABLE float getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName = QString("")); + Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString("")) const; + Q_INVOKABLE float getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName = QString("")) const; + Q_INVOKABLE float getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName = QString("")) const; Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index aaf5a639a6..af060429af 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1064,7 +1064,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { return numBytesRead; } -float AvatarData::getDataRate(const QString& rateName) { +float AvatarData::getDataRate(const QString& rateName) const { if (rateName == "") { return _parseBufferRate.rate() / BYTES_PER_KILOBIT; } else if (rateName == "globalPosition") { @@ -1119,7 +1119,7 @@ float AvatarData::getDataRate(const QString& rateName) { return 0.0f; } -float AvatarData::getUpdateRate(const QString& rateName) { +float AvatarData::getUpdateRate(const QString& rateName) const { if (rateName == "") { return _parseBufferUpdateRate.rate(); } else if (rateName == "globalPosition") { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index d23e4f5caf..01cab8b93a 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -547,8 +547,8 @@ public: Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const; Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const; - Q_INVOKABLE float getDataRate(const QString& rateName = QString("")); - Q_INVOKABLE float getUpdateRate(const QString& rateName = QString("")); + Q_INVOKABLE float getDataRate(const QString& rateName = QString("")) const; + Q_INVOKABLE float getUpdateRate(const QString& rateName = QString("")) const; int getJointCount() { return _jointData.size(); } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 9d43bf438b..00c515a635 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -90,7 +90,7 @@ AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, return avatar; } -AvatarSharedPointer AvatarHashMap::findAvatar(const QUuid& sessionUUID) { +AvatarSharedPointer AvatarHashMap::findAvatar(const QUuid& sessionUUID) const { QReadLocker locker(&_hashLock); if (_avatarHash.contains(sessionUUID)) { return _avatarHash.value(sessionUUID); diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index eae4026bfc..dd097aef22 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -40,7 +40,7 @@ public: Q_INVOKABLE QVector getAvatarIdentifiers(); Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID); - virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) { return findAvatar(sessionID); } + virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) const { return findAvatar(sessionID); } int numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters); signals: @@ -65,7 +65,7 @@ protected: virtual AvatarSharedPointer newSharedAvatar(); virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); AvatarSharedPointer newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); - virtual AvatarSharedPointer findAvatar(const QUuid& sessionUUID); // uses a QReadLocker on the hashLock + virtual AvatarSharedPointer findAvatar(const QUuid& sessionUUID) const; // uses a QReadLocker on the hashLock virtual void removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason = KillAvatarReason::NoReason); virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason); @@ -73,7 +73,7 @@ protected: AvatarHash _avatarHash; // "Case-based safety": Most access to the _avatarHash is on the same thread. Write access is protected by a write-lock. // If you read from a different thread, you must read-lock the _hashLock. (Scripted write access is not supported). - QReadWriteLock _hashLock; + mutable QReadWriteLock _hashLock; private: QUuid _lastOwnerSessionUUID; From bb4654506a18c87838c8595477c59cc4d3c0be8d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 9 Feb 2017 11:37:21 -0800 Subject: [PATCH 70/79] CR --- interface/src/avatar/Avatar.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index aa7221f4f0..ab97f563f6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -306,12 +306,14 @@ bool Avatar::shouldDie() const { } void Avatar::simulate(float deltaTime, bool inView) { + PROFILE_RANGE(simulation, "simulate"); + _simulationRate.increment(); if (inView) { _simulationInViewRate.increment(); } - PROFILE_RANGE(simulation, "simulate"); + PerformanceTimer perfTimer("simulate"); { PROFILE_RANGE(simulation, "updateJoints"); From fcb74bce1007f1c56613c13c5e5973c85c05b76d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 31 Jan 2017 16:09:56 -0800 Subject: [PATCH 71/79] First draft for entity script server log streaming --- assignment-client/src/AssignmentClient.h | 1 + .../src/scripts/EntityScriptServer.cpp | 115 ++++++++++++++++-- .../src/scripts/EntityScriptServer.h | 10 ++ interface/src/ui/LogDialog.cpp | 33 ++++- interface/src/ui/LogDialog.h | 3 + .../networking/src/EntityScriptClient.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- 7 files changed, 155 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 5147bfca98..28464bc222 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -27,6 +27,7 @@ public: QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort, quint16 assignmentMonitorPort); ~AssignmentClient(); + private slots: void sendAssignmentRequest(); void assignmentCompleted(); diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index bd79d0fc04..2df97760fe 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -27,9 +27,30 @@ #include "ClientServerUtils.h" #include "../entities/AssignmentParentFinder.h" + +#include +#include + +using Mutex = std::mutex; +using Lock = std::lock_guard; + +static std::mutex logBufferMutex; +static std::string logBuffer; + +void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { + auto logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); + + if (!logMessage.isEmpty()) { + Lock lock(logBufferMutex); + logBuffer.append(logMessage.toStdString() + '\n'); + } +} + int EntityScriptServer::_entitiesScriptEngineCount = 0; EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) { + qInstallMessageHandler(messageHandler); + DependencyManager::get()->setPacketSender(&_entityEditSender); ResourceManager::init(); @@ -57,6 +78,18 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket"); packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket"); + packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); + + static const int LOG_INTERVAL = MSECS_PER_SECOND / 50; + auto timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setInterval(LOG_INTERVAL); + connect(timer, &QTimer::timeout, this, &EntityScriptServer::pushLogs); + timer->start(); +} + +EntityScriptServer::~EntityScriptServer() { + qInstallMessageHandler(LogHandler::verboseMessageHandler); } static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server"; @@ -146,6 +179,60 @@ void EntityScriptServer::updateEntityPPS() { qDebug() << QString("Updating entity PPS to: %1 @ %2 PPS per script = %3 PPS").arg(numRunningScripts).arg(_entityPPSPerScript).arg(pps); } +void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { + // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them + // about each other. + if (senderNode->getCanRez() || senderNode->getCanRezTmp()) { + bool enable = false; + message->readPrimitive(&enable); + qInfo() << "======== Got log packet:" << enable; + + if (enable) { + _logListeners.insert(senderNode->getUUID()); + } else { + _logListeners.erase(senderNode->getUUID()); + } + } +} + +void EntityScriptServer::pushLogs() { + std::string buffer; + { + Lock lock(logBufferMutex); + std::swap(logBuffer, buffer); + } + + if (buffer.empty()) { + return; + } + if (_logListeners.empty()) { + return; + } + + auto packet = NLPacket::create(PacketType::EntityServerScriptLog, buffer.size(), true); + packet->write(buffer.data(), buffer.size()); + + auto nodeList = DependencyManager::get(); + + auto last = --std::end(_logListeners); + for (auto it = std::begin(_logListeners); it != last; ++it) { + auto node = nodeList->nodeWithUUID(*it); + if (node && node->getActiveSocket()) { + auto copy = NLPacket::createCopy(*packet); + nodeList->sendPacket(std::move(copy), *node); + } else { + qWarning() << "Node not found"; + } + } + + auto node = nodeList->nodeWithUUID(*last); + if (node && node->getActiveSocket()) { + nodeList->sendPacket(std::move(packet), *node); + } else { + qWarning() << "Node not found"; + } +} + void EntityScriptServer::run() { // make sure we request our script once the agent connects to the domain auto nodeList = DependencyManager::get(); @@ -347,15 +434,27 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, const } void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { - if (!_shuttingDown && killedNode->getType() == NodeType::EntityServer) { - if (_entitiesScriptEngine) { - _entitiesScriptEngine->unloadAllEntityScripts(); - _entitiesScriptEngine->stop(); + switch (killedNode->getType()) { + case NodeType::EntityServer: { + if (!_shuttingDown) { + if (_entitiesScriptEngine) { + _entitiesScriptEngine->unloadAllEntityScripts(); + _entitiesScriptEngine->stop(); + } + + resetEntitiesScriptEngine(); + + _entityViewer.clear(); + } + break; } - - resetEntitiesScriptEngine(); - - _entityViewer.clear(); + case NodeType::Agent: { + _logListeners.erase(killedNode->getUUID()); + break; + } + default: + // Do nothing + break; } } diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index 70f03977f8..5337b68eb7 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -12,7 +12,10 @@ #ifndef hifi_EntityScriptServer_h #define hifi_EntityScriptServer_h +#include + #include +#include #include #include @@ -28,6 +31,7 @@ class EntityScriptServer : public ThreadedAssignment { public: EntityScriptServer(ReceivedMessage& message); + ~EntityScriptServer(); virtual void aboutToFinish() override; @@ -48,6 +52,10 @@ private slots: void handleSettings(); void updateEntityPPS(); + void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + + void pushLogs(); + private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); @@ -71,6 +79,8 @@ private: int _maxEntityPPS { DEFAULT_MAX_ENTITY_PPS }; int _entityPPSPerScript { DEFAULT_ENTITY_PPS_PER_SCRIPT }; + std::set _logListeners; + QString _selectedCodecName; CodecPluginPointer _codec; Encoder* _encoder { nullptr }; diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 1e56d0cfd9..1ba8fb5ff8 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -46,6 +46,9 @@ int qTextBlockMeta = qRegisterMetaType("QTextBlock"); LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : QDialog(parent, Qt::Window) { + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); + _logger = logger; setWindowTitle("Log"); setAttribute(Qt::WA_DeleteOnClose); @@ -64,7 +67,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : QDialog move(screen.center() - rect().center()); setMinimumWidth(MINIMAL_WIDTH); - connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)), Qt::QueuedConnection); + //connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)), Qt::QueuedConnection); } LogDialog::~LogDialog() { @@ -97,7 +100,8 @@ void LogDialog::initControls() { _extraDebuggingBox->setCheckState(Qt::Checked); } _extraDebuggingBox->show(); - connect(_extraDebuggingBox, SIGNAL(stateChanged(int)), SLOT(handleExtraDebuggingCheckbox(int))); + //connect(_extraDebuggingBox, SIGNAL(stateChanged(int)), SLOT(handleExtraDebuggingCheckbox(int))); + connect(_extraDebuggingBox, &QCheckBox::stateChanged, this, &LogDialog::enableToEntityServerScriptLog); _revealLogButton = new QPushButton("Reveal log file", this); // set object name for css styling @@ -156,6 +160,31 @@ void LogDialog::showLogData() { _logTextBox->ensureCursorVisible(); } + +void LogDialog::enableToEntityServerScriptLog(bool enable) { + qDebug() << Q_FUNC_INFO << enable; + auto nodeList = DependencyManager::get(); + + if (auto node = nodeList->soloNodeOfType(NodeType::EntityScriptServer)) { + auto packet = NLPacket::create(PacketType::EntityServerScriptLog, sizeof(bool), true); + packet->writePrimitive(enable); + nodeList->sendPacket(std::move(packet), *node); + + if (enable) { + appendLogLine("====================== Subscribded to the Entity Script Server's log ======================"); + } else { + appendLogLine("==================== Unsubscribded from the Entity Script Server's log ===================="); + } + } else { + qWarning() << "Entity Script Server not found"; + } +} + +void LogDialog::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { + auto lines = QString::fromUtf8(message->readAll()); + QMetaObject::invokeMethod(this, "appendLogLine", Q_ARG(QString, lines)); +} + KeywordHighlighter::KeywordHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent), keywordFormat() { keywordFormat.setForeground(QColor(HIGHLIGHT_COLOR)); } diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index 1493a43f01..4f366257ec 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -53,6 +53,9 @@ private slots: void handleExtraDebuggingCheckbox(const int); void handleSearchTextChanged(const QString); + void enableToEntityServerScriptLog(bool enable); + void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + protected: void resizeEvent(QResizeEvent*) override; void showEvent(QShowEvent*) override; diff --git a/libraries/networking/src/EntityScriptClient.cpp b/libraries/networking/src/EntityScriptClient.cpp index 604a82fcca..a2c01312e6 100644 --- a/libraries/networking/src/EntityScriptClient.cpp +++ b/libraries/networking/src/EntityScriptClient.cpp @@ -162,4 +162,4 @@ void EntityScriptClient::forceFailureOfPendingRequests(SharedNodePointer node) { messageMapIt->second.clear(); } } -} \ No newline at end of file +} diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 88b5ec19ad..e1197bf8a5 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -111,7 +111,8 @@ public: EntityScriptGetStatusReply, ReloadEntityServerScript, EntityPhysics, - LAST_PACKET_TYPE = EntityPhysics + EntityServerScriptLog, + LAST_PACKET_TYPE = EntityServerScriptLog }; }; From 2962dd6dc27bf7b817aace1cb36ab3a745077670 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 31 Jan 2017 19:03:57 -0800 Subject: [PATCH 72/79] Factor LogDialog --- interface/src/Application.cpp | 1 + interface/src/ui/BaseLogDialog.cpp | 139 +++++++++++++++++++++++++++ interface/src/ui/BaseLogDialog.h | 60 ++++++++++++ interface/src/ui/LogDialog.cpp | 143 +++------------------------- interface/src/ui/LogDialog.h | 54 +++-------- libraries/shared/src/LogHandler.cpp | 2 +- 6 files changed, 226 insertions(+), 173 deletions(-) create mode 100644 interface/src/ui/BaseLogDialog.cpp create mode 100644 interface/src/ui/BaseLogDialog.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d39ad337a8..964549d283 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -41,6 +41,7 @@ #include +#include #include #include diff --git a/interface/src/ui/BaseLogDialog.cpp b/interface/src/ui/BaseLogDialog.cpp new file mode 100644 index 0000000000..cb8a510c26 --- /dev/null +++ b/interface/src/ui/BaseLogDialog.cpp @@ -0,0 +1,139 @@ +// +// BaseLogDialog.cpp +// interface/src/ui +// +// Created by Clement Brisset on 1/31/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BaseLogDialog.h" + +#include +#include +#include +#include +#include + +#include + +const int TOP_BAR_HEIGHT = 46; +const int INITIAL_WIDTH = 720; +const int INITIAL_HEIGHT = 480; +const int MINIMAL_WIDTH = 570; +const int SEARCH_BUTTON_LEFT = 25; +const int SEARCH_BUTTON_WIDTH = 20; +const int SEARCH_TEXT_WIDTH = 240; +const QColor HIGHLIGHT_COLOR = QColor("#3366CC"); + +class KeywordHighlighter : public QSyntaxHighlighter { +public: + KeywordHighlighter(QTextDocument* parent = nullptr); + QString keyword; + +protected: + void highlightBlock(const QString& text) override; + +private: + QTextCharFormat keywordFormat; + +}; + +BaseLogDialog::BaseLogDialog(QWidget* parent) : QDialog(parent, Qt::Window) { + setWindowTitle("Base Log"); + setAttribute(Qt::WA_DeleteOnClose); + + QFile styleSheet(PathUtils::resourcesPath() + "styles/log_dialog.qss"); + if (styleSheet.open(QIODevice::ReadOnly)) { + QDir::setCurrent(PathUtils::resourcesPath()); + setStyleSheet(styleSheet.readAll()); + } + + initControls(); + + resize(INITIAL_WIDTH, INITIAL_HEIGHT); + setMinimumWidth(MINIMAL_WIDTH); +} + +BaseLogDialog::~BaseLogDialog() { + deleteLater(); +} + +void BaseLogDialog::initControls() { + _searchButton = new QPushButton(this); + // set object name for css styling + _searchButton->setObjectName("searchButton"); + _leftPad = SEARCH_BUTTON_LEFT; + _searchButton->setGeometry(_leftPad, ELEMENT_MARGIN, SEARCH_BUTTON_WIDTH, ELEMENT_HEIGHT); + _leftPad += SEARCH_BUTTON_WIDTH; + _searchButton->show(); + connect(_searchButton, SIGNAL(clicked()), SLOT(handleSearchButton())); + + _searchTextBox = new QLineEdit(this); + // disable blue outline in Mac + _searchTextBox->setAttribute(Qt::WA_MacShowFocusRect, false); + _searchTextBox->setGeometry(_leftPad, ELEMENT_MARGIN, SEARCH_TEXT_WIDTH, ELEMENT_HEIGHT); + _leftPad += SEARCH_TEXT_WIDTH + CHECKBOX_MARGIN; + _searchTextBox->show(); + connect(_searchTextBox, SIGNAL(textChanged(QString)), SLOT(handleSearchTextChanged(QString))); + + _logTextBox = new QPlainTextEdit(this); + _logTextBox->setReadOnly(true); + _logTextBox->show(); + _highlighter = new KeywordHighlighter(_logTextBox->document()); + +} + +void BaseLogDialog::showEvent(QShowEvent* event) { + showLogData(); +} + +void BaseLogDialog::resizeEvent(QResizeEvent* event) { + _logTextBox->setGeometry(0, TOP_BAR_HEIGHT, width(), height() - TOP_BAR_HEIGHT); +} + +void BaseLogDialog::appendLogLine(QString logLine) { + if (isVisible()) { + if (logLine.contains(_searchTerm, Qt::CaseInsensitive)) { + _logTextBox->appendPlainText(logLine.trimmed()); + } + } +} + +void BaseLogDialog::handleSearchButton() { + _searchTextBox->setFocus(); +} + +void BaseLogDialog::handleSearchTextChanged(QString searchText) { + _searchTerm = searchText; + _highlighter->keyword = searchText; + showLogData(); +} + +void BaseLogDialog::showLogData() { + _logTextBox->clear(); + _logTextBox->insertPlainText(getCurrentLog()); + _logTextBox->ensureCursorVisible(); +} + + + +KeywordHighlighter::KeywordHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent) { + keywordFormat.setForeground(HIGHLIGHT_COLOR); +} + +void KeywordHighlighter::highlightBlock(const QString& text) { + if (keyword.isNull() || keyword.isEmpty()) { + return; + } + + int index = text.indexOf(keyword, 0, Qt::CaseInsensitive); + int length = keyword.length(); + + while (index >= 0) { + setFormat(index, length, keywordFormat); + index = text.indexOf(keyword, index + length, Qt::CaseInsensitive); + } +} diff --git a/interface/src/ui/BaseLogDialog.h b/interface/src/ui/BaseLogDialog.h new file mode 100644 index 0000000000..72fe83cd82 --- /dev/null +++ b/interface/src/ui/BaseLogDialog.h @@ -0,0 +1,60 @@ +// +// BaseLogDialog.h +// interface/src/ui +// +// Created by Clement Brisset on 1/31/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BaseLogDialog_h +#define hifi_BaseLogDialog_h + +#include + +const int ELEMENT_MARGIN = 7; +const int ELEMENT_HEIGHT = 32; +const int CHECKBOX_MARGIN = 12; +const int CHECKBOX_WIDTH = 140; + +class QPushButton; +class QLineEdit; +class QPlainTextEdit; +class KeywordHighlighter; + +class BaseLogDialog : public QDialog { + Q_OBJECT + +public: + BaseLogDialog(QWidget* parent); + ~BaseLogDialog(); + +public slots: + void appendLogLine(QString logLine); + +private slots: + void handleSearchButton(); + void handleSearchTextChanged(QString text); + +protected: + int _leftPad { 0 }; + + void resizeEvent(QResizeEvent* event) override; + void showEvent(QShowEvent* event) override; + virtual QString getCurrentLog() = 0; + +private: + QPushButton* _searchButton { nullptr }; + QLineEdit* _searchTextBox { nullptr }; + QPlainTextEdit* _logTextBox { nullptr }; + QString _searchTerm; + KeywordHighlighter* _highlighter { nullptr }; + + void initControls(); + void showLogData(); +}; + + +#endif // hifi_BaseLogDialog_h diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 1ba8fb5ff8..809fbd3772 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -9,93 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdouble-promotion" -#endif +#include "LogDialog.h" -#include -#include +#include +#include -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif +#include -#include -#include - -#include "Application.h" -#include "ui/LogDialog.h" - -const int TOP_BAR_HEIGHT = 46; -const int INITIAL_WIDTH = 720; -const int MINIMAL_WIDTH = 570; -const int ELEMENT_MARGIN = 7; -const int ELEMENT_HEIGHT = 32; -const int SEARCH_BUTTON_LEFT = 25; -const int SEARCH_BUTTON_WIDTH = 20; -const int SEARCH_TEXT_WIDTH = 240; -const int CHECKBOX_MARGIN = 12; -const int CHECKBOX_WIDTH = 140; const int REVEAL_BUTTON_WIDTH = 122; -const float INITIAL_HEIGHT_RATIO = 0.6f; -const QString HIGHLIGHT_COLOR = "#3366CC"; - -int qTextCursorMeta = qRegisterMetaType("QTextCursor"); -int qTextBlockMeta = qRegisterMetaType("QTextBlock"); - -LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : QDialog(parent, Qt::Window) { - - auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); +LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLogDialog(parent) { _logger = logger; setWindowTitle("Log"); - setAttribute(Qt::WA_DeleteOnClose); - - QFile styleSheet(PathUtils::resourcesPath() + "styles/log_dialog.qss"); - if (styleSheet.open(QIODevice::ReadOnly)) { - QDir::setCurrent(PathUtils::resourcesPath()); - setStyleSheet(styleSheet.readAll()); - } - - initControls(); - - QDesktopWidget desktop; - QRect screen = desktop.screenGeometry(); - resize(INITIAL_WIDTH, static_cast(screen.height() * INITIAL_HEIGHT_RATIO)); - move(screen.center() - rect().center()); - setMinimumWidth(MINIMAL_WIDTH); - - //connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)), Qt::QueuedConnection); -} - -LogDialog::~LogDialog() { - deleteLater(); -} - -void LogDialog::initControls() { - - int left; - _searchButton = new QPushButton(this); - // set object name for css styling - _searchButton->setObjectName("searchButton"); - left = SEARCH_BUTTON_LEFT; - _searchButton->setGeometry(left, ELEMENT_MARGIN, SEARCH_BUTTON_WIDTH, ELEMENT_HEIGHT); - left += SEARCH_BUTTON_WIDTH; - _searchButton->show(); - connect(_searchButton, SIGNAL(clicked()), SLOT(handleSearchButton())); - - _searchTextBox = new QLineEdit(this); - // disable blue outline in Mac - _searchTextBox->setAttribute(Qt::WA_MacShowFocusRect, false); - _searchTextBox->setGeometry(left, ELEMENT_MARGIN, SEARCH_TEXT_WIDTH, ELEMENT_HEIGHT); - left += SEARCH_TEXT_WIDTH + CHECKBOX_MARGIN; - _searchTextBox->show(); - connect(_searchTextBox, SIGNAL(textChanged(QString)), SLOT(handleSearchTextChanged(QString))); _extraDebuggingBox = new QCheckBox("Extra debugging", this); - _extraDebuggingBox->setGeometry(left, ELEMENT_MARGIN, CHECKBOX_WIDTH, ELEMENT_HEIGHT); + _extraDebuggingBox->setGeometry(_leftPad, ELEMENT_MARGIN, CHECKBOX_WIDTH, ELEMENT_HEIGHT); if (_logger->extraDebugging()) { _extraDebuggingBox->setCheckState(Qt::Checked); } @@ -109,37 +37,19 @@ void LogDialog::initControls() { _revealLogButton->show(); connect(_revealLogButton, SIGNAL(clicked()), SLOT(handleRevealButton())); - _logTextBox = new QPlainTextEdit(this); - _logTextBox->setReadOnly(true); - _logTextBox->show(); - _highlighter = new KeywordHighlighter(_logTextBox->document()); - + //connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)), Qt::QueuedConnection); + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); } -void LogDialog::showEvent(QShowEvent*) { - showLogData(); -} - -void LogDialog::resizeEvent(QResizeEvent*) { - _logTextBox->setGeometry(0, TOP_BAR_HEIGHT, width(), height() - TOP_BAR_HEIGHT); +void LogDialog::resizeEvent(QResizeEvent* event) { + BaseLogDialog::resizeEvent(event); _revealLogButton->setGeometry(width() - ELEMENT_MARGIN - REVEAL_BUTTON_WIDTH, ELEMENT_MARGIN, REVEAL_BUTTON_WIDTH, ELEMENT_HEIGHT); } -void LogDialog::appendLogLine(QString logLine) { - if (isVisible()) { - if (logLine.contains(_searchTerm, Qt::CaseInsensitive)) { - _logTextBox->appendPlainText(logLine.trimmed()); - } - } -} - -void LogDialog::handleSearchButton() { - _searchTextBox->setFocus(); -} - void LogDialog::handleRevealButton() { _logger->locateLog(); } @@ -148,19 +58,10 @@ void LogDialog::handleExtraDebuggingCheckbox(const int state) { _logger->setExtraDebugging(state != 0); } -void LogDialog::handleSearchTextChanged(const QString searchText) { - _searchTerm = searchText; - _highlighter->keyword = searchText; - showLogData(); +QString LogDialog::getCurrentLog() { + return _logger->getLogData(); } -void LogDialog::showLogData() { - _logTextBox->clear(); - _logTextBox->insertPlainText(_logger->getLogData()); - _logTextBox->ensureCursorVisible(); -} - - void LogDialog::enableToEntityServerScriptLog(bool enable) { qDebug() << Q_FUNC_INFO << enable; auto nodeList = DependencyManager::get(); @@ -185,21 +86,3 @@ void LogDialog::handleEntityServerScriptLogPacket(QSharedPointer= 0) { - setFormat(index, length, keywordFormat); - index = text.indexOf(keyword, index + length, Qt::CaseInsensitive); - } -} diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index 4f366257ec..406d5ce74e 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -12,67 +12,37 @@ #ifndef hifi_LogDialog_h #define hifi_LogDialog_h -#include -#include -#include -#include -#include -#include -#include +#include "BaseLogDialog.h" -#include +#include -class KeywordHighlighter : public QSyntaxHighlighter { +class QCheckBox; +class QPushButton; +class QResizeEvent; +class AbstractLoggerInterface; + +class LogDialog : public BaseLogDialog { Q_OBJECT public: - KeywordHighlighter(QTextDocument *parent = 0); - QString keyword; - -protected: - void highlightBlock(const QString &text) override; - -private: - QTextCharFormat keywordFormat; - -}; - -class LogDialog : public QDialog { - Q_OBJECT - -public: - LogDialog(QWidget*, AbstractLoggerInterface*); - ~LogDialog(); - -public slots: - void appendLogLine(QString logLine); + LogDialog(QWidget* parent, AbstractLoggerInterface* logger); private slots: - void handleSearchButton(); void handleRevealButton(); void handleExtraDebuggingCheckbox(const int); - void handleSearchTextChanged(const QString); void enableToEntityServerScriptLog(bool enable); void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); protected: - void resizeEvent(QResizeEvent*) override; - void showEvent(QShowEvent*) override; - + void resizeEvent(QResizeEvent* event) override; + QString getCurrentLog() override; + private: - QPushButton* _searchButton; - QLineEdit* _searchTextBox; QCheckBox* _extraDebuggingBox; QPushButton* _revealLogButton; - QPlainTextEdit* _logTextBox; - QString _searchTerm; - KeywordHighlighter* _highlighter; AbstractLoggerInterface* _logger; - - void initControls(); - void showLogData(); }; #endif // hifi_LogDialog_h diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 8e2c372bb6..e40ef814ea 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -177,7 +177,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont prefixString.append(QString(" [%1]").arg(_targetName)); } - QString logMessage = QString("%1 %2").arg(prefixString, message.split("\n").join("\n" + prefixString + " ")); + QString logMessage = QString("%1 %2").arg(prefixString, message.split('\n').join('\n' + prefixString + " ")); fprintf(stdout, "%s\n", qPrintable(logMessage)); return logMessage; } From 191121888c5e9b8f377d5dedd7cac503439e6edc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 1 Feb 2017 13:07:58 -0800 Subject: [PATCH 73/79] Add log window to the ESS log --- .../src/scripts/EntityScriptServer.cpp | 101 ++++++++++++------ .../src/scripts/EntityScriptServer.h | 4 + interface/src/Application.cpp | 11 ++ interface/src/Application.h | 3 + interface/src/Menu.cpp | 11 +- interface/src/Menu.h | 1 + interface/src/ui/BaseLogDialog.cpp | 13 +-- .../src/ui/EntityScriptServerLogDialog.cpp | 58 ++++++++++ .../src/ui/EntityScriptServerLogDialog.h | 37 +++++++ interface/src/ui/LogDialog.cpp | 34 +----- interface/src/ui/LogDialog.h | 7 +- 11 files changed, 203 insertions(+), 77 deletions(-) create mode 100644 interface/src/ui/EntityScriptServerLogDialog.cpp create mode 100644 interface/src/ui/EntityScriptServerLogDialog.h diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 2df97760fe..1975b0ce15 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -185,12 +185,20 @@ void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointergetCanRez() || senderNode->getCanRezTmp()) { bool enable = false; message->readPrimitive(&enable); - qInfo() << "======== Got log packet:" << enable; + + auto senderUUID = senderNode->getUUID(); + auto it = _logListeners.find(senderUUID); if (enable) { - _logListeners.insert(senderNode->getUUID()); + if (it == std::end(_logListeners)) { + _logListeners.insert(senderUUID); + qInfo() << "Node" << senderUUID << "subscribed to log stream"; + } } else { - _logListeners.erase(senderNode->getUUID()); + if (it != std::end(_logListeners)) { + _logListeners.erase(it); + qInfo() << "Node" << senderUUID << "unsubscribed from log stream"; + } } } } @@ -290,9 +298,67 @@ void EntityScriptServer::run() { connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection); } +void EntityScriptServer::cleanupOldKilledListeners() { + auto threshold = usecTimestampNow() - 5 * USECS_PER_SECOND; + using ValueType = std::pair; + auto it = std::remove_if(std::begin(_killedListeners), std::end(_killedListeners), [&](ValueType value) { + return value.second < threshold; + }); + _killedListeners.erase(it, std::end(_killedListeners)); +} + void EntityScriptServer::nodeActivated(SharedNodePointer activatedNode) { - if (activatedNode->getType() == NodeType::AudioMixer) { - negotiateAudioFormat(); + switch (activatedNode->getType()) { + case NodeType::AudioMixer: + negotiateAudioFormat(); + break; + case NodeType::Agent: { + auto activatedNodeUUID = activatedNode->getUUID(); + using ValueType = std::pair; + auto it = std::find_if(std::begin(_killedListeners), std::end(_killedListeners), [&](ValueType value) { + return value.first == activatedNodeUUID; + }); + if (it != std::end(_killedListeners)) { + _killedListeners.erase(it); + _logListeners.insert(activatedNodeUUID); + } + break; + } + default: + // Do nothing + break; + } +} + +void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { + switch (killedNode->getType()) { + case NodeType::EntityServer: { + if (!_shuttingDown) { + if (_entitiesScriptEngine) { + _entitiesScriptEngine->unloadAllEntityScripts(); + _entitiesScriptEngine->stop(); + } + + resetEntitiesScriptEngine(); + + _entityViewer.clear(); + } + break; + } + case NodeType::Agent: { + cleanupOldKilledListeners(); + + auto killedNodeUUID = killedNode->getUUID(); + auto it = _logListeners.find(killedNodeUUID); + if (it != std::end(_logListeners)) { + _logListeners.erase(killedNodeUUID); + _killedListeners.emplace_back(killedNodeUUID, usecTimestampNow()); + } + break; + } + default: + // Do nothing + break; } } @@ -433,31 +499,6 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, const } } -void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { - switch (killedNode->getType()) { - case NodeType::EntityServer: { - if (!_shuttingDown) { - if (_entitiesScriptEngine) { - _entitiesScriptEngine->unloadAllEntityScripts(); - _entitiesScriptEngine->stop(); - } - - resetEntitiesScriptEngine(); - - _entityViewer.clear(); - } - break; - } - case NodeType::Agent: { - _logListeners.erase(killedNode->getUUID()); - break; - } - default: - // Do nothing - break; - } -} - void EntityScriptServer::sendStatsPacket() { } diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index 5337b68eb7..a468e62958 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -13,6 +13,7 @@ #define hifi_EntityScriptServer_h #include +#include #include #include @@ -69,6 +70,8 @@ private: void entityServerScriptChanging(const EntityItemID& entityID, const bool reload); void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false); + void cleanupOldKilledListeners(); + bool _shuttingDown { false }; static int _entitiesScriptEngineCount; @@ -80,6 +83,7 @@ private: int _entityPPSPerScript { DEFAULT_ENTITY_PPS_PER_SCRIPT }; std::set _logListeners; + std::vector> _killedListeners; QString _selectedCodecName; CodecPluginPointer _codec; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 964549d283..cb340863f7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6284,6 +6284,17 @@ void Application::toggleLogDialog() { } } +void Application::toggleEntityScriptServerLogDialog() { + if (! _entityScriptServerLogDialog) { + _entityScriptServerLogDialog = new EntityScriptServerLogDialog(nullptr); + } + + if (_entityScriptServerLogDialog->isVisible()) { + _entityScriptServerLogDialog->hide(); + } else { + _entityScriptServerLogDialog->show(); + } +} void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio) { postLambdaEvent([notify, includeAnimated, aspectRatio, this] { diff --git a/interface/src/Application.h b/interface/src/Application.h index 05ff5beb48..6072acac93 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -62,6 +62,7 @@ #include "scripting/DialogsManagerScriptingInterface.h" #include "ui/ApplicationOverlay.h" #include "ui/BandwidthDialog.h" +#include "ui/EntityScriptServerLogDialog.h" #include "ui/LodToolsDialog.h" #include "ui/LogDialog.h" #include "ui/OctreeStatsDialog.h" @@ -314,6 +315,7 @@ public slots: Q_INVOKABLE void loadDialog(); Q_INVOKABLE void loadScriptURLDialog() const; void toggleLogDialog(); + void toggleEntityScriptServerLogDialog(); void toggleRunningScriptsWidget() const; Q_INVOKABLE void showAssetServerWidget(QString filePath = ""); @@ -566,6 +568,7 @@ private: NodeToOctreeSceneStats _octreeServerSceneStats; ControllerScriptingInterface* _controllerScriptingInterface{ nullptr }; QPointer _logDialog; + QPointer _entityScriptServerLogDialog; FileLogger* _logger; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 870d60fdf3..bc4de76f1c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -702,7 +702,16 @@ Menu::Menu() { // Developer > Log... addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L, - qApp, SLOT(toggleLogDialog())); + qApp, SLOT(toggleLogDialog())); + auto essLogAction = addActionToQMenuAndActionHash(developerMenu, MenuOption::EntityScriptServerLog, 0, + qApp, SLOT(toggleEntityScriptServerLogDialog())); + auto shouldEnableLog = [essLogAction] { + auto nodeList = DependencyManager::get(); + essLogAction->setEnabled(nodeList->getThisNodeCanRez() || nodeList->getThisNodeCanRezTmp()); + }; + QObject::connect(nodeList.data(), &NodeList::canRezChanged, essLogAction, shouldEnableLog); + QObject::connect(nodeList.data(), &NodeList::canRezTmpChanged, essLogAction, shouldEnableLog); + shouldEnableLog(); action = addActionToQMenuAndActionHash(developerMenu, "Script Log (HMD friendly)..."); connect(action, &QAction::triggered, [] { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e2a368db2d..1b2564735b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -98,6 +98,7 @@ namespace MenuOption { const QString EchoServerAudio = "Echo Server Audio"; const QString EnableCharacterController = "Enable avatar collisions"; const QString EnableInverseKinematics = "Enable Inverse Kinematics"; + const QString EntityScriptServerLog = "Entity Script Server Log"; const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; const QString ExpandMyAvatarTiming = "Expand /myAvatar"; const QString ExpandOtherAvatarTiming = "Expand /otherAvatar"; diff --git a/interface/src/ui/BaseLogDialog.cpp b/interface/src/ui/BaseLogDialog.cpp index cb8a510c26..c17ede4a56 100644 --- a/interface/src/ui/BaseLogDialog.cpp +++ b/interface/src/ui/BaseLogDialog.cpp @@ -95,10 +95,8 @@ void BaseLogDialog::resizeEvent(QResizeEvent* event) { } void BaseLogDialog::appendLogLine(QString logLine) { - if (isVisible()) { - if (logLine.contains(_searchTerm, Qt::CaseInsensitive)) { - _logTextBox->appendPlainText(logLine.trimmed()); - } + if (logLine.contains(_searchTerm, Qt::CaseInsensitive)) { + _logTextBox->appendPlainText(logLine.trimmed()); } } @@ -109,17 +107,14 @@ void BaseLogDialog::handleSearchButton() { void BaseLogDialog::handleSearchTextChanged(QString searchText) { _searchTerm = searchText; _highlighter->keyword = searchText; - showLogData(); + _highlighter->rehighlight(); } void BaseLogDialog::showLogData() { - _logTextBox->clear(); - _logTextBox->insertPlainText(getCurrentLog()); + _logTextBox->setPlainText(getCurrentLog()); _logTextBox->ensureCursorVisible(); } - - KeywordHighlighter::KeywordHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent) { keywordFormat.setForeground(HIGHLIGHT_COLOR); } diff --git a/interface/src/ui/EntityScriptServerLogDialog.cpp b/interface/src/ui/EntityScriptServerLogDialog.cpp new file mode 100644 index 0000000000..5746a92748 --- /dev/null +++ b/interface/src/ui/EntityScriptServerLogDialog.cpp @@ -0,0 +1,58 @@ +// +// EntityScriptServerLogDialog.cpp +// interface/src/ui +// +// Created by Clement Brisset on 1/31/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "EntityScriptServerLogDialog.h" + +EntityScriptServerLogDialog::EntityScriptServerLogDialog(QWidget* parent) : BaseLogDialog(parent) { + setWindowTitle("Entity Script Server Log"); + + auto nodeList = DependencyManager::get(); + auto& packetReceiver = nodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); + + auto shouldEnableLog = [this] { + auto nodeList = DependencyManager::get(); + enableToEntityServerScriptLog(nodeList->getThisNodeCanRez() || nodeList->getThisNodeCanRezTmp()); + }; + QObject::connect(nodeList.data(), &NodeList::canRezChanged, this, shouldEnableLog); + QObject::connect(nodeList.data(), &NodeList::canRezTmpChanged, this, shouldEnableLog); + shouldEnableLog(); +} + +EntityScriptServerLogDialog::~EntityScriptServerLogDialog() { + enableToEntityServerScriptLog(false); +} + +void EntityScriptServerLogDialog::enableToEntityServerScriptLog(bool enable) { + auto nodeList = DependencyManager::get(); + + if (auto node = nodeList->soloNodeOfType(NodeType::EntityScriptServer)) { + auto packet = NLPacket::create(PacketType::EntityServerScriptLog, sizeof(bool), true); + packet->writePrimitive(enable); + nodeList->sendPacket(std::move(packet), *node); + + if (_subscribed != enable) { + if (enable) { + appendLogLine("====================== Subscribded to the Entity Script Server's log ======================"); + } else { + appendLogLine("==================== Unsubscribded from the Entity Script Server's log ===================="); + } + } + _subscribed = enable; + } else { + qWarning() << "Entity Script Server not found"; + } +} + +void EntityScriptServerLogDialog::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { + auto lines = QString::fromUtf8(message->readAll()); + QMetaObject::invokeMethod(this, "appendLogLine", Q_ARG(QString, lines)); +} diff --git a/interface/src/ui/EntityScriptServerLogDialog.h b/interface/src/ui/EntityScriptServerLogDialog.h new file mode 100644 index 0000000000..b19ca5b32c --- /dev/null +++ b/interface/src/ui/EntityScriptServerLogDialog.h @@ -0,0 +1,37 @@ +// +// EntityScriptServerLogDialog.h +// interface/src/ui +// +// Created by Clement Brisset on 1/31/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_EntityScriptServerLogDialog_h +#define hifi_EntityScriptServerLogDialog_h + +#include "BaseLogDialog.h" + +#include + +class EntityScriptServerLogDialog : public BaseLogDialog { + Q_OBJECT + +public: + EntityScriptServerLogDialog(QWidget* parent = nullptr); + ~EntityScriptServerLogDialog(); + +protected: + QString getCurrentLog() override { return QString(); }; + +private slots: + void enableToEntityServerScriptLog(bool enable); + void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + +private: + bool _subscribed { false }; +}; + +#endif // hifi_EntityScriptServerLogDialog_h diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 809fbd3772..cce7879e94 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -28,8 +28,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _extraDebuggingBox->setCheckState(Qt::Checked); } _extraDebuggingBox->show(); - //connect(_extraDebuggingBox, SIGNAL(stateChanged(int)), SLOT(handleExtraDebuggingCheckbox(int))); - connect(_extraDebuggingBox, &QCheckBox::stateChanged, this, &LogDialog::enableToEntityServerScriptLog); + connect(_extraDebuggingBox, SIGNAL(stateChanged(int)), SLOT(handleExtraDebuggingCheckbox(int))); _revealLogButton = new QPushButton("Reveal log file", this); // set object name for css styling @@ -37,9 +36,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _revealLogButton->show(); connect(_revealLogButton, SIGNAL(clicked()), SLOT(handleRevealButton())); - //connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)), Qt::QueuedConnection); - auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); + connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)), Qt::QueuedConnection); } void LogDialog::resizeEvent(QResizeEvent* event) { @@ -54,35 +51,10 @@ void LogDialog::handleRevealButton() { _logger->locateLog(); } -void LogDialog::handleExtraDebuggingCheckbox(const int state) { +void LogDialog::handleExtraDebuggingCheckbox(int state) { _logger->setExtraDebugging(state != 0); } QString LogDialog::getCurrentLog() { return _logger->getLogData(); } - -void LogDialog::enableToEntityServerScriptLog(bool enable) { - qDebug() << Q_FUNC_INFO << enable; - auto nodeList = DependencyManager::get(); - - if (auto node = nodeList->soloNodeOfType(NodeType::EntityScriptServer)) { - auto packet = NLPacket::create(PacketType::EntityServerScriptLog, sizeof(bool), true); - packet->writePrimitive(enable); - nodeList->sendPacket(std::move(packet), *node); - - if (enable) { - appendLogLine("====================== Subscribded to the Entity Script Server's log ======================"); - } else { - appendLogLine("==================== Unsubscribded from the Entity Script Server's log ===================="); - } - } else { - qWarning() << "Entity Script Server not found"; - } -} - -void LogDialog::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { - auto lines = QString::fromUtf8(message->readAll()); - QMetaObject::invokeMethod(this, "appendLogLine", Q_ARG(QString, lines)); -} - diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index 406d5ce74e..c8794b57ea 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -14,8 +14,6 @@ #include "BaseLogDialog.h" -#include - class QCheckBox; class QPushButton; class QResizeEvent; @@ -29,10 +27,7 @@ public: private slots: void handleRevealButton(); - void handleExtraDebuggingCheckbox(const int); - - void enableToEntityServerScriptLog(bool enable); - void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleExtraDebuggingCheckbox(int); protected: void resizeEvent(QResizeEvent* event) override; From 35f8afe45616af01608e931ea9223e662dc759b0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 1 Feb 2017 14:09:12 -0800 Subject: [PATCH 74/79] Handle domain reconnections --- .../src/ui/EntityScriptServerLogDialog.cpp | 28 +++++++++++++++---- .../src/ui/EntityScriptServerLogDialog.h | 5 ++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/EntityScriptServerLogDialog.cpp b/interface/src/ui/EntityScriptServerLogDialog.cpp index 5746a92748..bb79ed7ef3 100644 --- a/interface/src/ui/EntityScriptServerLogDialog.cpp +++ b/interface/src/ui/EntityScriptServerLogDialog.cpp @@ -18,18 +18,21 @@ EntityScriptServerLogDialog::EntityScriptServerLogDialog(QWidget* parent) : Base auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); - auto shouldEnableLog = [this] { - auto nodeList = DependencyManager::get(); - enableToEntityServerScriptLog(nodeList->getThisNodeCanRez() || nodeList->getThisNodeCanRezTmp()); - }; - QObject::connect(nodeList.data(), &NodeList::canRezChanged, this, shouldEnableLog); - QObject::connect(nodeList.data(), &NodeList::canRezTmpChanged, this, shouldEnableLog); + QObject::connect(nodeList.data(), &NodeList::nodeActivated, this, &EntityScriptServerLogDialog::nodeActivated); + QObject::connect(nodeList.data(), &NodeList::nodeKilled, this, &EntityScriptServerLogDialog::nodeKilled); + + QObject::connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptServerLogDialog::shouldEnableLog); + QObject::connect(nodeList.data(), &NodeList::canRezTmpChanged, this, &EntityScriptServerLogDialog::shouldEnableLog); shouldEnableLog(); } EntityScriptServerLogDialog::~EntityScriptServerLogDialog() { enableToEntityServerScriptLog(false); } +void EntityScriptServerLogDialog::shouldEnableLog() { + auto nodeList = DependencyManager::get(); + enableToEntityServerScriptLog(nodeList->getThisNodeCanRez() || nodeList->getThisNodeCanRezTmp()); +}; void EntityScriptServerLogDialog::enableToEntityServerScriptLog(bool enable) { auto nodeList = DependencyManager::get(); @@ -56,3 +59,16 @@ void EntityScriptServerLogDialog::handleEntityServerScriptLogPacket(QSharedPoint auto lines = QString::fromUtf8(message->readAll()); QMetaObject::invokeMethod(this, "appendLogLine", Q_ARG(QString, lines)); } + +void EntityScriptServerLogDialog::nodeActivated(SharedNodePointer activatedNode) { + if (_subscribed && activatedNode->getType() == NodeType::EntityScriptServer) { + _subscribed = false; + shouldEnableLog(); + } +} + +void EntityScriptServerLogDialog::nodeKilled(SharedNodePointer killedNode) { + if (killedNode->getType() == NodeType::EntityScriptServer) { + appendLogLine("====================== Connection to the Entity Script Server lost ======================"); + } +} diff --git a/interface/src/ui/EntityScriptServerLogDialog.h b/interface/src/ui/EntityScriptServerLogDialog.h index b19ca5b32c..8c68db036c 100644 --- a/interface/src/ui/EntityScriptServerLogDialog.h +++ b/interface/src/ui/EntityScriptServerLogDialog.h @@ -30,6 +30,11 @@ private slots: void enableToEntityServerScriptLog(bool enable); void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + void nodeActivated(SharedNodePointer activatedNode); + void nodeKilled(SharedNodePointer killedNode); + + void shouldEnableLog(); + private: bool _subscribed { false }; }; From 0f39356e94931ea84bc763f82b94b71e78ecc5b2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 1 Feb 2017 16:16:41 -0800 Subject: [PATCH 75/79] Only users with perm rez can see the log --- assignment-client/src/scripts/EntityScriptServer.cpp | 2 +- interface/src/ui/EntityScriptServerLogDialog.cpp | 12 +++--------- interface/src/ui/EntityScriptServerLogDialog.h | 2 -- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 1975b0ce15..f1ba93b68a 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -182,7 +182,7 @@ void EntityScriptServer::updateEntityPPS() { void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them // about each other. - if (senderNode->getCanRez() || senderNode->getCanRezTmp()) { + if (senderNode->getCanRez()) { bool enable = false; message->readPrimitive(&enable); diff --git a/interface/src/ui/EntityScriptServerLogDialog.cpp b/interface/src/ui/EntityScriptServerLogDialog.cpp index bb79ed7ef3..fd06388bf9 100644 --- a/interface/src/ui/EntityScriptServerLogDialog.cpp +++ b/interface/src/ui/EntityScriptServerLogDialog.cpp @@ -21,19 +21,13 @@ EntityScriptServerLogDialog::EntityScriptServerLogDialog(QWidget* parent) : Base QObject::connect(nodeList.data(), &NodeList::nodeActivated, this, &EntityScriptServerLogDialog::nodeActivated); QObject::connect(nodeList.data(), &NodeList::nodeKilled, this, &EntityScriptServerLogDialog::nodeKilled); - QObject::connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptServerLogDialog::shouldEnableLog); - QObject::connect(nodeList.data(), &NodeList::canRezTmpChanged, this, &EntityScriptServerLogDialog::shouldEnableLog); - shouldEnableLog(); + QObject::connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptServerLogDialog::enableToEntityServerScriptLog); + enableToEntityServerScriptLog(nodeList->getThisNodeCanRez()); } EntityScriptServerLogDialog::~EntityScriptServerLogDialog() { enableToEntityServerScriptLog(false); } -void EntityScriptServerLogDialog::shouldEnableLog() { - auto nodeList = DependencyManager::get(); - enableToEntityServerScriptLog(nodeList->getThisNodeCanRez() || nodeList->getThisNodeCanRezTmp()); -}; - void EntityScriptServerLogDialog::enableToEntityServerScriptLog(bool enable) { auto nodeList = DependencyManager::get(); @@ -63,7 +57,7 @@ void EntityScriptServerLogDialog::handleEntityServerScriptLogPacket(QSharedPoint void EntityScriptServerLogDialog::nodeActivated(SharedNodePointer activatedNode) { if (_subscribed && activatedNode->getType() == NodeType::EntityScriptServer) { _subscribed = false; - shouldEnableLog(); + enableToEntityServerScriptLog(DependencyManager::get()->getThisNodeCanRez()); } } diff --git a/interface/src/ui/EntityScriptServerLogDialog.h b/interface/src/ui/EntityScriptServerLogDialog.h index 8c68db036c..f183e9df33 100644 --- a/interface/src/ui/EntityScriptServerLogDialog.h +++ b/interface/src/ui/EntityScriptServerLogDialog.h @@ -33,8 +33,6 @@ private slots: void nodeActivated(SharedNodePointer activatedNode); void nodeKilled(SharedNodePointer killedNode); - void shouldEnableLog(); - private: bool _subscribed { false }; }; From 43d25019931824dfd183587916b521ee1dc38313 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Feb 2017 13:06:14 -0800 Subject: [PATCH 76/79] Add HMD friendly window for the ESS log --- interface/src/Application.cpp | 5 ++ interface/src/EntityScriptServerLogClient.cpp | 83 +++++++++++++++++++ interface/src/EntityScriptServerLogClient.h | 44 ++++++++++ .../src/ui/EntityScriptServerLogDialog.cpp | 55 ++---------- .../src/ui/EntityScriptServerLogDialog.h | 13 --- scripts/developer/debugging/essDebugWindow.js | 28 +++++++ 6 files changed, 165 insertions(+), 63 deletions(-) create mode 100644 interface/src/EntityScriptServerLogClient.cpp create mode 100644 interface/src/EntityScriptServerLogClient.h create mode 100644 scripts/developer/debugging/essDebugWindow.js diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cb340863f7..33db4fb0d6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -134,6 +134,7 @@ #include "devices/Faceshift.h" #include "devices/Leapmotion.h" #include "DiscoverabilityManager.h" +#include "EntityScriptServerLogClient.h" #include "GLCanvas.h" #include "InterfaceActionFactory.h" #include "InterfaceLogging.h" @@ -520,6 +521,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); return previousSessionCrashed; } @@ -5524,6 +5526,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri auto recordingInterface = DependencyManager::get(); scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); + auto entityScriptServerLog = DependencyManager::get(); + scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data()); + // connect this script engines printedMessage signal to the global ScriptEngines these various messages connect(scriptEngine, &ScriptEngine::printedMessage, DependencyManager::get().data(), &ScriptEngines::onPrintedMessage); connect(scriptEngine, &ScriptEngine::errorMessage, DependencyManager::get().data(), &ScriptEngines::onErrorMessage); diff --git a/interface/src/EntityScriptServerLogClient.cpp b/interface/src/EntityScriptServerLogClient.cpp new file mode 100644 index 0000000000..3a8e248499 --- /dev/null +++ b/interface/src/EntityScriptServerLogClient.cpp @@ -0,0 +1,83 @@ +// +// EntityScriptServerLogClient.cpp +// interface/src +// +// Created by Clement Brisset on 2/1/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "EntityScriptServerLogClient.h" + +EntityScriptServerLogClient::EntityScriptServerLogClient() { + auto nodeList = DependencyManager::get(); + auto& packetReceiver = nodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); + + QObject::connect(nodeList.data(), &NodeList::nodeActivated, this, &EntityScriptServerLogClient::nodeActivated); + QObject::connect(nodeList.data(), &NodeList::nodeKilled, this, &EntityScriptServerLogClient::nodeKilled); + + QObject::connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptServerLogClient::canRezChanged); +} + + +void EntityScriptServerLogClient::connectNotify(const QMetaMethod& signal) { + auto numReceivers = receivers(SIGNAL(receivedNewLogLines(QString))); + if (!_subscribed && numReceivers > 0) { + enableToEntityServerScriptLog(DependencyManager::get()->getThisNodeCanRez()); + } +} + +void EntityScriptServerLogClient::disconnectNotify(const QMetaMethod& signal) { + auto numReceivers = receivers(SIGNAL(receivedNewLogLines(QString))); + if (_subscribed && numReceivers == 0) { + enableToEntityServerScriptLog(false); + } +} + +void EntityScriptServerLogClient::enableToEntityServerScriptLog(bool enable) { + auto nodeList = DependencyManager::get(); + + if (auto node = nodeList->soloNodeOfType(NodeType::EntityScriptServer)) { + auto packet = NLPacket::create(PacketType::EntityServerScriptLog, sizeof(bool), true); + packet->writePrimitive(enable); + nodeList->sendPacket(std::move(packet), *node); + + if (_subscribed != enable) { + if (enable) { + emit receivedNewLogLines("====================== Subscribded to the Entity Script Server's log ======================"); + } else { + emit receivedNewLogLines("==================== Unsubscribded from the Entity Script Server's log ===================="); + } + } + _subscribed = enable; + } else { + qWarning() << "Entity Script Server not found"; + } +} + +void EntityScriptServerLogClient::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { + emit receivedNewLogLines(QString::fromUtf8(message->readAll())); +} + +void EntityScriptServerLogClient::nodeActivated(SharedNodePointer activatedNode) { + if (_subscribed && activatedNode->getType() == NodeType::EntityScriptServer) { + _subscribed = false; + enableToEntityServerScriptLog(DependencyManager::get()->getThisNodeCanRez()); + } +} + +void EntityScriptServerLogClient::nodeKilled(SharedNodePointer killedNode) { + if (killedNode->getType() == NodeType::EntityScriptServer) { + emit receivedNewLogLines("====================== Connection to the Entity Script Server lost ======================"); + } +} + +void EntityScriptServerLogClient::canRezChanged(bool canRez) { + auto numReceivers = receivers(SIGNAL(receivedNewLogLines(QString))); + if (numReceivers > 0) { + enableToEntityServerScriptLog(canRez); + } +} diff --git a/interface/src/EntityScriptServerLogClient.h b/interface/src/EntityScriptServerLogClient.h new file mode 100644 index 0000000000..6fb0c9a3ce --- /dev/null +++ b/interface/src/EntityScriptServerLogClient.h @@ -0,0 +1,44 @@ +// +// EntityScriptServerLogClient.h +// interface/src +// +// Created by Clement Brisset on 2/1/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_EntityScriptServerLogClient_h +#define hifi_EntityScriptServerLogClient_h + +#include + +#include + +class EntityScriptServerLogClient : public QObject, public Dependency { + Q_OBJECT + +public: + EntityScriptServerLogClient(); + +signals: + void receivedNewLogLines(QString logLines); + +protected: + void connectNotify(const QMetaMethod& signal) override; + void disconnectNotify(const QMetaMethod& signal) override; + +private slots: + void enableToEntityServerScriptLog(bool enable); + void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + + void nodeActivated(SharedNodePointer activatedNode); + void nodeKilled(SharedNodePointer killedNode); + void canRezChanged(bool canRez); + +private: + bool _subscribed { false }; +}; + +#endif // hifi_EntityScriptServerLogClient_h diff --git a/interface/src/ui/EntityScriptServerLogDialog.cpp b/interface/src/ui/EntityScriptServerLogDialog.cpp index fd06388bf9..e8ee3ee522 100644 --- a/interface/src/ui/EntityScriptServerLogDialog.cpp +++ b/interface/src/ui/EntityScriptServerLogDialog.cpp @@ -11,58 +11,13 @@ #include "EntityScriptServerLogDialog.h" +#include + EntityScriptServerLogDialog::EntityScriptServerLogDialog(QWidget* parent) : BaseLogDialog(parent) { setWindowTitle("Entity Script Server Log"); - auto nodeList = DependencyManager::get(); - auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); - QObject::connect(nodeList.data(), &NodeList::nodeActivated, this, &EntityScriptServerLogDialog::nodeActivated); - QObject::connect(nodeList.data(), &NodeList::nodeKilled, this, &EntityScriptServerLogDialog::nodeKilled); - - QObject::connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptServerLogDialog::enableToEntityServerScriptLog); - enableToEntityServerScriptLog(nodeList->getThisNodeCanRez()); -} - -EntityScriptServerLogDialog::~EntityScriptServerLogDialog() { - enableToEntityServerScriptLog(false); -} -void EntityScriptServerLogDialog::enableToEntityServerScriptLog(bool enable) { - auto nodeList = DependencyManager::get(); - - if (auto node = nodeList->soloNodeOfType(NodeType::EntityScriptServer)) { - auto packet = NLPacket::create(PacketType::EntityServerScriptLog, sizeof(bool), true); - packet->writePrimitive(enable); - nodeList->sendPacket(std::move(packet), *node); - - if (_subscribed != enable) { - if (enable) { - appendLogLine("====================== Subscribded to the Entity Script Server's log ======================"); - } else { - appendLogLine("==================== Unsubscribded from the Entity Script Server's log ===================="); - } - } - _subscribed = enable; - } else { - qWarning() << "Entity Script Server not found"; - } -} - -void EntityScriptServerLogDialog::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { - auto lines = QString::fromUtf8(message->readAll()); - QMetaObject::invokeMethod(this, "appendLogLine", Q_ARG(QString, lines)); -} - -void EntityScriptServerLogDialog::nodeActivated(SharedNodePointer activatedNode) { - if (_subscribed && activatedNode->getType() == NodeType::EntityScriptServer) { - _subscribed = false; - enableToEntityServerScriptLog(DependencyManager::get()->getThisNodeCanRez()); - } -} - -void EntityScriptServerLogDialog::nodeKilled(SharedNodePointer killedNode) { - if (killedNode->getType() == NodeType::EntityScriptServer) { - appendLogLine("====================== Connection to the Entity Script Server lost ======================"); - } + auto client = DependencyManager::get(); + QObject::connect(client.data(), &EntityScriptServerLogClient::receivedNewLogLines, + this, &EntityScriptServerLogDialog::appendLogLine); } diff --git a/interface/src/ui/EntityScriptServerLogDialog.h b/interface/src/ui/EntityScriptServerLogDialog.h index f183e9df33..a5451b6159 100644 --- a/interface/src/ui/EntityScriptServerLogDialog.h +++ b/interface/src/ui/EntityScriptServerLogDialog.h @@ -14,27 +14,14 @@ #include "BaseLogDialog.h" -#include - class EntityScriptServerLogDialog : public BaseLogDialog { Q_OBJECT public: EntityScriptServerLogDialog(QWidget* parent = nullptr); - ~EntityScriptServerLogDialog(); protected: QString getCurrentLog() override { return QString(); }; - -private slots: - void enableToEntityServerScriptLog(bool enable); - void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); - - void nodeActivated(SharedNodePointer activatedNode); - void nodeKilled(SharedNodePointer killedNode); - -private: - bool _subscribed { false }; }; #endif // hifi_EntityScriptServerLogDialog_h diff --git a/scripts/developer/debugging/essDebugWindow.js b/scripts/developer/debugging/essDebugWindow.js new file mode 100644 index 0000000000..7622655d13 --- /dev/null +++ b/scripts/developer/debugging/essDebugWindow.js @@ -0,0 +1,28 @@ +// +// essDebugWindow.js +// +// Created by Clement Brisset on 2/2/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { // BEGIN LOCAL_SCOPE + +// Set up the qml ui +var qml = Script.resolvePath('debugWindow.qml'); +var window = new OverlayWindow({ + title: 'Debug Window', + source: qml, + width: 400, height: 900, +}); +window.setPosition(25, 50); +window.closed.connect(function() { Script.stop(); }); + +EntityScriptServerLog.receivedNewLogLines.connect(function(message) { + window.sendToQml(message); +}); + + +}()); // END LOCAL_SCOPE From 6fbe3c918771c7eb7ecd182c1f0b227b96d3468b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Feb 2017 14:44:10 -0800 Subject: [PATCH 77/79] Windows specific changes --- .../src/scripts/EntityScriptServer.cpp | 28 +++++++++---------- interface/src/EntityScriptServerLogClient.cpp | 17 +++++++---- interface/src/EntityScriptServerLogClient.h | 2 ++ interface/src/Menu.cpp | 10 +++---- interface/src/ui/BaseLogDialog.cpp | 3 +- scripts/developer/debugging/essDebugWindow.js | 2 +- 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index f1ba93b68a..e64e2fe3ce 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -182,23 +182,21 @@ void EntityScriptServer::updateEntityPPS() { void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them // about each other. - if (senderNode->getCanRez()) { - bool enable = false; - message->readPrimitive(&enable); + bool enable = false; + message->readPrimitive(&enable); - auto senderUUID = senderNode->getUUID(); - auto it = _logListeners.find(senderUUID); + auto senderUUID = senderNode->getUUID(); + auto it = _logListeners.find(senderUUID); - if (enable) { - if (it == std::end(_logListeners)) { - _logListeners.insert(senderUUID); - qInfo() << "Node" << senderUUID << "subscribed to log stream"; - } - } else { - if (it != std::end(_logListeners)) { - _logListeners.erase(it); - qInfo() << "Node" << senderUUID << "unsubscribed from log stream"; - } + if (enable && senderNode->getCanRez()) { + if (it == std::end(_logListeners)) { + _logListeners.insert(senderUUID); + qInfo() << "Node" << senderUUID << "subscribed to log stream"; + } + } else { + if (it != std::end(_logListeners)) { + _logListeners.erase(it); + qInfo() << "Node" << senderUUID << "unsubscribed from log stream"; } } } diff --git a/interface/src/EntityScriptServerLogClient.cpp b/interface/src/EntityScriptServerLogClient.cpp index 3a8e248499..e02bd6cb5c 100644 --- a/interface/src/EntityScriptServerLogClient.cpp +++ b/interface/src/EntityScriptServerLogClient.cpp @@ -22,17 +22,22 @@ EntityScriptServerLogClient::EntityScriptServerLogClient() { QObject::connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptServerLogClient::canRezChanged); } - void EntityScriptServerLogClient::connectNotify(const QMetaMethod& signal) { - auto numReceivers = receivers(SIGNAL(receivedNewLogLines(QString))); - if (!_subscribed && numReceivers > 0) { - enableToEntityServerScriptLog(DependencyManager::get()->getThisNodeCanRez()); - } + // This needs to be delayed or "receivers()" will return completely inconsistent values + QMetaObject::invokeMethod(this, "connectionsChanged", Qt::QueuedConnection); } void EntityScriptServerLogClient::disconnectNotify(const QMetaMethod& signal) { + // This needs to be delayed or "receivers()" will return completely inconsistent values + QMetaObject::invokeMethod(this, "connectionsChanged", Qt::QueuedConnection); +} + +void EntityScriptServerLogClient::connectionsChanged() { + qDebug() << Q_FUNC_INFO << _subscribed << receivers(SIGNAL(receivedNewLogLines(QString))); auto numReceivers = receivers(SIGNAL(receivedNewLogLines(QString))); - if (_subscribed && numReceivers == 0) { + if (!_subscribed && numReceivers > 0) { + enableToEntityServerScriptLog(DependencyManager::get()->getThisNodeCanRez()); + } else if (_subscribed && numReceivers == 0) { enableToEntityServerScriptLog(false); } } diff --git a/interface/src/EntityScriptServerLogClient.h b/interface/src/EntityScriptServerLogClient.h index 6fb0c9a3ce..22245e2a4e 100644 --- a/interface/src/EntityScriptServerLogClient.h +++ b/interface/src/EntityScriptServerLogClient.h @@ -37,6 +37,8 @@ private slots: void nodeKilled(SharedNodePointer killedNode); void canRezChanged(bool canRez); + void connectionsChanged(); + private: bool _subscribed { false }; }; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index bc4de76f1c..acf97ad5f7 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -705,13 +705,11 @@ Menu::Menu() { qApp, SLOT(toggleLogDialog())); auto essLogAction = addActionToQMenuAndActionHash(developerMenu, MenuOption::EntityScriptServerLog, 0, qApp, SLOT(toggleEntityScriptServerLogDialog())); - auto shouldEnableLog = [essLogAction] { + QObject::connect(nodeList.data(), &NodeList::canRezChanged, essLogAction, [essLogAction] { auto nodeList = DependencyManager::get(); - essLogAction->setEnabled(nodeList->getThisNodeCanRez() || nodeList->getThisNodeCanRezTmp()); - }; - QObject::connect(nodeList.data(), &NodeList::canRezChanged, essLogAction, shouldEnableLog); - QObject::connect(nodeList.data(), &NodeList::canRezTmpChanged, essLogAction, shouldEnableLog); - shouldEnableLog(); + essLogAction->setEnabled(nodeList->getThisNodeCanRez()); + }); + essLogAction->setEnabled(nodeList->getThisNodeCanRez()); action = addActionToQMenuAndActionHash(developerMenu, "Script Log (HMD friendly)..."); connect(action, &QAction::triggered, [] { diff --git a/interface/src/ui/BaseLogDialog.cpp b/interface/src/ui/BaseLogDialog.cpp index c17ede4a56..47cea9c26a 100644 --- a/interface/src/ui/BaseLogDialog.cpp +++ b/interface/src/ui/BaseLogDialog.cpp @@ -111,7 +111,8 @@ void BaseLogDialog::handleSearchTextChanged(QString searchText) { } void BaseLogDialog::showLogData() { - _logTextBox->setPlainText(getCurrentLog()); + _logTextBox->clear(); + _logTextBox->appendPlainText(getCurrentLog()); _logTextBox->ensureCursorVisible(); } diff --git a/scripts/developer/debugging/essDebugWindow.js b/scripts/developer/debugging/essDebugWindow.js index 7622655d13..fbce09f93d 100644 --- a/scripts/developer/debugging/essDebugWindow.js +++ b/scripts/developer/debugging/essDebugWindow.js @@ -21,7 +21,7 @@ window.setPosition(25, 50); window.closed.connect(function() { Script.stop(); }); EntityScriptServerLog.receivedNewLogLines.connect(function(message) { - window.sendToQml(message); + window.sendToQml(message.trim()); }); From 72ed1add94d5ba55cd8148bd6855668d772d8f04 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Feb 2017 15:08:34 -0800 Subject: [PATCH 78/79] CR log spam cleanup --- .../src/AssignmentClientLogging.cpp | 2 +- .../src/AssignmentClientLogging.h | 2 +- .../src/scripts/EntityScriptServer.cpp | 26 ++++++++----------- .../src/scripts/EntityScriptServerLogging.cpp | 14 ++++++++++ .../src/scripts/EntityScriptServerLogging.h | 19 ++++++++++++++ interface/src/EntityScriptServerLogClient.cpp | 3 --- scripts/developer/debugging/essDebugWindow.js | 2 +- 7 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 assignment-client/src/scripts/EntityScriptServerLogging.cpp create mode 100644 assignment-client/src/scripts/EntityScriptServerLogging.h diff --git a/assignment-client/src/AssignmentClientLogging.cpp b/assignment-client/src/AssignmentClientLogging.cpp index 9110dccc5f..73687f94d0 100644 --- a/assignment-client/src/AssignmentClientLogging.cpp +++ b/assignment-client/src/AssignmentClientLogging.cpp @@ -3,7 +3,7 @@ // assignment-client/src // // Created by Clement on 12/14/15. -// Copyright 2015 High Fidelity, Inc. +// Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/assignment-client/src/AssignmentClientLogging.h b/assignment-client/src/AssignmentClientLogging.h index 88e2add017..144fbe2125 100644 --- a/assignment-client/src/AssignmentClientLogging.h +++ b/assignment-client/src/AssignmentClientLogging.h @@ -3,7 +3,7 @@ // assignment-client/src // // Created by Clement on 12/14/15. -// Copyright 2015 High Fidelity, Inc. +// Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index e64e2fe3ce..b21b5e9dcd 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -11,9 +11,13 @@ #include "EntityScriptServer.h" +#include + #include #include +#include #include +#include #include #include #include @@ -24,13 +28,9 @@ #include #include -#include "ClientServerUtils.h" +#include "EntityScriptServerLogging.h" #include "../entities/AssignmentParentFinder.h" - -#include -#include - using Mutex = std::mutex; using Lock = std::lock_guard; @@ -101,7 +101,7 @@ void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointerread(NUM_BYTES_RFC4122_UUID)); if (_entityViewer.getTree() && !_shuttingDown) { - qDebug() << "Reloading: " << entityID; + qCDebug(entity_script_server) << "Reloading: " << entityID; _entitiesScriptEngine->unloadEntityScript(entityID); checkAndCallPreload(entityID, true); } @@ -191,12 +191,12 @@ void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointergetCanRez()) { if (it == std::end(_logListeners)) { _logListeners.insert(senderUUID); - qInfo() << "Node" << senderUUID << "subscribed to log stream"; + qCInfo(entity_script_server) << "Node" << senderUUID << "subscribed to log stream"; } } else { if (it != std::end(_logListeners)) { _logListeners.erase(it); - qInfo() << "Node" << senderUUID << "unsubscribed from log stream"; + qCInfo(entity_script_server) << "Node" << senderUUID << "unsubscribed from log stream"; } } } @@ -226,16 +226,12 @@ void EntityScriptServer::pushLogs() { if (node && node->getActiveSocket()) { auto copy = NLPacket::createCopy(*packet); nodeList->sendPacket(std::move(copy), *node); - } else { - qWarning() << "Node not found"; } } auto node = nodeList->nodeWithUUID(*last); if (node && node->getActiveSocket()) { nodeList->sendPacket(std::move(packet), *node); - } else { - qWarning() << "Node not found"; } } @@ -388,7 +384,7 @@ void EntityScriptServer::handleSelectedAudioFormat(QSharedPointergetName()) { _codec = plugin; _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO); - qDebug() << "Selected Codec Plugin:" << _codec.get(); + qCDebug(entity_script_server) << "Selected Codec Plugin:" << _codec.get(); break; } } @@ -490,7 +486,7 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, const QString scriptUrl = entity->getServerScripts(); if (!scriptUrl.isEmpty()) { scriptUrl = ResourceManager::normalizeURL(scriptUrl); - qDebug() << "Loading entity server script" << scriptUrl << "for" << entityID; + qCDebug(entity_script_server) << "Loading entity server script" << scriptUrl << "for" << entityID; ScriptEngine::loadEntityScript(_entitiesScriptEngine, entityID, scriptUrl, reload); } } diff --git a/assignment-client/src/scripts/EntityScriptServerLogging.cpp b/assignment-client/src/scripts/EntityScriptServerLogging.cpp new file mode 100644 index 0000000000..7d033d8c9c --- /dev/null +++ b/assignment-client/src/scripts/EntityScriptServerLogging.cpp @@ -0,0 +1,14 @@ +// +// EntityScriptServerLogging.cpp +// assignment-client/src/scripts +// +// Created by Clement on 2/2/17. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "EntityScriptServerLogging.h" + +Q_LOGGING_CATEGORY(entity_script_server, "hifi.entity-script-server") \ No newline at end of file diff --git a/assignment-client/src/scripts/EntityScriptServerLogging.h b/assignment-client/src/scripts/EntityScriptServerLogging.h new file mode 100644 index 0000000000..efb0c70cd0 --- /dev/null +++ b/assignment-client/src/scripts/EntityScriptServerLogging.h @@ -0,0 +1,19 @@ +// +// EntityScriptServerLogging.h +// assignment-client/src/scripts +// +// Created by Clement on 2/2/17. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_EntityScriptServerLogging_h +#define hifi_EntityScriptServerLogging_h + +#include + +Q_DECLARE_LOGGING_CATEGORY(entity_script_server) + +#endif // hifi_EntityScriptServerLogging_h \ No newline at end of file diff --git a/interface/src/EntityScriptServerLogClient.cpp b/interface/src/EntityScriptServerLogClient.cpp index e02bd6cb5c..4405af5b1b 100644 --- a/interface/src/EntityScriptServerLogClient.cpp +++ b/interface/src/EntityScriptServerLogClient.cpp @@ -33,7 +33,6 @@ void EntityScriptServerLogClient::disconnectNotify(const QMetaMethod& signal) { } void EntityScriptServerLogClient::connectionsChanged() { - qDebug() << Q_FUNC_INFO << _subscribed << receivers(SIGNAL(receivedNewLogLines(QString))); auto numReceivers = receivers(SIGNAL(receivedNewLogLines(QString))); if (!_subscribed && numReceivers > 0) { enableToEntityServerScriptLog(DependencyManager::get()->getThisNodeCanRez()); @@ -58,8 +57,6 @@ void EntityScriptServerLogClient::enableToEntityServerScriptLog(bool enable) { } } _subscribed = enable; - } else { - qWarning() << "Entity Script Server not found"; } } diff --git a/scripts/developer/debugging/essDebugWindow.js b/scripts/developer/debugging/essDebugWindow.js index fbce09f93d..ef52694184 100644 --- a/scripts/developer/debugging/essDebugWindow.js +++ b/scripts/developer/debugging/essDebugWindow.js @@ -13,7 +13,7 @@ // Set up the qml ui var qml = Script.resolvePath('debugWindow.qml'); var window = new OverlayWindow({ - title: 'Debug Window', + title: 'Entity Script Server Log Window', source: qml, width: 400, height: 900, }); From 3a30de79aa052e41e2b845a241ca495d668df670 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 3 Feb 2017 11:26:29 -0800 Subject: [PATCH 79/79] CR --- .../src/AssignmentClientLogging.cpp | 2 +- .../src/AssignmentClientLogging.h | 2 +- .../src/scripts/EntityScriptServer.cpp | 22 +++++-------------- interface/src/Application.cpp | 3 +-- .../src/EntityScriptServerLogClient.cpp | 0 .../src/EntityScriptServerLogClient.h | 0 6 files changed, 9 insertions(+), 20 deletions(-) rename {interface => libraries/entities}/src/EntityScriptServerLogClient.cpp (100%) rename {interface => libraries/entities}/src/EntityScriptServerLogClient.h (100%) diff --git a/assignment-client/src/AssignmentClientLogging.cpp b/assignment-client/src/AssignmentClientLogging.cpp index 73687f94d0..9110dccc5f 100644 --- a/assignment-client/src/AssignmentClientLogging.cpp +++ b/assignment-client/src/AssignmentClientLogging.cpp @@ -3,7 +3,7 @@ // assignment-client/src // // Created by Clement on 12/14/15. -// Copyright 2017 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/assignment-client/src/AssignmentClientLogging.h b/assignment-client/src/AssignmentClientLogging.h index 144fbe2125..88e2add017 100644 --- a/assignment-client/src/AssignmentClientLogging.h +++ b/assignment-client/src/AssignmentClientLogging.h @@ -3,7 +3,7 @@ // assignment-client/src // // Created by Clement on 12/14/15. -// Copyright 2017 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index b21b5e9dcd..930b3946c6 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -80,9 +80,8 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket"); packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); - static const int LOG_INTERVAL = MSECS_PER_SECOND / 50; + static const int LOG_INTERVAL = MSECS_PER_SECOND / 10; auto timer = new QTimer(this); - timer->setTimerType(Qt::PreciseTimer); timer->setInterval(LOG_INTERVAL); connect(timer, &QTimer::timeout, this, &EntityScriptServer::pushLogs); timer->start(); @@ -215,24 +214,15 @@ void EntityScriptServer::pushLogs() { return; } - auto packet = NLPacket::create(PacketType::EntityServerScriptLog, buffer.size(), true); - packet->write(buffer.data(), buffer.size()); - auto nodeList = DependencyManager::get(); - - auto last = --std::end(_logListeners); - for (auto it = std::begin(_logListeners); it != last; ++it) { - auto node = nodeList->nodeWithUUID(*it); + for (auto uuid : _logListeners) { + auto node = nodeList->nodeWithUUID(uuid); if (node && node->getActiveSocket()) { - auto copy = NLPacket::createCopy(*packet); - nodeList->sendPacket(std::move(copy), *node); + auto packet = NLPacketList::create(PacketType::EntityServerScriptLog, QByteArray(), true, true); + packet->write(buffer.data(), buffer.size()); + nodeList->sendPacketList(std::move(packet), *node); } } - - auto node = nodeList->nodeWithUUID(*last); - if (node && node->getActiveSocket()) { - nodeList->sendPacket(std::move(packet), *node); - } } void EntityScriptServer::run() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 33db4fb0d6..1441ae9001 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -134,7 +135,6 @@ #include "devices/Faceshift.h" #include "devices/Leapmotion.h" #include "DiscoverabilityManager.h" -#include "EntityScriptServerLogClient.h" #include "GLCanvas.h" #include "InterfaceActionFactory.h" #include "InterfaceLogging.h" @@ -176,7 +176,6 @@ #include "FrameTimingsScriptingInterface.h" #include #include -#include // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. diff --git a/interface/src/EntityScriptServerLogClient.cpp b/libraries/entities/src/EntityScriptServerLogClient.cpp similarity index 100% rename from interface/src/EntityScriptServerLogClient.cpp rename to libraries/entities/src/EntityScriptServerLogClient.cpp diff --git a/interface/src/EntityScriptServerLogClient.h b/libraries/entities/src/EntityScriptServerLogClient.h similarity index 100% rename from interface/src/EntityScriptServerLogClient.h rename to libraries/entities/src/EntityScriptServerLogClient.h