mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 22:36:57 +02:00
Remove all oglplus usage and references
This commit is contained in:
parent
d3d3aa587c
commit
488d191428
12 changed files with 19 additions and 1405 deletions
21
cmake/externals/oglplus/CMakeLists.txt
vendored
21
cmake/externals/oglplus/CMakeLists.txt
vendored
|
@ -1,21 +0,0 @@
|
||||||
set(EXTERNAL_NAME oglplus)
|
|
||||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|
||||||
|
|
||||||
include(ExternalProject)
|
|
||||||
ExternalProject_Add(
|
|
||||||
${EXTERNAL_NAME}
|
|
||||||
URL http://hifi-public.s3.amazonaws.com/dependencies/oglplus-0.63.0.zip
|
|
||||||
URL_MD5 de984ab245b185b45c87415c0e052135
|
|
||||||
CONFIGURE_COMMAND ""
|
|
||||||
BUILD_COMMAND ""
|
|
||||||
INSTALL_COMMAND ""
|
|
||||||
LOG_DOWNLOAD 1
|
|
||||||
)
|
|
||||||
|
|
||||||
# Hide this external target (for ide users)
|
|
||||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
|
||||||
|
|
||||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
|
||||||
|
|
||||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include ${SOURCE_DIR}/implement CACHE TYPE INTERNAL)
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright 2015 High Fidelity, Inc.
|
|
||||||
# Created by Bradley Austin Davis on 2015/10/10
|
|
||||||
#
|
|
||||||
# Distributed under the Apache License, Version 2.0.
|
|
||||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
#
|
|
||||||
macro(TARGET_OGLPLUS)
|
|
||||||
# our OGL plus setup requires glew
|
|
||||||
target_glew()
|
|
||||||
|
|
||||||
# our OGL plus setup requires boostconfig
|
|
||||||
add_dependency_external_projects(boostconfig)
|
|
||||||
find_package(BoostConfig REQUIRED)
|
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
|
|
||||||
add_dependency_external_projects(oglplus)
|
|
||||||
find_package(OGLPLUS REQUIRED)
|
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
|
|
||||||
endmacro()
|
|
|
@ -1,24 +0,0 @@
|
||||||
#
|
|
||||||
# Try to find OGLPLUS include path.
|
|
||||||
# Once done this will define
|
|
||||||
#
|
|
||||||
# OGLPLUS_INCLUDE_DIRS
|
|
||||||
#
|
|
||||||
# Created by Bradley Austin Davis on 2015/05/22
|
|
||||||
# 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
|
|
||||||
#
|
|
||||||
|
|
||||||
# setup hints for OGLPLUS search
|
|
||||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
|
||||||
hifi_library_search_hints("oglplus")
|
|
||||||
|
|
||||||
# locate header
|
|
||||||
find_path(OGLPLUS_INCLUDE_DIRS "oglplus/fwd.hpp" HINTS ${OGLPLUS_SEARCH_DIRS})
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(OGLPLUS DEFAULT_MSG OGLPLUS_INCLUDE_DIRS)
|
|
||||||
|
|
||||||
mark_as_advanced(OGLPLUS_INCLUDE_DIRS OGLPLUS_SEARCH_DIRS)
|
|
|
@ -6,7 +6,3 @@ link_hifi_libraries(shared plugins ui-plugins gl gpu-gl ui render-utils)
|
||||||
target_opengl()
|
target_opengl()
|
||||||
|
|
||||||
GroupSources("src/display-plugins")
|
GroupSources("src/display-plugins")
|
||||||
|
|
||||||
if (NOT ANDROID)
|
|
||||||
target_oglplus()
|
|
||||||
endif ()
|
|
||||||
|
|
|
@ -6,5 +6,4 @@ target_opengl()
|
||||||
|
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
target_glew()
|
target_glew()
|
||||||
target_oglplus()
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
@ -1,482 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Bradley Austin Davis on 2015/05/29
|
|
||||||
// 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 "OglplusHelpers.h"
|
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <oglplus/shapes/plane.hpp>
|
|
||||||
#include <oglplus/shapes/sky_box.hpp>
|
|
||||||
#include "GLLogging.h"
|
|
||||||
|
|
||||||
using namespace oglplus;
|
|
||||||
using namespace oglplus::shapes;
|
|
||||||
|
|
||||||
static const char * SIMPLE_TEXTURED_VS = R"VS(#version 410 core
|
|
||||||
#pragma line __LINE__
|
|
||||||
|
|
||||||
uniform mat4 mvp = mat4(1);
|
|
||||||
|
|
||||||
in vec3 Position;
|
|
||||||
in vec2 TexCoord;
|
|
||||||
|
|
||||||
out vec3 vPosition;
|
|
||||||
out vec2 vTexCoord;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = mvp * vec4(Position, 1);
|
|
||||||
vTexCoord = TexCoord;
|
|
||||||
vPosition = Position;
|
|
||||||
}
|
|
||||||
|
|
||||||
)VS";
|
|
||||||
|
|
||||||
static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core
|
|
||||||
#pragma line __LINE__
|
|
||||||
|
|
||||||
uniform sampler2D sampler;
|
|
||||||
uniform float alpha = 1.0;
|
|
||||||
|
|
||||||
in vec3 vPosition;
|
|
||||||
in vec2 vTexCoord;
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
FragColor = texture(sampler, vTexCoord);
|
|
||||||
FragColor.a *= alpha;
|
|
||||||
if (FragColor.a <= 0.0) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
)FS";
|
|
||||||
|
|
||||||
|
|
||||||
static const char * SIMPLE_TEXTURED_CUBEMAP_FS = R"FS(#version 410 core
|
|
||||||
#pragma line __LINE__
|
|
||||||
|
|
||||||
uniform samplerCube sampler;
|
|
||||||
uniform float alpha = 1.0;
|
|
||||||
|
|
||||||
in vec3 vPosition;
|
|
||||||
in vec3 vTexCoord;
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
|
|
||||||
FragColor = texture(sampler, vPosition);
|
|
||||||
FragColor.a *= alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
)FS";
|
|
||||||
|
|
||||||
|
|
||||||
ProgramPtr loadDefaultShader() {
|
|
||||||
ProgramPtr result;
|
|
||||||
compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgramPtr loadCubemapShader() {
|
|
||||||
ProgramPtr result;
|
|
||||||
compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_CUBEMAP_FS);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& gs, const std::string& fs) {
|
|
||||||
using namespace oglplus;
|
|
||||||
try {
|
|
||||||
result = std::make_shared<Program>();
|
|
||||||
// attach the shaders to the program
|
|
||||||
result->AttachShader(
|
|
||||||
VertexShader()
|
|
||||||
.Source(GLSLSource(vs))
|
|
||||||
.Compile()
|
|
||||||
);
|
|
||||||
result->AttachShader(
|
|
||||||
GeometryShader()
|
|
||||||
.Source(GLSLSource(gs))
|
|
||||||
.Compile()
|
|
||||||
);
|
|
||||||
result->AttachShader(
|
|
||||||
FragmentShader()
|
|
||||||
.Source(GLSLSource(fs))
|
|
||||||
.Compile()
|
|
||||||
);
|
|
||||||
result->Link();
|
|
||||||
} catch (ProgramBuildError& err) {
|
|
||||||
Q_UNUSED(err);
|
|
||||||
qWarning() << err.Log().c_str();
|
|
||||||
Q_ASSERT_X(false, "compileProgram", "Failed to build shader program");
|
|
||||||
qFatal("%s", (const char*)err.Message);
|
|
||||||
result.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) {
|
|
||||||
using namespace oglplus;
|
|
||||||
try {
|
|
||||||
result = std::make_shared<Program>();
|
|
||||||
// attach the shaders to the program
|
|
||||||
result->AttachShader(
|
|
||||||
VertexShader()
|
|
||||||
.Source(GLSLSource(vs))
|
|
||||||
.Compile()
|
|
||||||
);
|
|
||||||
result->AttachShader(
|
|
||||||
FragmentShader()
|
|
||||||
.Source(GLSLSource(fs))
|
|
||||||
.Compile()
|
|
||||||
);
|
|
||||||
result->Link();
|
|
||||||
} catch (ProgramBuildError& err) {
|
|
||||||
Q_UNUSED(err);
|
|
||||||
qWarning() << err.Log().c_str();
|
|
||||||
Q_ASSERT_X(false, "compileProgram", "Failed to build shader program");
|
|
||||||
qFatal("%s", (const char*) err.Message);
|
|
||||||
result.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) {
|
|
||||||
using namespace oglplus;
|
|
||||||
Vec3f a(1, 0, 0);
|
|
||||||
Vec3f b(0, 1, 0);
|
|
||||||
if (aspect > 1) {
|
|
||||||
b[1] /= aspect;
|
|
||||||
} else {
|
|
||||||
a[0] *= aspect;
|
|
||||||
}
|
|
||||||
return ShapeWrapperPtr(
|
|
||||||
new shapes::ShapeWrapper({ "Position", "TexCoord" }, shapes::Plane(a, b), *program)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ShapeWrapperPtr loadSkybox(ProgramPtr program) {
|
|
||||||
return ShapeWrapperPtr(new shapes::ShapeWrapper(std::initializer_list<std::string>{ "Position" }, shapes::SkyBox(), *program));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a point's cartesian coordinates on a sphere from pitch and yaw
|
|
||||||
static glm::vec3 getPoint(float yaw, float pitch) {
|
|
||||||
return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
|
|
||||||
glm::sin(-pitch),
|
|
||||||
glm::cos(-pitch) * (-glm::cos(yaw)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class SphereSection : public DrawingInstructionWriter, public DrawMode {
|
|
||||||
public:
|
|
||||||
using IndexArray = std::vector<GLuint>;
|
|
||||||
using PosArray = std::vector<float>;
|
|
||||||
using TexArray = std::vector<float>;
|
|
||||||
/// The type of the index container returned by Indices()
|
|
||||||
// vertex positions
|
|
||||||
PosArray _pos_data;
|
|
||||||
// vertex tex coords
|
|
||||||
TexArray _tex_data;
|
|
||||||
IndexArray _idx_data;
|
|
||||||
unsigned int _prim_count{ 0 };
|
|
||||||
|
|
||||||
public:
|
|
||||||
SphereSection(
|
|
||||||
const float fov,
|
|
||||||
const float aspectRatio,
|
|
||||||
const int slices_,
|
|
||||||
const int stacks_) {
|
|
||||||
//UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
|
|
||||||
if (fov >= PI) {
|
|
||||||
qCDebug(glLogging) << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
|
|
||||||
}
|
|
||||||
|
|
||||||
int gridSize = std::max(slices_, stacks_);
|
|
||||||
int gridSizeLog2 = 1;
|
|
||||||
while (1 << gridSizeLog2 < gridSize) {
|
|
||||||
++gridSizeLog2;
|
|
||||||
}
|
|
||||||
gridSize = (1 << gridSizeLog2) + 1;
|
|
||||||
// Compute number of vertices needed
|
|
||||||
int vertices = gridSize * gridSize;
|
|
||||||
_pos_data.resize(vertices * 3);
|
|
||||||
_tex_data.resize(vertices * 2);
|
|
||||||
|
|
||||||
// Compute vertices positions and texture UV coordinate
|
|
||||||
for (int y = 0; y <= gridSize; ++y) {
|
|
||||||
for (int x = 0; x <= gridSize; ++x) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < gridSize; i++) {
|
|
||||||
float stacksRatio = (float)i / (float)(gridSize - 1); // First stack is 0.0f, last stack is 1.0f
|
|
||||||
// abs(theta) <= fov / 2.0f
|
|
||||||
float pitch = -fov * (stacksRatio - 0.5f);
|
|
||||||
for (int j = 0; j < gridSize; j++) {
|
|
||||||
float slicesRatio = (float)j / (float)(gridSize - 1); // First slice is 0.0f, last slice is 1.0f
|
|
||||||
// abs(phi) <= fov * aspectRatio / 2.0f
|
|
||||||
float yaw = -fov * aspectRatio * (slicesRatio - 0.5f);
|
|
||||||
int vertex = i * gridSize + j;
|
|
||||||
int posOffset = vertex * 3;
|
|
||||||
int texOffset = vertex * 2;
|
|
||||||
vec3 pos = getPoint(yaw, pitch);
|
|
||||||
_pos_data[posOffset] = pos.x;
|
|
||||||
_pos_data[posOffset + 1] = pos.y;
|
|
||||||
_pos_data[posOffset + 2] = pos.z;
|
|
||||||
_tex_data[texOffset] = slicesRatio;
|
|
||||||
_tex_data[texOffset + 1] = stacksRatio;
|
|
||||||
}
|
|
||||||
} // done with vertices
|
|
||||||
|
|
||||||
int rowLen = gridSize;
|
|
||||||
|
|
||||||
// gridsize now refers to the triangles, not the vertices, so reduce by one
|
|
||||||
// or die by fencepost error http://en.wikipedia.org/wiki/Off-by-one_error
|
|
||||||
--gridSize;
|
|
||||||
int quads = gridSize * gridSize;
|
|
||||||
for (int t = 0; t < quads; ++t) {
|
|
||||||
int x =
|
|
||||||
((t & 0x0001) >> 0) |
|
|
||||||
((t & 0x0004) >> 1) |
|
|
||||||
((t & 0x0010) >> 2) |
|
|
||||||
((t & 0x0040) >> 3) |
|
|
||||||
((t & 0x0100) >> 4) |
|
|
||||||
((t & 0x0400) >> 5) |
|
|
||||||
((t & 0x1000) >> 6) |
|
|
||||||
((t & 0x4000) >> 7);
|
|
||||||
int y =
|
|
||||||
((t & 0x0002) >> 1) |
|
|
||||||
((t & 0x0008) >> 2) |
|
|
||||||
((t & 0x0020) >> 3) |
|
|
||||||
((t & 0x0080) >> 4) |
|
|
||||||
((t & 0x0200) >> 5) |
|
|
||||||
((t & 0x0800) >> 6) |
|
|
||||||
((t & 0x2000) >> 7) |
|
|
||||||
((t & 0x8000) >> 8);
|
|
||||||
int i = x * (rowLen) + y;
|
|
||||||
|
|
||||||
_idx_data.push_back(i);
|
|
||||||
_idx_data.push_back(i + 1);
|
|
||||||
_idx_data.push_back(i + rowLen + 1);
|
|
||||||
|
|
||||||
_idx_data.push_back(i + rowLen + 1);
|
|
||||||
_idx_data.push_back(i + rowLen);
|
|
||||||
_idx_data.push_back(i);
|
|
||||||
}
|
|
||||||
_prim_count = quads * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the winding direction of faces
|
|
||||||
FaceOrientation FaceWinding(void) const {
|
|
||||||
return FaceOrientation::CCW;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef GLuint(SphereSection::*VertexAttribFunc)(std::vector<GLfloat>&) const;
|
|
||||||
|
|
||||||
/// Makes the vertex positions and returns the number of values per vertex
|
|
||||||
template <typename T>
|
|
||||||
GLuint Positions(std::vector<T>& dest) const {
|
|
||||||
dest.clear();
|
|
||||||
dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end());
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes the vertex normals and returns the number of values per vertex
|
|
||||||
template <typename T>
|
|
||||||
GLuint Normals(std::vector<T>& dest) const {
|
|
||||||
dest.clear();
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes the vertex tangents and returns the number of values per vertex
|
|
||||||
template <typename T>
|
|
||||||
GLuint Tangents(std::vector<T>& dest) const {
|
|
||||||
dest.clear();
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes the vertex bi-tangents and returns the number of values per vertex
|
|
||||||
template <typename T>
|
|
||||||
GLuint Bitangents(std::vector<T>& dest) const {
|
|
||||||
dest.clear();
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes the texture coordinates returns the number of values per vertex
|
|
||||||
template <typename T>
|
|
||||||
GLuint TexCoordinates(std::vector<T>& dest) const {
|
|
||||||
dest.clear();
|
|
||||||
dest.insert(dest.begin(), _tex_data.begin(), _tex_data.end());
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef VertexAttribsInfo<
|
|
||||||
SphereSection,
|
|
||||||
std::tuple<
|
|
||||||
VertexPositionsTag,
|
|
||||||
VertexNormalsTag,
|
|
||||||
VertexTangentsTag,
|
|
||||||
VertexBitangentsTag,
|
|
||||||
VertexTexCoordinatesTag
|
|
||||||
>
|
|
||||||
> VertexAttribs;
|
|
||||||
|
|
||||||
Spheref MakeBoundingSphere(void) const {
|
|
||||||
GLfloat min_x = _pos_data[3], max_x = _pos_data[3];
|
|
||||||
GLfloat min_y = _pos_data[4], max_y = _pos_data[4];
|
|
||||||
GLfloat min_z = _pos_data[5], max_z = _pos_data[5];
|
|
||||||
for (std::size_t v = 0, vn = _pos_data.size() / 3; v != vn; ++v) {
|
|
||||||
GLfloat x = _pos_data[v * 3 + 0];
|
|
||||||
GLfloat y = _pos_data[v * 3 + 1];
|
|
||||||
GLfloat z = _pos_data[v * 3 + 2];
|
|
||||||
|
|
||||||
if (min_x > x) min_x = x;
|
|
||||||
if (min_y > y) min_y = y;
|
|
||||||
if (min_z > z) min_z = z;
|
|
||||||
if (max_x < x) max_x = x;
|
|
||||||
if (max_y < y) max_y = y;
|
|
||||||
if (max_z < z) max_z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3f c(
|
|
||||||
(min_x + max_x) * 0.5f,
|
|
||||||
(min_y + max_y) * 0.5f,
|
|
||||||
(min_z + max_z) * 0.5f
|
|
||||||
);
|
|
||||||
|
|
||||||
return Spheref(
|
|
||||||
c.x(), c.y(), c.z(),
|
|
||||||
Distance(c, Vec3f(min_x, min_y, min_z))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queries the bounding sphere coordinates and dimensions
|
|
||||||
template <typename T>
|
|
||||||
void BoundingSphere(oglplus::Sphere<T>& bounding_sphere) const {
|
|
||||||
bounding_sphere = oglplus::Sphere<T>(MakeBoundingSphere());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns element indices that are used with the drawing instructions
|
|
||||||
const IndexArray & Indices(Default = Default()) const {
|
|
||||||
return _idx_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the instructions for rendering of faces
|
|
||||||
DrawingInstructions Instructions(PrimitiveType primitive) const {
|
|
||||||
DrawingInstructions instr = MakeInstructions();
|
|
||||||
DrawOperation operation;
|
|
||||||
operation.method = DrawOperation::Method::DrawElements;
|
|
||||||
operation.mode = primitive;
|
|
||||||
operation.first = 0;
|
|
||||||
operation.count = _prim_count * 3;
|
|
||||||
operation.restart_index = DrawOperation::NoRestartIndex();
|
|
||||||
operation.phase = 0;
|
|
||||||
AddInstruction(instr, operation);
|
|
||||||
return instr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the instructions for rendering of faces
|
|
||||||
DrawingInstructions Instructions(Default = Default()) const {
|
|
||||||
return Instructions(PrimitiveType::Triangles);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov, float aspect, int slices, int stacks) {
|
|
||||||
using namespace oglplus;
|
|
||||||
return ShapeWrapperPtr(
|
|
||||||
new shapes::ShapeWrapper({ "Position", "TexCoord" }, SphereSection(fov, aspect, slices, stacks), *program)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace oglplus {
|
|
||||||
namespace shapes {
|
|
||||||
|
|
||||||
class Laser : public DrawingInstructionWriter, public DrawMode {
|
|
||||||
public:
|
|
||||||
using IndexArray = std::vector<GLuint>;
|
|
||||||
using PosArray = std::vector<float>;
|
|
||||||
/// The type of the index container returned by Indices()
|
|
||||||
// vertex positions
|
|
||||||
PosArray _pos_data;
|
|
||||||
IndexArray _idx_data;
|
|
||||||
unsigned int _prim_count { 0 };
|
|
||||||
|
|
||||||
public:
|
|
||||||
Laser() {
|
|
||||||
int vertices = 2;
|
|
||||||
_pos_data.resize(vertices * 3);
|
|
||||||
_pos_data[0] = 0;
|
|
||||||
_pos_data[1] = 0;
|
|
||||||
_pos_data[2] = 0;
|
|
||||||
|
|
||||||
_pos_data[3] = 0;
|
|
||||||
_pos_data[4] = 0;
|
|
||||||
_pos_data[5] = -1;
|
|
||||||
|
|
||||||
_idx_data.push_back(0);
|
|
||||||
_idx_data.push_back(1);
|
|
||||||
_prim_count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the winding direction of faces
|
|
||||||
FaceOrientation FaceWinding(void) const {
|
|
||||||
return FaceOrientation::CCW;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queries the bounding sphere coordinates and dimensions
|
|
||||||
template <typename T>
|
|
||||||
void BoundingSphere(Sphere<T>& bounding_sphere) const {
|
|
||||||
bounding_sphere = Sphere<T>(0, 0, -0.5, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef GLuint(Laser::*VertexAttribFunc)(std::vector<GLfloat>&) const;
|
|
||||||
|
|
||||||
/// Makes the vertex positions and returns the number of values per vertex
|
|
||||||
template <typename T>
|
|
||||||
GLuint Positions(std::vector<T>& dest) const {
|
|
||||||
dest.clear();
|
|
||||||
dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end());
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef VertexAttribsInfo<
|
|
||||||
Laser,
|
|
||||||
std::tuple<VertexPositionsTag>
|
|
||||||
> VertexAttribs;
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns element indices that are used with the drawing instructions
|
|
||||||
const IndexArray & Indices(Default = Default()) const {
|
|
||||||
return _idx_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the instructions for rendering of faces
|
|
||||||
DrawingInstructions Instructions(PrimitiveType primitive) const {
|
|
||||||
DrawingInstructions instr = MakeInstructions();
|
|
||||||
DrawOperation operation;
|
|
||||||
operation.method = DrawOperation::Method::DrawElements;
|
|
||||||
operation.mode = primitive;
|
|
||||||
operation.first = 0;
|
|
||||||
operation.count = _prim_count * 3;
|
|
||||||
operation.restart_index = DrawOperation::NoRestartIndex();
|
|
||||||
operation.phase = 0;
|
|
||||||
AddInstruction(instr, operation);
|
|
||||||
return instr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the instructions for rendering of faces
|
|
||||||
DrawingInstructions Instructions(Default = Default()) const {
|
|
||||||
return Instructions(PrimitiveType::Lines);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShapeWrapperPtr loadLaser(const ProgramPtr& program) {
|
|
||||||
return std::make_shared<shapes::ShapeWrapper>(shapes::ShapeWrapper("Position", shapes::Laser(), *program));
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Bradley Austin Davis on 2015/05/26
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// FIXME support oglplus on all platforms
|
|
||||||
// For now it's a convenient helper for Windows
|
|
||||||
|
|
||||||
#include <queue>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
#include <QtGlobal>
|
|
||||||
|
|
||||||
#include "GLMHelpers.h"
|
|
||||||
|
|
||||||
#define OGLPLUS_USE_GLCOREARB_H 0
|
|
||||||
#define OGLPLUS_USE_GLEW 1
|
|
||||||
#define OGLPLUS_USE_BOOST_CONFIG 1
|
|
||||||
#define OGLPLUS_NO_SITE_CONFIG 1
|
|
||||||
#define OGLPLUS_LOW_PROFILE 1
|
|
||||||
|
|
||||||
// NOTE: oglplus does some naked "#pragma GCC" without proper platform wrapping, so we need to disable this warning.
|
|
||||||
#ifdef _WIN32
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning( disable : 4068 )
|
|
||||||
#elif defined(Q_OS_MAC)
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wpessimizing-move"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1
|
|
||||||
#pragma GCC diagnostic ignored "-Wsuggest-override"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <oglplus/gl.hpp>
|
|
||||||
|
|
||||||
#include <oglplus/all.hpp>
|
|
||||||
#include <oglplus/interop/glm.hpp>
|
|
||||||
#include <oglplus/bound/texture.hpp>
|
|
||||||
#include <oglplus/bound/framebuffer.hpp>
|
|
||||||
#include <oglplus/bound/renderbuffer.hpp>
|
|
||||||
#include <oglplus/shapes/wrapper.hpp>
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#pragma warning(pop)
|
|
||||||
#elif defined(Q_OS_MAC)
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "NumericalConstants.h"
|
|
||||||
|
|
||||||
using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>;
|
|
||||||
using RenderbufferPtr = std::shared_ptr<oglplus::Renderbuffer>;
|
|
||||||
using TexturePtr = std::shared_ptr<oglplus::Texture>;
|
|
||||||
using ShapeWrapperPtr = std::shared_ptr<oglplus::shapes::ShapeWrapper>;
|
|
||||||
using BufferPtr = std::shared_ptr<oglplus::Buffer>;
|
|
||||||
using VertexArrayPtr = std::shared_ptr<oglplus::VertexArray>;
|
|
||||||
using ProgramPtr = std::shared_ptr<oglplus::Program>;
|
|
||||||
using Mat4Uniform = oglplus::Uniform<mat4>;
|
|
||||||
|
|
||||||
ProgramPtr loadDefaultShader();
|
|
||||||
ProgramPtr loadCubemapShader();
|
|
||||||
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs);
|
|
||||||
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& gs, const std::string& fs);
|
|
||||||
|
|
||||||
ShapeWrapperPtr loadSkybox(ProgramPtr program);
|
|
||||||
ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f);
|
|
||||||
ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 128, int stacks = 128);
|
|
||||||
ShapeWrapperPtr loadLaser(const ProgramPtr& program);
|
|
||||||
|
|
||||||
|
|
||||||
// A basic wrapper for constructing a framebuffer with a renderbuffer
|
|
||||||
// for the depth attachment and an undefined type for the color attachement
|
|
||||||
// This allows us to reuse the basic framebuffer code for both the Mirror
|
|
||||||
// FBO as well as the Oculus swap textures we will use to render the scene
|
|
||||||
// Though we don't really need depth at all for the mirror FBO, or even an
|
|
||||||
// FBO, but using one means I can just use a glBlitFramebuffer to get it onto
|
|
||||||
// the screen.
|
|
||||||
template <
|
|
||||||
typename C,
|
|
||||||
typename D
|
|
||||||
>
|
|
||||||
struct FramebufferWrapper {
|
|
||||||
uvec2 size;
|
|
||||||
oglplus::Framebuffer fbo;
|
|
||||||
C color;
|
|
||||||
D depth;
|
|
||||||
|
|
||||||
FramebufferWrapper() {}
|
|
||||||
|
|
||||||
virtual ~FramebufferWrapper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Init(const uvec2 & size) {
|
|
||||||
this->size = size;
|
|
||||||
initColor();
|
|
||||||
initDepth();
|
|
||||||
initDone();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F>
|
|
||||||
void Bound(F f) {
|
|
||||||
Bound(oglplus::Framebuffer::Target::Draw, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F>
|
|
||||||
void Bound(oglplus::Framebuffer::Target target , F f) {
|
|
||||||
fbo.Bind(target);
|
|
||||||
onBind(target);
|
|
||||||
f();
|
|
||||||
onUnbind(target);
|
|
||||||
oglplus::DefaultFramebuffer().Bind(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Viewport() {
|
|
||||||
oglplus::Context::Viewport(size.x, size.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void onBind(oglplus::Framebuffer::Target target) {}
|
|
||||||
virtual void onUnbind(oglplus::Framebuffer::Target target) {}
|
|
||||||
|
|
||||||
static GLenum toEnum(oglplus::Framebuffer::Target target) {
|
|
||||||
switch (target) {
|
|
||||||
case oglplus::Framebuffer::Target::Draw:
|
|
||||||
return GL_DRAW_FRAMEBUFFER;
|
|
||||||
case oglplus::Framebuffer::Target::Read:
|
|
||||||
return GL_READ_FRAMEBUFFER;
|
|
||||||
default:
|
|
||||||
Q_ASSERT(false);
|
|
||||||
return GL_FRAMEBUFFER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void initDepth() {}
|
|
||||||
|
|
||||||
virtual void initColor() {}
|
|
||||||
|
|
||||||
virtual void initDone() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BasicFramebufferWrapper : public FramebufferWrapper <oglplus::Texture, oglplus::Renderbuffer> {
|
|
||||||
protected:
|
|
||||||
virtual void initDepth() override {
|
|
||||||
using namespace oglplus;
|
|
||||||
Context::Bound(Renderbuffer::Target::Renderbuffer, depth)
|
|
||||||
.Storage(
|
|
||||||
PixelDataInternalFormat::DepthComponent,
|
|
||||||
size.x, size.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void initColor() override {
|
|
||||||
using namespace oglplus;
|
|
||||||
Context::Bound(oglplus::Texture::Target::_2D, color)
|
|
||||||
.MinFilter(TextureMinFilter::Linear)
|
|
||||||
.MagFilter(TextureMagFilter::Linear)
|
|
||||||
.WrapS(TextureWrap::ClampToEdge)
|
|
||||||
.WrapT(TextureWrap::ClampToEdge)
|
|
||||||
.Image2D(
|
|
||||||
0, PixelDataInternalFormat::RGBA8,
|
|
||||||
size.x, size.y,
|
|
||||||
0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void initDone() override {
|
|
||||||
using namespace oglplus;
|
|
||||||
static const Framebuffer::Target target = Framebuffer::Target::Draw;
|
|
||||||
Bound(target, [&] {
|
|
||||||
fbo.AttachTexture(target, FramebufferAttachment::Color, color, 0);
|
|
||||||
fbo.AttachRenderbuffer(target, FramebufferAttachment::Depth, depth);
|
|
||||||
fbo.Complete(target);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>;
|
|
||||||
|
|
|
@ -7,5 +7,4 @@ link_hifi_libraries(shared gpu model model-networking render animation fbx entit
|
||||||
|
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
target_nsight()
|
target_nsight()
|
||||||
target_oglplus()
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
@ -23,14 +23,10 @@
|
||||||
|
|
||||||
#include <gl/QOpenGLContextWrapper.h>
|
#include <gl/QOpenGLContextWrapper.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <gl/OglplusHelpers.h>
|
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <gpu/gl/GLbackend.h>
|
#include <gpu/gl/GLbackend.h>
|
||||||
|
|
||||||
#include <ui-plugins/PluginContainer.h>
|
#include <ui-plugins/PluginContainer.h>
|
||||||
#include "OculusHelpers.h"
|
|
||||||
|
|
||||||
using namespace oglplus;
|
|
||||||
|
|
||||||
const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift");
|
const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift");
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <gl/OglplusHelpers.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "stb_font_consolas_24_latin1.inl"
|
#include "stb_font_consolas_24_latin1.inl"
|
||||||
|
|
||||||
|
@ -37,23 +35,16 @@
|
||||||
// todo : comment
|
// todo : comment
|
||||||
class TextOverlay {
|
class TextOverlay {
|
||||||
private:
|
private:
|
||||||
|
uvec2 _size;
|
||||||
|
// FIXME port from oglplus
|
||||||
|
#if 0
|
||||||
FramebufferPtr _framebuffer;
|
FramebufferPtr _framebuffer;
|
||||||
TexturePtr _texture;
|
TexturePtr _texture;
|
||||||
uvec2 _size;
|
|
||||||
BufferPtr _vertexBuffer;
|
BufferPtr _vertexBuffer;
|
||||||
ProgramPtr _program;
|
ProgramPtr _program;
|
||||||
VertexArrayPtr _vertexArray;
|
VertexArrayPtr _vertexArray;
|
||||||
|
|
||||||
//vk::DescriptorPool descriptorPool;
|
|
||||||
//vk::DescriptorSetLayout descriptorSetLayout;
|
|
||||||
//vk::DescriptorSet descriptorSet;
|
|
||||||
//vk::PipelineLayout pipelineLayout;
|
|
||||||
//vk::Pipeline pipeline;
|
|
||||||
|
|
||||||
// Pointer to mapped vertex buffer
|
// Pointer to mapped vertex buffer
|
||||||
glm::vec4* _mapped { nullptr };
|
glm::vec4* _mapped { nullptr };
|
||||||
stb_fontchar stbFontData[STB_NUM_CHARS];
|
|
||||||
uint32_t numLetters;
|
|
||||||
|
|
||||||
const char* const VERTEX_SHADER = R"SHADER(
|
const char* const VERTEX_SHADER = R"SHADER(
|
||||||
#version 450 core
|
#version 450 core
|
||||||
|
@ -92,6 +83,12 @@ void main(void)
|
||||||
}
|
}
|
||||||
)SHADER";
|
)SHADER";
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
stb_fontchar stbFontData[STB_NUM_CHARS];
|
||||||
|
uint32_t numLetters;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum TextAlign { alignLeft, alignCenter, alignRight };
|
enum TextAlign { alignLeft, alignCenter, alignRight };
|
||||||
|
|
||||||
|
@ -104,11 +101,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
~TextOverlay() {
|
~TextOverlay() {
|
||||||
|
#if 0
|
||||||
// Free up all Vulkan resources requested by the text overlay
|
// Free up all Vulkan resources requested by the text overlay
|
||||||
_program.reset();
|
_program.reset();
|
||||||
_texture.reset();
|
_texture.reset();
|
||||||
_vertexBuffer.reset();
|
_vertexBuffer.reset();
|
||||||
_vertexArray.reset();
|
_vertexArray.reset();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(const uvec2& size) {
|
void resize(const uvec2& size) {
|
||||||
|
@ -118,6 +117,7 @@ public:
|
||||||
// Prepare all vulkan resources required to render the font
|
// Prepare all vulkan resources required to render the font
|
||||||
// The text overlay uses separate resources for descriptors (pool, sets, layouts), pipelines and command buffers
|
// The text overlay uses separate resources for descriptors (pool, sets, layouts), pipelines and command buffers
|
||||||
void prepare() {
|
void prepare() {
|
||||||
|
#if 0
|
||||||
static unsigned char font24pixels[STB_FONT_HEIGHT][STB_FONT_WIDTH];
|
static unsigned char font24pixels[STB_FONT_HEIGHT][STB_FONT_WIDTH];
|
||||||
STB_FONT_NAME(stbFontData, font24pixels, STB_FONT_HEIGHT);
|
STB_FONT_NAME(stbFontData, font24pixels, STB_FONT_HEIGHT);
|
||||||
|
|
||||||
|
@ -154,14 +154,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
compileProgram(_program, VERTEX_SHADER, FRAGMENT_SHADER);
|
compileProgram(_program, VERTEX_SHADER, FRAGMENT_SHADER);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Map buffer
|
// Map buffer
|
||||||
void beginTextUpdate() {
|
void beginTextUpdate() {
|
||||||
|
#if 0
|
||||||
using namespace oglplus;
|
using namespace oglplus;
|
||||||
_mapped = (glm::vec4*)glMapNamedBuffer(GetName(*_vertexBuffer), GL_WRITE_ONLY);
|
_mapped = (glm::vec4*)glMapNamedBuffer(GetName(*_vertexBuffer), GL_WRITE_ONLY);
|
||||||
numLetters = 0;
|
numLetters = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add text to the current buffer
|
// Add text to the current buffer
|
||||||
|
@ -223,17 +226,21 @@ public:
|
||||||
|
|
||||||
// Unmap buffer and update command buffers
|
// Unmap buffer and update command buffers
|
||||||
void endTextUpdate() {
|
void endTextUpdate() {
|
||||||
|
#if 0
|
||||||
glUnmapNamedBuffer(GetName(*_vertexBuffer));
|
glUnmapNamedBuffer(GetName(*_vertexBuffer));
|
||||||
_mapped = nullptr;
|
_mapped = nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needs to be called by the application
|
// Needs to be called by the application
|
||||||
void render() {
|
void render() {
|
||||||
|
#if 0
|
||||||
_texture->Bind(oglplus::TextureTarget::_2D);
|
_texture->Bind(oglplus::TextureTarget::_2D);
|
||||||
_program->Use();
|
_program->Use();
|
||||||
_vertexArray->Bind();
|
_vertexArray->Bind();
|
||||||
for (uint32_t j = 0; j < numLetters; j++) {
|
for (uint32_t j = 0; j < numLetters; j++) {
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, j * 4, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, j * 4, 4);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,8 +5,6 @@ set(TARGET_NAME shaders-test)
|
||||||
setup_hifi_project(Quick Gui OpenGL)
|
setup_hifi_project(Quick Gui OpenGL)
|
||||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||||
|
|
||||||
#include_oglplus()
|
|
||||||
|
|
||||||
# link in the shared libraries
|
# link in the shared libraries
|
||||||
link_hifi_libraries(shared octree gl gpu gpu-gl model render fbx networking entities
|
link_hifi_libraries(shared octree gl gpu gpu-gl model render fbx networking entities
|
||||||
script-engine physics
|
script-engine physics
|
||||||
|
|
|
@ -1,643 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Bradley Austin Davis on 2015-04-22
|
|
||||||
// Copyright 2013-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 <gl/Config.h>
|
|
||||||
#include <gl/OglplusHelpers.h>
|
|
||||||
#include <gl/GLHelpers.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <QtCore/QFile>
|
|
||||||
#include <QtCore/QDir>
|
|
||||||
#include <QtCore/QTime>
|
|
||||||
#include <QtCore/QTimer>
|
|
||||||
#include <QtCore/QElapsedTimer>
|
|
||||||
#include <QtCore/QLoggingCategory>
|
|
||||||
#include <QtCore/QThread>
|
|
||||||
#include <QtCore/QUuid>
|
|
||||||
|
|
||||||
#include <QtGui/QWindow>
|
|
||||||
#include <QtGui/QImage>
|
|
||||||
#include <QtGui/QGuiApplication>
|
|
||||||
#include <QtGui/QResizeEvent>
|
|
||||||
#include <QtGui/QScreen>
|
|
||||||
|
|
||||||
#include <gl/QOpenGLContextWrapper.h>
|
|
||||||
|
|
||||||
#include <QtScript/QScriptEngine>
|
|
||||||
|
|
||||||
#include <QtQml/QQmlContext>
|
|
||||||
#include <QtQml/QQmlApplicationEngine>
|
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
|
||||||
#include <gl/OffscreenGLCanvas.h>
|
|
||||||
#include <OffscreenUi.h>
|
|
||||||
#include <PathUtils.h>
|
|
||||||
#include <PathUtils.h>
|
|
||||||
#include <VrMenu.h>
|
|
||||||
#include <InfoView.h>
|
|
||||||
#include <QmlWebWindowClass.h>
|
|
||||||
#include <RegisteredMetaTypes.h>
|
|
||||||
|
|
||||||
const QString& getResourcesDir() {
|
|
||||||
static QString dir;
|
|
||||||
if (dir.isEmpty()) {
|
|
||||||
QDir path(__FILE__);
|
|
||||||
path.cdUp();
|
|
||||||
dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/";
|
|
||||||
qDebug() << "Resources Path: " << dir;
|
|
||||||
}
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString& getExamplesDir() {
|
|
||||||
static QString dir;
|
|
||||||
if (dir.isEmpty()) {
|
|
||||||
QDir path(__FILE__);
|
|
||||||
path.cdUp();
|
|
||||||
dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/";
|
|
||||||
qDebug() << "Resources Path: " << dir;
|
|
||||||
}
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString& getInterfaceQmlDir() {
|
|
||||||
static QString dir;
|
|
||||||
if (dir.isEmpty()) {
|
|
||||||
dir = getResourcesDir() + "qml/";
|
|
||||||
qDebug() << "Qml Path: " << dir;
|
|
||||||
}
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString& getTestQmlDir() {
|
|
||||||
static QString dir;
|
|
||||||
if (dir.isEmpty()) {
|
|
||||||
QDir path(__FILE__);
|
|
||||||
path.cdUp();
|
|
||||||
dir = path.cleanPath(path.absoluteFilePath("../")) + "/";
|
|
||||||
qDebug() << "Qml Test Path: " << dir;
|
|
||||||
}
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class RateCounter {
|
|
||||||
std::vector<float> times;
|
|
||||||
QElapsedTimer timer;
|
|
||||||
public:
|
|
||||||
RateCounter() {
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
times.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t count() const {
|
|
||||||
return times.size() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float elapsed() const {
|
|
||||||
if (times.size() < 1) {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
float elapsed = *times.rbegin() - *times.begin();
|
|
||||||
return elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void increment() {
|
|
||||||
times.push_back(timer.elapsed() / 1000.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
float rate() const {
|
|
||||||
if (elapsed() == 0.0f) {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
return (float) count() / elapsed();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern QOpenGLContext* qt_gl_global_share_context();
|
|
||||||
|
|
||||||
|
|
||||||
static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) {
|
|
||||||
if (engine.hasUncaughtException()) {
|
|
||||||
const auto backtrace = engine.uncaughtExceptionBacktrace();
|
|
||||||
const auto exception = engine.uncaughtException().toString();
|
|
||||||
const auto line = QString::number(engine.uncaughtExceptionLineNumber());
|
|
||||||
engine.clearExceptions();
|
|
||||||
|
|
||||||
auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
|
|
||||||
if (!backtrace.empty()) {
|
|
||||||
static const auto lineSeparator = "\n ";
|
|
||||||
message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
|
|
||||||
}
|
|
||||||
qWarning() << qPrintable(message);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f);
|
|
||||||
|
|
||||||
static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) {
|
|
||||||
QString message = "";
|
|
||||||
for (int i = 0; i < context->argumentCount(); i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
message += " ";
|
|
||||||
}
|
|
||||||
message += context->argument(i).toString();
|
|
||||||
}
|
|
||||||
qDebug().noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline
|
|
||||||
|
|
||||||
message = message.replace("\\", "\\\\")
|
|
||||||
.replace("\n", "\\n")
|
|
||||||
.replace("\r", "\\r")
|
|
||||||
.replace("'", "\\'");
|
|
||||||
engine->evaluate("Script.print('" + message + "')");
|
|
||||||
|
|
||||||
return QScriptValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ScriptEngine : public QScriptEngine {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
void loadFile(const QString& scriptPath) {
|
|
||||||
if (_isRunning) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
qDebug() << "Loading script from " << scriptPath;
|
|
||||||
_fileNameString = scriptPath;
|
|
||||||
|
|
||||||
QFile file(scriptPath);
|
|
||||||
if (file.exists()) {
|
|
||||||
file.open(QIODevice::ReadOnly);
|
|
||||||
_scriptContents = file.readAll();
|
|
||||||
} else {
|
|
||||||
qFatal("Missing file ");
|
|
||||||
}
|
|
||||||
runInThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE void stop() {
|
|
||||||
if (!_isFinished) {
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
QMetaObject::invokeMethod(this, "stop");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_isFinished = true;
|
|
||||||
if (_wantSignals) {
|
|
||||||
emit runningStateChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE void print(const QString& message) {
|
|
||||||
if (_wantSignals) {
|
|
||||||
emit printedMessage(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) {
|
|
||||||
// create the timer, add it to the map, and start it
|
|
||||||
QTimer* newTimer = new QTimer(this);
|
|
||||||
newTimer->setSingleShot(isSingleShot);
|
|
||||||
|
|
||||||
connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
|
|
||||||
|
|
||||||
// make sure the timer stops when the script does
|
|
||||||
connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
|
|
||||||
|
|
||||||
_timerFunctionMap.insert(newTimer, function);
|
|
||||||
|
|
||||||
newTimer->start(intervalMS);
|
|
||||||
return newTimer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) {
|
|
||||||
return setupTimerWithInterval(function, intervalMS, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) {
|
|
||||||
return setupTimerWithInterval(function, timeoutMS, true);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
|
|
||||||
void runInThread() {
|
|
||||||
QThread* workerThread = new QThread();
|
|
||||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
|
||||||
connect(workerThread, &QThread::started, this, &ScriptEngine::run);
|
|
||||||
connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater);
|
|
||||||
connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
|
|
||||||
moveToThread(workerThread);
|
|
||||||
workerThread->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void init() {
|
|
||||||
_isInitialized = true;
|
|
||||||
registerMetaTypes(this);
|
|
||||||
registerGlobalObject("Script", this);
|
|
||||||
qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
|
|
||||||
qScriptRegisterSequenceMetaType<QVector<QString>>(this);
|
|
||||||
globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor));
|
|
||||||
QScriptValue printConstructorValue = newFunction(debugPrint);
|
|
||||||
globalObject().setProperty("print", printConstructorValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerFired() {
|
|
||||||
QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
|
|
||||||
QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
|
|
||||||
|
|
||||||
if (!callingTimer->isActive()) {
|
|
||||||
// this timer is done, we can kill it
|
|
||||||
_timerFunctionMap.remove(callingTimer);
|
|
||||||
delete callingTimer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// call the associated JS function, if it exists
|
|
||||||
if (timerFunction.isValid()) {
|
|
||||||
timerFunction.call();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void run() {
|
|
||||||
if (!_isInitialized) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
_isRunning = true;
|
|
||||||
if (_wantSignals) {
|
|
||||||
emit runningStateChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue result = evaluate(_scriptContents, _fileNameString);
|
|
||||||
QElapsedTimer startTime;
|
|
||||||
startTime.start();
|
|
||||||
|
|
||||||
int thisFrame = 0;
|
|
||||||
|
|
||||||
qint64 lastUpdate = usecTimestampNow();
|
|
||||||
|
|
||||||
while (!_isFinished) {
|
|
||||||
int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
|
|
||||||
if (usecToSleep > 0) {
|
|
||||||
usleep(usecToSleep);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_isFinished) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
if (_isFinished) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 now = usecTimestampNow();
|
|
||||||
float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND;
|
|
||||||
if (!_isFinished) {
|
|
||||||
if (_wantSignals) {
|
|
||||||
emit update(deltaTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastUpdate = now;
|
|
||||||
|
|
||||||
// Debug and clear exceptions
|
|
||||||
hadUncaughtExceptions(*this, _fileNameString);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_wantSignals) {
|
|
||||||
emit scriptEnding();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_wantSignals) {
|
|
||||||
emit finished(_fileNameString, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
_isRunning = false;
|
|
||||||
|
|
||||||
if (_wantSignals) {
|
|
||||||
emit runningStateChanged();
|
|
||||||
emit doneRunning();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerGlobalObject(const QString& name, QObject* object) {
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
QMetaObject::invokeMethod(this, "registerGlobalObject",
|
|
||||||
Q_ARG(const QString&, name),
|
|
||||||
Q_ARG(QObject*, object));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!globalObject().property(name).isValid()) {
|
|
||||||
if (object) {
|
|
||||||
QScriptValue value = newQObject(object);
|
|
||||||
globalObject().setProperty(name, value);
|
|
||||||
} else {
|
|
||||||
globalObject().setProperty(name, QScriptValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
QMetaObject::invokeMethod(this, "registerFunction",
|
|
||||||
Q_ARG(const QString&, name),
|
|
||||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
|
||||||
Q_ARG(int, numArguments));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QScriptValue scriptFun = newFunction(functionSignature, numArguments);
|
|
||||||
globalObject().setProperty(name, scriptFun);
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
QMetaObject::invokeMethod(this, "registerFunction",
|
|
||||||
Q_ARG(const QString&, name),
|
|
||||||
Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
|
|
||||||
Q_ARG(int, numArguments));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue object = globalObject().property(parent);
|
|
||||||
if (object.isValid()) {
|
|
||||||
QScriptValue scriptFun = newFunction(functionSignature, numArguments);
|
|
||||||
object.setProperty(name, scriptFun);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void scriptLoaded(const QString& scriptFilename);
|
|
||||||
void errorLoadingScript(const QString& scriptFilename);
|
|
||||||
void update(float deltaTime);
|
|
||||||
void scriptEnding();
|
|
||||||
void finished(const QString& fileNameString, ScriptEngine* engine);
|
|
||||||
void cleanupMenuItem(const QString& menuItemString);
|
|
||||||
void printedMessage(const QString& message);
|
|
||||||
void errorMessage(const QString& message);
|
|
||||||
void runningStateChanged();
|
|
||||||
void evaluationFinished(QScriptValue result, bool isException);
|
|
||||||
void loadScript(const QString& scriptName, bool isUserLoaded);
|
|
||||||
void reloadScript(const QString& scriptName, bool isUserLoaded);
|
|
||||||
void doneRunning();
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString _scriptContents;
|
|
||||||
QString _fileNameString;
|
|
||||||
QString _parentURL;
|
|
||||||
bool _isInitialized { false };
|
|
||||||
std::atomic<bool> _isFinished { false };
|
|
||||||
std::atomic<bool> _isRunning { false };
|
|
||||||
bool _wantSignals { true };
|
|
||||||
QHash<QTimer*, QScriptValue> _timerFunctionMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ScriptEngine* loadScript(const QString& scriptFilename) {
|
|
||||||
ScriptEngine* scriptEngine = new ScriptEngine();
|
|
||||||
scriptEngine->loadFile(scriptFilename);
|
|
||||||
return scriptEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
OffscreenGLCanvas* _chromiumShareContext { nullptr };
|
|
||||||
Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
|
|
||||||
|
|
||||||
|
|
||||||
// Create a simple OpenGL window that renders text in various ways
|
|
||||||
class QTestWindow : public QWindow {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
QOpenGLContextWrapper* _context{ nullptr };
|
|
||||||
QSize _size;
|
|
||||||
bool _altPressed{ false };
|
|
||||||
RateCounter fps;
|
|
||||||
QTimer _timer;
|
|
||||||
int testQmlTexture{ 0 };
|
|
||||||
ProgramPtr _program;
|
|
||||||
ShapeWrapperPtr _plane;
|
|
||||||
QScriptEngine* _scriptEngine { nullptr };
|
|
||||||
|
|
||||||
public:
|
|
||||||
QObject* rootMenu;
|
|
||||||
|
|
||||||
QTestWindow() {
|
|
||||||
_scriptEngine = new ScriptEngine();
|
|
||||||
_timer.setInterval(1);
|
|
||||||
QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw);
|
|
||||||
|
|
||||||
_chromiumShareContext = new OffscreenGLCanvas();
|
|
||||||
_chromiumShareContext->create();
|
|
||||||
_chromiumShareContext->makeCurrent();
|
|
||||||
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
|
||||||
|
|
||||||
{
|
|
||||||
setSurfaceType(QSurface::OpenGLSurface);
|
|
||||||
QSurfaceFormat format = getDefaultOpenGLSurfaceFormat();
|
|
||||||
setFormat(format);
|
|
||||||
_context = new QOpenGLContextWrapper();
|
|
||||||
_context->setFormat(format);
|
|
||||||
_context->setShareContext(_chromiumShareContext->getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!_context->create()) {
|
|
||||||
qFatal("Could not create OpenGL context");
|
|
||||||
}
|
|
||||||
|
|
||||||
show();
|
|
||||||
|
|
||||||
makeCurrent();
|
|
||||||
|
|
||||||
glewExperimental = true;
|
|
||||||
glewInit();
|
|
||||||
glGetError();
|
|
||||||
|
|
||||||
using namespace oglplus;
|
|
||||||
Context::Enable(Capability::Blend);
|
|
||||||
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
|
|
||||||
Context::Disable(Capability::DepthTest);
|
|
||||||
Context::Disable(Capability::CullFace);
|
|
||||||
Context::ClearColor(0.2f, 0.2f, 0.2f, 1);
|
|
||||||
|
|
||||||
InfoView::registerType();
|
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::set<OffscreenUi>();
|
|
||||||
{
|
|
||||||
offscreenUi->create(_context->getContext());
|
|
||||||
offscreenUi->setProxyWindow(this);
|
|
||||||
|
|
||||||
connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) {
|
|
||||||
testQmlTexture = textureId;
|
|
||||||
});
|
|
||||||
|
|
||||||
makeCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
auto primaryScreen = QGuiApplication::primaryScreen();
|
|
||||||
auto targetScreen = primaryScreen;
|
|
||||||
auto screens = QGuiApplication::screens();
|
|
||||||
if (screens.size() > 1) {
|
|
||||||
for (auto screen : screens) {
|
|
||||||
if (screen != targetScreen) {
|
|
||||||
targetScreen = screen;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto rect = targetScreen->availableGeometry();
|
|
||||||
rect.setWidth(rect.width() * 0.8f);
|
|
||||||
rect.setHeight(rect.height() * 0.8f);
|
|
||||||
rect.moveTo(QPoint(20, 20));
|
|
||||||
setGeometry(rect);
|
|
||||||
|
|
||||||
#ifdef QML_CONTROL_GALLERY
|
|
||||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir()));
|
|
||||||
offscreenUi->load(QUrl("main.qml"));
|
|
||||||
#else
|
|
||||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir()));
|
|
||||||
offscreenUi->load(QUrl("TestRoot.qml"));
|
|
||||||
#endif
|
|
||||||
installEventFilter(offscreenUi.data());
|
|
||||||
offscreenUi->resume();
|
|
||||||
_timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~QTestWindow() {
|
|
||||||
DependencyManager::destroy<OffscreenUi>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void draw() {
|
|
||||||
if (!isVisible()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
makeCurrent();
|
|
||||||
auto error = glGetError();
|
|
||||||
if (error != GL_NO_ERROR) {
|
|
||||||
qDebug() << "GL error in entering draw " << error;
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace oglplus;
|
|
||||||
Context::Clear().ColorBuffer().DepthBuffer();
|
|
||||||
ivec2 size(_size.width(), _size.height());
|
|
||||||
size *= devicePixelRatio();
|
|
||||||
size = glm::max(size, ivec2(100, 100));
|
|
||||||
Context::Viewport(size.x, size.y);
|
|
||||||
if (!_program) {
|
|
||||||
_program = loadDefaultShader();
|
|
||||||
_plane = loadPlane(_program);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (testQmlTexture > 0) {
|
|
||||||
glBindTexture(GL_TEXTURE_2D, testQmlTexture);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
}
|
|
||||||
|
|
||||||
_program->Bind();
|
|
||||||
_plane->Use();
|
|
||||||
_plane->Draw();
|
|
||||||
_context->swapBuffers(this);
|
|
||||||
|
|
||||||
fps.increment();
|
|
||||||
if (fps.elapsed() >= 10.0f) {
|
|
||||||
qDebug() << "FPS: " << fps.rate();
|
|
||||||
fps.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeCurrent() {
|
|
||||||
_context->makeCurrent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resizeWindow(const QSize & size) {
|
|
||||||
_size = size;
|
|
||||||
DependencyManager::get<OffscreenUi>()->resize(_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void resizeEvent(QResizeEvent* ev) override {
|
|
||||||
resizeWindow(ev->size());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void keyPressEvent(QKeyEvent* event) override {
|
|
||||||
_altPressed = Qt::Key_Alt == event->key();
|
|
||||||
switch (event->key()) {
|
|
||||||
case Qt::Key_B:
|
|
||||||
if (event->modifiers() & Qt::CTRL) {
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
|
||||||
offscreenUi->load("Browser.qml");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Qt::Key_J:
|
|
||||||
if (event->modifiers() & Qt::CTRL) {
|
|
||||||
loadScript(getExamplesDir() + "tests/qmlWebTest.js");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Qt::Key_K:
|
|
||||||
if (event->modifiers() & Qt::CTRL) {
|
|
||||||
OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){
|
|
||||||
qDebug() << b;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
QWindow::keyPressEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveEvent(QMoveEvent* event) override {
|
|
||||||
static qreal oldPixelRatio = 0.0;
|
|
||||||
if (devicePixelRatio() != oldPixelRatio) {
|
|
||||||
oldPixelRatio = devicePixelRatio();
|
|
||||||
resizeWindow(size());
|
|
||||||
}
|
|
||||||
QWindow::moveEvent(event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const char * LOG_FILTER_RULES = R"V0G0N(
|
|
||||||
hifi.offscreen.focus.debug=false
|
|
||||||
qt.quick.mouse.debug=false
|
|
||||||
)V0G0N";
|
|
||||||
|
|
||||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
|
||||||
QString logMessage = message;
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
if (!logMessage.isEmpty()) {
|
|
||||||
OutputDebugStringA(logMessage.toLocal8Bit().constData());
|
|
||||||
OutputDebugStringA("\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
QGuiApplication app(argc, argv);
|
|
||||||
qInstallMessageHandler(messageHandler);
|
|
||||||
QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
|
|
||||||
QTestWindow window;
|
|
||||||
app.exec();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "main.moc"
|
|
Loading…
Reference in a new issue