git-svn-id: svn://db.shs.com.ru/libs@626 a8b55f48-bf90-11e4-a774-851b48703e85

This commit is contained in:
2019-11-22 15:20:52 +00:00
parent 5e2b563d57
commit 09248aae34
128 changed files with 16038 additions and 0 deletions

65
qglengine/CMakeLists.txt Normal file
View File

@@ -0,0 +1,65 @@
project(qglengine)
cmake_minimum_required(VERSION 2.6)
find_package(QAD REQUIRED)
if (NOT Qt5)
message(WARNING "Building ${PROJECT_NAME} available only on Qt5!")
return()
endif()
if (POLICY CMP0017)
cmake_policy(SET CMP0017 NEW)
endif()
if (IBPROJECT)
include(SDKMacros)
else()
option(LIB "System install" 0)
option(DEBUG "Build with -g3" 0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
if (DEBUG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3")
endif()
endif()
if (MINGW)
find_package(MinGW REQUIRED)
endif()
find_package(OpenGL REQUIRED)
include_directories(${QAD_INCLUDES} {CMAKE_CURRENT_SOURCE_DIR})
find_qt(Qt5 Core Gui OpenGL Xml)
qt_sources(SRC)
qt_sources(FSRC DIR "formats")
list(APPEND SRC ${FSRC})
qt_wrap(${SRC} HDRS out_HDR CPPS out_CPP QMS out_QM)
qt_add_library(qglengine_core SHARED out_CPP)
qt_target_link_libraries(qglengine_core qad_utils qad_widgets assimp ${OPENGL_LIBRARIES})
message(STATUS "Building qglengine_core")
list(APPEND QT_MULTILIB_LIST qglengine_core)
add_subdirectory(widgets)
set(QT_MULTILIB_LIST ${QT_MULTILIB_LIST} PARENT_SCOPE)
if (LIBPROJECT)
sdk_install("qglengine" "qglengine_core" "${out_HDR}" "${out_QM}")
else()
if (LIB)
if (WIN32)
qt_install(FILES ${out_HDR} DESTINATION ${MINGW_INCLUDE}/qglengine)
qt_install(TARGETS qglengine_core DESTINATION ${MINGW_LIB})
qt_install(TARGETS qglengine_core DESTINATION ${MINGW_BIN})
qt_install(TARGETS qglengine_core DESTINATION QtBin)
else()
qt_install(FILES ${out_HDR} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/qglengine)
qt_install(TARGETS qglengine_core DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
endif()
message(STATUS "Install qglengine_core to system \"${CMAKE_INSTALL_PREFIX}\"")
else()
qt_install(TARGETS qglengine_core DESTINATION bin)
message(STATUS "Install qglengine_core to local \"bin\"")
endif()
endif()
if (NOT DEFINED ANDROID_PLATFORM)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin")
#add_subdirectory(plugin)
endif()
endif()
qt_sources(test_SRC DIR "qglview_test")
qt_wrap(${test_SRC} CPPS test_CPP)
qt_add_executable(qglview_test test_CPP)
qt_target_link_libraries(qglview_test qglengine_core qglengine_widgets)

View File

@@ -0,0 +1,133 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "loader_assimp.h"
#include "glscene.h"
#include "glmesh.h"
#include "glmaterial.h"
#include "globject.h"
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
#include <assimp/material.h>
QVector3D fromAiVector3D(const aiVector3D & v) {return QVector3D(v.x, v.y, v.z);}
Vector3i fromAiFace (const aiFace & v) {return Vector3i(v.mIndices[0], v.mIndices[1], v.mIndices[2]);}
QMatrix4x4 fromAiMatrix4D(const aiMatrix4x4 & v) {return QMatrix4x4(v.a1, v.a2, v.a3, v.a4,
v.b1, v.b2, v.b3, v.b4,
v.c1, v.c2, v.c3, v.c4,
v.d1, v.d2, v.d3, v.d4);}
bool isAiMeshTriangles(const aiMesh * m) {return (m->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) == aiPrimitiveType_TRIANGLE;}
Mesh * assimpMesh(const aiMesh * m) {
if (!m) return 0;
if (!isAiMeshTriangles(m)) return 0;
Mesh * ret = new Mesh();
int vcnt = m->mNumVertices, tcnt = m->mNumFaces;
QVector<QVector3D> & v(ret->vertices()); v.resize(vcnt);
QVector<QVector2D> & t(ret->texcoords()); t.resize(vcnt);
QVector< Vector3i> & ind(ret->indices());
for (int i = 0; i < vcnt; ++i)
v[i] = fromAiVector3D(m->mVertices[i]);
if (m->HasNormals()) {
QVector<QVector3D> & n(ret->normals());
n.resize(vcnt);
for (int i = 0; i < vcnt; ++i)
n[i] = fromAiVector3D(m->mNormals[i]);
}
if (m->HasTextureCoords(0)) {
for (int i = 0; i < vcnt; ++i)
t[i] = fromAiVector3D(m->mTextureCoords[0][i]).toVector2D();
}
if (m->HasFaces()) {
ind.resize(tcnt);
for (int i = 0; i < tcnt; ++i)
ind[i] = fromAiFace(m->mFaces[i]);
} else {
tcnt = vcnt / 3;
ind.resize(tcnt);
int si = 0;
for (int i = 0; i < tcnt; ++i) {
si = i+i+i;
ind[i] = Vector3i(si, si+1, si+2);
}
}
//qDebug() << "add mesh" << v.size() << ret->normals().size() << ret->texcoords().size() << ret->indices().size();
return ret;
}
ObjectBase * assimpObject(const aiNode * n, const QVector<Mesh * > & meshes) {
if (!n) return 0;
ObjectBase * ret = new ObjectBase();
ret->setName(n->mName.C_Str());
ret->setTransform(fromAiMatrix4D(n->mTransformation));
//qDebug() << "add object" << ret << ret->name();
for (uint i = 0; i < n->mNumMeshes; ++i) {
int mi = n->mMeshes[i];
if (meshes[mi]) {
ret->setMesh(meshes[mi]);
//qDebug() << "set mesh" << mi << ret->mesh();
break;
}
}
for (uint i = 0; i < n->mNumChildren; ++i) {
ObjectBase * co = assimpObject(n->mChildren[i], meshes);
if (co) ret->addChild(co);
}
return ret;
}
Scene * loadScene(const QString & filepath) {
if (filepath.isEmpty()) return 0;
qDebug() << "[Loader Assimp] Import" << filepath << "...";
Assimp::Importer importer;
const aiScene * ais = importer.ReadFile(filepath.toUtf8(), aiProcess_Triangulate |
aiProcess_SortByPType |
aiProcess_GenUVCoords |
aiProcess_TransformUVCoords);
if (!ais) {
qDebug() << "[Loader Assimp] Error: \"" + QString(importer.GetErrorString()) + "\"";
return 0;
}
qDebug() << "[Loader Assimp] Imported" << ais->mNumMeshes << "meshes";
QVector<Mesh * > meshes;
for (uint i = 0; i < ais->mNumMeshes; ++i)
meshes << assimpMesh(ais->mMeshes[i]);
ObjectBase * root = assimpObject(ais->mRootNode, meshes);
if (!root) return 0;
Scene * scene = new Scene();
scene->setName(root->name());
foreach (ObjectBase * o, root->children())
scene->addObject(o);
return scene;
}

View File

@@ -0,0 +1,26 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOADER_ASSIMP_H
#define LOADER_ASSIMP_H
#include "gltypes.h"
Scene * loadScene(const QString & filepath);
#endif // LOADER_ASSIMP_H

View File

@@ -0,0 +1,67 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "loader_qgl.h"
#include "glscene.h"
#include <chunkstream.h>
Scene * loadFromQGLFile(const QString & filepath) {
QFile f(filepath);
if (!f.exists()) {
qDebug() << "[Loader QGL] Error: can`t open \"" + filepath + "\"";
return 0;
}
f.open(QIODevice::ReadOnly);
QDataStream s(&f);
s.setVersion(QDataStream::Qt_5_0);
char sign[4];
s.readRawData(sign, 4);
if ((sign[0] != 'Q') || (sign[1] != 'G') || (sign[2] != 'L') || (sign[3] != 'E')) {
qDebug() << "[Loader QGL] Error: \"" + filepath + "\" is not valid QGLEngine file!";
return 0;
}
ushort version = 0x1;
f.peek((char*)&version, 2);
if (version != 1) {
qDebug() << "[Loader QGL] Error: \"" + filepath + "\" unsupported version!";
return 0;
}
Scene * ret = 0;
s.skipRawData(2);
s >> ret;
//root->buildTransform();
qDebug() << "[Loader QGL] Loaded" << ret->objectsCount(true) << "objects from" << filepath;
return ret;
}
bool saveToQGLFile(const QString & filepath, const Scene * scene) {
QFile f(filepath);
if (!f.open(QIODevice::ReadWrite))
return false;
f.resize(0);
QDataStream s(&f);
s.setVersion(QDataStream::Qt_5_0);
char sign[4] = {'Q', 'G', 'L', 'E'};
ushort version = 0x1;
s.writeRawData(sign, 4);
s.writeRawData((char*)&version, 2);
s << scene;
return true;
}

View File

@@ -0,0 +1,28 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOADER_QGL_H
#define LOADER_QGL_H
#include "gltypes.h"
#include <QFileInfo>
Scene * loadFromQGLFile(const QString & filepath);
bool saveToQGLFile(const QString & filepath, const Scene * scene);
#endif // LOADER_QGL_H

87
qglengine/glbuffer.cpp Normal file
View File

@@ -0,0 +1,87 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "glbuffer.h"
Buffer::Buffer(GLenum target, GLenum _usage) {
target_ = target;
usage_ = _usage;
buffer_ = 0;
prev_size = 0;
}
Buffer::~Buffer() {
}
void Buffer::init(QOpenGLExtraFunctions * f) {
if (!isInit()) {
f->glGenBuffers(1, &buffer_);
}
}
void Buffer::destroy(QOpenGLExtraFunctions * f) {
if (buffer_ != 0) {
f->glDeleteBuffers(1, &buffer_);
}
buffer_ = 0;
}
void Buffer::bind(QOpenGLExtraFunctions * f) {
f->glBindBuffer(target_, buffer_);
}
void Buffer::release(QOpenGLExtraFunctions * f) {
f->glBindBuffer(target_, 0);
}
void * Buffer::map(QOpenGLExtraFunctions * f, GLbitfield mode, int size) {
if (size < 0) size = prev_size;
return f->glMapBufferRange(target_, 0, size, mode);
}
void Buffer::unmap(QOpenGLExtraFunctions * f) {
f->glUnmapBuffer(target_);
}
bool Buffer::resize(QOpenGLExtraFunctions * f, int new_size) {
if (new_size <= 0) return false;
//qDebug() << "check resize buffer" << buffer_ << "bytes" << new_size << ", old =" << prev_size;
if (new_size <= prev_size) return false;
prev_size = new_size;
//qDebug() << "resize buffer " << buffer_ << target_ << "for" << new_size << "bytes";
f->glBufferData(target_, new_size, 0, usage_);
return true;
}
void Buffer::load(QOpenGLExtraFunctions * f, const void * data, int size, int offset) {
if (!data || size <= 0) return;
//qDebug() << "load buffer" << buffer_ << "bytes" << size;
f->glBufferSubData(target_, offset, size, data);
}

56
qglengine/glbuffer.h Normal file
View File

@@ -0,0 +1,56 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLBUFFER_H
#define GLBUFFER_H
#include "gltypes.h"
class Buffer
{
friend class ObjectBase;
public:
Buffer(GLenum target, GLenum usage = GL_DYNAMIC_DRAW);
~Buffer();
void init (QOpenGLExtraFunctions * f);
void destroy (QOpenGLExtraFunctions * f);
void bind (QOpenGLExtraFunctions * f);
void release (QOpenGLExtraFunctions * f);
void * map (QOpenGLExtraFunctions * f, GLbitfield mode, int size = -1);
void unmap (QOpenGLExtraFunctions * f);
// returns true if size changed
bool resize (QOpenGLExtraFunctions * f, int new_size);
void load (QOpenGLExtraFunctions * f, const void * data, int size, int offset = 0);
GLuint ID() const {return buffer_;}
GLenum usage() const {return usage_;}
bool isInit() const {return buffer_ != 0;}
private:
GLenum target_, usage_;
GLuint buffer_;
int prev_size;
};
#endif // GLBUFFER_H

313
qglengine/glcamera.cpp Normal file
View File

@@ -0,0 +1,313 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gltypes.h"
#include "qglview.h"
Camera::Camera() {
type_ = glCamera;
fov_ = 60.;
angle_limit_lower_xy = 0.f;
angle_limit_upper_xy = 360.f;
angles_.setY(270.f);
depth_start = 0.1f;
depth_end = 1000.f;
mirror_x = mirror_y = false;
}
void Camera::anglesFromPoints() {
QVector3D dv = aim_ - pos_, tv;
tv = QVector3D(dv.x(), dv.y(), 0.);
angles_.setZ(atan2f(tv.x(), tv.y()) * rad2deg);
angles_.setY(piClamp<GLfloat>(atan2f(tv.length(), dv.z()) * rad2deg, angle_limit_lower_xy, angle_limit_upper_xy) + 180.f);
}
void Camera::apply(const GLfloat & aspect) {
glMatrixMode(GL_PROJECTION);
if (aspect <= 1.f)
glScalef(aspect, aspect, 1.f);
QMatrix4x4 pm = glMatrixPerspective(fov_, aspect, depth_start, depth_end);
//pm.perspective(fov_, aspect, depth_start, depth_end);
//qDebug() << pm;// << glMatrixPerspective(fov_, aspect, depth_start, depth_end);
//qDebug() << pm;
//setGLMatrix(pm);
glMatrixMode(GL_MODELVIEW);
pm.setToIdentity();
pm.translate(0., 0., -distance());
pm.rotate(angles_.y(), 1., 0., 0.);
pm.rotate(angles_.x(), 0., 1., 0.);
pm.rotate(angles_.z(), 0., 0., 1.);
//pm.translate(-aim_);
if (parent_) {
QMatrix4x4 pmat = parent_->worldTransform();
offset_ = pmat.column(3).toVector3D();
pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.;
pmat.translate(aim_);
pm *= pmat.inverted();
//qDebug() << pmat;
}
//setGLMatrix(pm);
//qDebug() << angles_;
}
QMatrix4x4 Camera::offsetMatrix() const {
QMatrix4x4 ret;
ret.translate(parent_ ? -offset_ : -aim_);
return ret;
}
/*
void Camera::localTransform(QMatrix4x4 & m) {
return;
if (parent_)
m *= parent_->worldTransform();
QMatrix4x4 ret;
//qDebug() << "local camera";
ret.translate(0., 0., -distance());
ret.rotate(angles_.y(), 1., 0., 0.);
ret.rotate(angles_.x(), 0., 1., 0.);
ret.rotate(angles_.z(), 0., 0., 1.);
//m *= ret.inverted();
}
*/
void Camera::assign(const Camera & c) {
pos_ = c.pos_;
aim_ = c.aim_;
fov_ = c.fov_;
angles_ = c.angles_;
angle_limit_lower_xy = c.angle_limit_lower_xy;
angle_limit_upper_xy = c.angle_limit_upper_xy;
mirror_x = c.mirror_x;
mirror_y = c.mirror_y;
depth_start = c.depth_start;
depth_end = c.depth_end;
buildTransform();
}
ObjectBase * Camera::clone(bool withChildren) {
Camera * o = new Camera(*this);
//GLObjectBase::clone(withChildren);
o->is_init = false;
o->name_ = name_;// + "_copy";
o->scene_ = nullptr;
o->children_.clear();
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
o->pos_ = pos_;
o->aim_ = aim_;
o->fov_ = fov_;
o->angles_ = angles_;
o->angle_limit_lower_xy = angle_limit_lower_xy;
o->angle_limit_upper_xy = angle_limit_upper_xy;
o->mirror_x = mirror_x;
o->mirror_y = mirror_y;
o->depth_start = depth_start;
o->depth_end = depth_end;
o->meta = meta;
return o;
}
QMatrix4x4 Camera::viewMatrix() const {
QMatrix4x4 ret;
ret.translate(0., 0., -distance());
ret.rotate(angles_.y(), 1., 0., 0.);
ret.rotate(angles_.x(), 0., 1., 0.);
ret.rotate(angles_.z(), 0., 0., 1.);
//pm.translate(-aim_);
if (parent_) {
QMatrix4x4 pmat = parent_->worldTransform();
offset_ = pmat.column(3).toVector3D();
pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.;
pmat.translate(aim_);
ret *= pmat.inverted();
}
return ret;
}
QMatrix4x4 Camera::projectionMatrix(double aspect) const {
return glMatrixPerspective(fov_, aspect, depth_start, depth_end);
}
void Camera::panZ(const float & a) {
QVector3D dv = aim_ - pos_;
float tl = QVector2D(dv.x(), dv.y()).length();
angles_.setZ(angles_.z() + a);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tl, cosf(angles_.z() * deg2rad) * tl, dv.z());
aim_ = pos_ + dv;
buildTransform();
}
void Camera::panXY(const float & a) {
QVector3D dv = aim_ - pos_;
float tl = dv.length(), tc;
angles_.setY(angles_.y() + a);
angles_.setY(piClamp<GLfloat>(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy));
tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad));
aim_ = pos_ + dv * tl;
buildTransform();
}
void Camera::rotateZ(const float & a) {
QVector3D dv = aim_ - pos_;
float tl = QVector2D(dv.x(), dv.y()).length();
angles_.setZ(angles_.z() + a);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tl, cosf(angles_.z() * deg2rad) * tl, dv.z());
aim_ = pos_ + dv;
buildTransform();
}
void Camera::rotateXY(const float & a) {
QVector3D dv = aim_ - pos_;
float tl = dv.length(), tc;
angles_.setY(angles_.y() + a);
angles_.setY(piClamp<GLfloat>(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy));
tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad));
aim_ = pos_ + dv * tl;
buildTransform();
}
void Camera::orbitZ(const float & a) {
QVector3D dv = aim_ - pos_;
float tl = QVector2D(dv.x(), dv.y()).length();
angles_.setZ(angles_.z() + a);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tl, cosf(angles_.z() * deg2rad) * tl, dv.z());
pos_ = aim_ - dv;
buildTransform();
}
void Camera::orbitXY(const float & a) {
QVector3D dv = aim_ - pos_;
float tl = dv.length(), tc;
angles_.setY(angles_.y() + a);
angles_.setY(piClamp<GLfloat>(angles_.y(), angle_limit_lower_xy, angle_limit_upper_xy));
tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad));
pos_ = aim_ - dv * tl;
buildTransform();
}
void Camera::setAngleZ(const float & a) {
QVector3D dv = aim_ - pos_;
float tl = QVector2D(dv.x(), dv.y()).length();
angles_.setZ(a);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tl, cosf(angles_.z() * deg2rad) * tl, dv.z());
aim_ = pos_ + dv;
buildTransform();
}
void Camera::setAngleXY(const float & a) {
QVector3D dv = aim_ - pos_;
float tl = dv.length(), tc;
angles_.setY(a);
tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad));
//pos_ = aim_ - dv;
aim_ = pos_ + dv * tl;
buildTransform();
//anglesFromPoints();
}
void Camera::moveForward(const float & x, bool withZ) {
QVector3D dv;// = aim_ - pos_;
float tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, 0.);
if (withZ) dv.setZ(-cosf(angles_.y() * deg2rad));
dv.normalize();
dv *= x;
pos_ += dv;
aim_ += dv;
buildTransform();
}
void Camera::moveLeft(const float & x, bool withZ) {
QVector3D dv;// = aim_ - pos_;
float tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad - float(M_PI_2)) * tc, cosf(angles_.z() * deg2rad - float(M_PI_2)) * tc, 0.f);
if (withZ) dv.setZ(-sinf(angles_.x() * deg2rad));
dv.normalize();
dv *= x;
pos_ += dv;
aim_ += dv;
buildTransform();
}
void Camera::moveUp(const float & x, bool onlyZ) {
QVector3D dv;
if (onlyZ)
dv = QVector3D(0., 0., x);
else {
float tc = cosf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -sinf(angles_.y() * deg2rad));
dv.normalize();
dv *= x;
}
pos_ += dv;
aim_ += dv;
buildTransform();
}
void Camera::flyCloser(const float & s) {
QVector3D dv = aim_ - pos_;
float tl = dv.length() / (1.f + s), tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad));
pos_ = aim_ - dv * tl;
buildTransform();
}
void Camera::flyFarer(const float & s) {
QVector3D dv = aim_ - pos_;
float tl = dv.length() * (1.f + s), tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad));
pos_ = aim_ - dv * tl;
buildTransform();
}
void Camera::flyToDistance(const float & d) {
QVector3D dv = aim_ - pos_;
float tc = -sinf(angles_.y() * deg2rad);
dv = QVector3D(sinf(angles_.z() * deg2rad) * tc, cosf(angles_.z() * deg2rad) * tc, -cosf(angles_.y() * deg2rad));
pos_ = aim_ - dv * d;
buildTransform();
}

107
qglengine/glcamera.h Normal file
View File

@@ -0,0 +1,107 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLCAMERA_H
#define GLCAMERA_H
#include "globject.h"
//extern QMatrix4x4 globCameraMatrix;
//extern Camera * currentCamera;
class Camera: public ObjectBase
{
friend class QGLView;
friend class GLParticlesSystem;
friend QDataStream & operator <<(QDataStream & s, const ObjectBase * p);
friend QDataStream & operator >>(QDataStream & s, ObjectBase *& p);
public:
Camera();
void setPos(const QVector3D & p) {pos_ = p; anglesFromPoints(); buildTransform();}
void setAim(const QVector3D & p) {aim_ = p; anglesFromPoints(); buildTransform();}
void move(const QVector3D & p) {pos_ += p; aim_ += p; buildTransform();}
void move(const float & x, const float & y = 0., const float & z = 0.) {pos_ += QVector3D(x, y, z); aim_ += QVector3D(x, y, z); buildTransform();}
void moveForward(const float & x, bool withZ = true);
void moveBackward(const float & x, bool withZ = true) {moveForward(-x, withZ);}
void moveLeft(const float & x, bool withZ = true);
void moveRight(const float & x, bool withZ = true) {moveLeft(-x, withZ);}
void moveUp(const float & x, bool onlyZ = false);
void moveDown(const float & x, bool onlyZ = false) {moveUp(-x, onlyZ);}
void rotateZ(const float & a);
void rotateXY(const float & a);
void rotateRoll(const float & a) {angles_.setX(angles_.x() + a); buildTransform();}
void orbitZ(const float & a);
void orbitXY(const float & a);
void panZ(const float & a);
void panXY(const float & a);
void setFOV(const float & f) {fov_ = f;}
void setAngles(const QVector3D & a) {setRotation(a);}
void setAngleZ(const float & a);
void setAngleXY(const float & a);
void setAngleRoll(const float & a) {angles_.setX(a); buildTransform();}
void setAngleLowerLimitXY(const float & a) {angle_limit_lower_xy = a; buildTransform();}
void setAngleUpperLimitXY(const float & a) {angle_limit_upper_xy = a; buildTransform();}
void setAngleLimitsXY(const float & lower, const float & upper) {angle_limit_lower_xy = lower; angle_limit_upper_xy = upper; buildTransform();}
void setDepthStart(const float & d) {depth_start = d;}
void setDepthEnd(const float & d) {depth_end = d;}
void setMirrorX(bool yes) {mirror_x = yes;}
void setMirrorY(bool yes) {mirror_y = yes;}
void flyCloser(const float & s);
void flyFarer(const float & s);
void flyToDistance(const float & d);
QVector3D aim() const {return aim_;}
QVector3D angles() const {return rotation();}
QVector3D direction() const {return (aim_ - pos_).normalized();}
QVector3D directionXY() const {QVector3D tv = aim_ - pos_; return QVector3D(tv.x(), tv.y(), 0.).normalized();}
float FOV() const {return fov_;}
float distance() const {return (pos_ - aim_).length();}
float angleZ() const {return angles_.z();}
float angleXY() const {return angles_.y();}
float angleRoll() const {return angles_.x();}
float angleLowerLimitXY() const {return angle_limit_lower_xy;}
float angleUpperLimitXY() const {return angle_limit_upper_xy;}
float depthStart() const {return depth_start;}
float depthEnd() const {return depth_end;}
bool isMirrorX() const {return mirror_x;}
bool isMirrorY() const {return mirror_y;}
void anglesFromPoints();
void apply(const GLfloat & aspect = 1.);
void assign(const Camera & c);
virtual ObjectBase * clone(bool withChildren = true);
QMatrix4x4 viewMatrix() const;
QMatrix4x4 projectionMatrix(double aspect) const;
QMatrix4x4 offsetMatrix() const;
private:
QVector3D aim_;
mutable QVector3D offset_;
GLfloat fov_;
GLfloat depth_start;
GLfloat depth_end;
GLfloat angle_limit_lower_xy;
GLfloat angle_limit_upper_xy;
bool mirror_x;
bool mirror_y;
};
#endif // GLCAMERA_H

295
qglengine/glframebuffer.cpp Normal file
View File

@@ -0,0 +1,295 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QOpenGLExtraFunctions>
#include "glframebuffer.h"
#include <QTime>
Framebuffer::Framebuffer(QOpenGLExtraFunctions * f_, int colorAttachments_, bool withDepth, GLenum colorFormat_, GLenum _target): f(f_),
pbo(GL_PIXEL_PACK_BUFFER, GL_STREAM_DRAW) {
is_depth = withDepth;
color_format = colorFormat_;
target_ = _target;
colors.fill(0, colorAttachments_);
fbo = drbo = 0;
tex_d = 0;
wid = hei = 0;
pbo_queried = 0;
is_changed = false;
}
Framebuffer::~Framebuffer() {
deleteGLFramebuffer(fbo);
deleteGLRenderbuffer(drbo);
for (int i = 0; i < colors.size(); ++i)
deleteGLTexture(f, colors[i]);
deleteGLTexture(f, tex_d);
}
void Framebuffer::resize(int width, int height, bool force) {
if ((wid == width) && (hei == height) && !force) return;
wid = width;
hei = height;
deleteGLFramebuffer(fbo);
f->glGenFramebuffers(1, &fbo);
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
for (int i = 0; i < colors.size(); ++i) {
deleteGLTexture(f, colors[i]);
createGLTexture(f, colors[i], width, height, color_format, target_);
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
f->glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, 4);
//f->glTexParameteri(target_, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, target_, colors[i], 0);
}
if (is_depth) {
deleteGLTexture(f, tex_d);
deleteGLRenderbuffer(drbo);
f->glGenRenderbuffers(1, &drbo);
f->glBindRenderbuffer(GL_RENDERBUFFER, drbo);
f->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, drbo);
createGLTexture(f, tex_d, width, height, GL_DEPTH_COMPONENT);
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//f->glTexParameteri(target_, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target_, tex_d, 0);
}
f->glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (pbo.isInit()) {
pbo.bind(f);
pbo.resize(f, width*height*4);
pbo.release(f);
}
is_changed = false;
}
QImage Framebuffer::grab() const {
//glReadPixels(0, 0, wid, hei, GL_RGBA, );
//QImage ret();
return QImage();
}
void Framebuffer::queryPoint(int index, QPoint p) {
pbo_queried = 0;
if (index < 0 || index >= colors.size()) return;
if (!rect().contains(p) || !pbo.isInit()) return;
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index);
//QTime tm; tm.restart();
pbo.bind(f);
f->glReadPixels(p.x(), height() - p.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 0);
pbo_queried = 1;
pbo.release(f);
//qDebug() << tm.elapsed();
}
void Framebuffer::queryPoints(int index, QRect rect_) {
pbo_queried = 0;
if (index < 0 || index >= colors.size()) return;
rect_ &= rect();
if (rect_.isEmpty() || !pbo.isInit()) return;
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index);
//QTime tm; tm.restart();
pbo.bind(f);
f->glReadPixels(rect_.x(), height() - rect_.bottom(), rect_.width(), rect_.height(), GL_RGBA, GL_UNSIGNED_BYTE, 0);
pbo_queried = rect_.width() * rect_.height();
pbo.release(f);
//qDebug() << tm.elapsed();
}
void Framebuffer::queryImage(int index) {
queryPoints(index, rect());
}
uint Framebuffer::getPoint() const {
if (!pbo.isInit() || (pbo_queried == 0)) return 0;
//QTime tm; tm.restart();
uint ret = 0;
pbo.bind(f);
//glClearError();
void * map = pbo.map(f, GL_MAP_READ_BIT, sizeof(uint));
//qDebug() << map << QString::number(glGetError(), 16);
if (map)
memcpy(&ret, map, sizeof(uint));
pbo.unmap(f);
pbo.release(f);
//qDebug() << tm.elapsed();
return ret;
}
QVector<uint> Framebuffer::getPoints() const {
QVector<uint> ret;
if (!pbo.isInit() || (pbo_queried == 0)) return ret;
ret.resize(pbo_queried);
//QTime tm; tm.restart();
pbo.bind(f);
//glClearError();
void * map = pbo.map(f, GL_MAP_READ_BIT, pbo_queried * sizeof(uint));
//qDebug() << map << QString::number(glGetError(), 16);
if (map)
memcpy(ret.data(), map, pbo_queried * sizeof(uint));
pbo.unmap(f);
pbo.release(f);
//qDebug() << tm.elapsed();
return ret;
}
QImage Framebuffer::getImage() const {
QImage ret;
if (!pbo.isInit() || (pbo_queried == 0)) return ret;
ret = QImage(size(), QImage::Format_RGBA8888);
int bytes = width() * height() * 4;
//QTime tm; tm.restart();
pbo.bind(f);
//glClearError();
void * map = pbo.map(f, GL_MAP_READ_BIT, bytes);
//qDebug() << map << QString::number(glGetError(), 16);
if (map)
memcpy(ret.bits(), map, bytes);
pbo.unmap(f);
pbo.release(f);
//qDebug() << tm.elapsed();
return ret;
}
QVector<float> Framebuffer::grabF(int index) const {
QVector<float> ret;
if (index < 0 || index >= colors.size()) return ret;
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index);
ret.resize(wid * hei * 4);
f->glReadPixels(0, 0, wid, hei, GL_RGBA, GL_FLOAT, ret.data());
return ret;
}
void Framebuffer::blit(int index_from, GLuint fb_to, int index_to, QRect from, QRect to, GLbitfield mask, GLenum filter) {
if (index_from < 0 || index_from >= colors.size()) return;
GLenum e = GL_COLOR_ATTACHMENT0 + index_to;
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_to);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index_from);
f->glDrawBuffers(1, &e);
f->glBlitFramebuffer(from.x(), from.y(), from.right(), from.bottom(), to.x(), to.y(), to.right(), to.bottom(), mask, filter);
}
void Framebuffer::bind() {
if (is_changed) resize(wid, hei);
if (fbo == 0) return;
//glFlush();
f->glGetIntegerv(GL_VIEWPORT, prev_view);
//glClearError();
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//qDebug() << QString::number(glGetError(), 16);
setWriteBuffers();
f->glReadBuffer(GL_COLOR_ATTACHMENT0);
//f->glDrawBuffer(GL_COLOR_ATTACHMENT0);
f->glViewport(0, 0, wid, hei);
}
void Framebuffer::release() {
is_changed = false;
if (fbo == 0) return;
//glFlush();
f->glBindFramebuffer(GL_FRAMEBUFFER, 0);
f->glViewport(prev_view[0], prev_view[1], prev_view[2], prev_view[3]);
}
void Framebuffer::setWriteBuffer(int index) {
//QVector<GLenum> buffers; buffers << GL_COLOR_ATTACHMENT0 + index;
GLenum e = GL_COLOR_ATTACHMENT0 + index;
f->glDrawBuffers(1, &e);
}
void Framebuffer::setWriteBuffers(int * indeces, int count) {
QVector<GLenum> buffers;
for (int i = 0; i < count; ++i)
buffers << GL_COLOR_ATTACHMENT0 + indeces[i];
f->glDrawBuffers(buffers.size(), buffers.constData());
}
void Framebuffer::setWriteBuffers() {
QVector<GLenum> buffers;
for (int i = 0; i < colors.size(); ++i)
buffers << GL_COLOR_ATTACHMENT0 + i;
f->glDrawBuffers(buffers.size(), buffers.constData());
}
void Framebuffer::enablePixelBuffer() {
pbo.init(f);
}
void Framebuffer::bindColorTexture(int index, int channel) {
if (index < 0 || index >= colors.size()) return;
f->glActiveTexture(GL_TEXTURE0 + channel);
f->glBindTexture(GL_TEXTURE_2D, colors[index]);
}
void Framebuffer::bindColorTextures() {
for (int i = colors.size() - 1; i >= 0; --i) {
f->glActiveTexture(GL_TEXTURE0 + i);
f->glBindTexture(GL_TEXTURE_2D, colors[i]);
//f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
}
void Framebuffer::bindDepthTexture(int channel) {
f->glActiveTexture(GL_TEXTURE0 + channel);
f->glBindTexture(GL_TEXTURE_2D, tex_d);
}
void Framebuffer::deleteGLRenderbuffer(GLuint & drbo) {
if (drbo != 0)
f->glDeleteRenderbuffers(1, &drbo);
drbo = 0;
}
void Framebuffer::deleteGLFramebuffer(GLuint & fbo) {
if (fbo != 0)
f->glDeleteFramebuffers(1, &fbo);
fbo = 0;
}

81
qglengine/glframebuffer.h Normal file
View File

@@ -0,0 +1,81 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLFRAMEBUFFER_H
#define GLFRAMEBUFFER_H
#include "glbuffer.h"
class Framebuffer
{
public:
Framebuffer(QOpenGLExtraFunctions * f_, int colorAttachments = 1, bool withDepth = true, GLenum colorFormat = GL_RGBA8, GLenum _target = GL_TEXTURE_2D);
virtual ~Framebuffer();
GLuint id() const {return fbo;}
GLuint colorTexture(int index = 0) const {return colors[index];}
GLenum colorFormat() const {return color_format;}
GLuint depthTexture() const {return tex_d;}
GLenum target() const {return target_;}
int width() const {return wid;}
int height() const {return hei;}
QSize size() const {return QSize(wid, hei);}
QRect rect() const {return QRect(0, 0, wid, hei);}
QImage grab() const;
QVector<float> grabF(int index) const;
void queryPoint(int index, QPoint p);
void queryPoints(int index, QRect rect);
void queryImage(int index);
uint getPoint() const;
QVector<uint> getPoints() const;
QImage getImage() const;
int queriedPoints() const {return pbo_queried;}
void blit(int index_from, GLuint fb_to, int index_to, QRect from, QRect to, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_NEAREST );
void resize(int width, int height, bool force = false);
void bind();
void release();
void setReadBuffer(int index) {glReadBuffer(GL_COLOR_ATTACHMENT0 + index);}
void setWriteBuffer(int index);
void setWriteBuffers(int * indeces, int count);
void setWriteBuffers();
void setColorFormat(GLenum format) {color_format = format; is_changed = true;}
void enablePixelBuffer();
void copyDepthFrom(GLuint tex) {;}
void bindColorTexture(int index, int channel = 0);
void bindColorTextures();
void bindDepthTexture(int channel);
private:
void deleteGLRenderbuffer(GLuint & drbo);
void deleteGLFramebuffer(GLuint & fbo);
bool is_depth, is_changed;
int pbo_queried;
QOpenGLExtraFunctions * f;
mutable Buffer pbo;
QVector<GLuint> colors;
GLenum color_format, target_;
GLuint fbo, drbo, tex_d;
GLint prev_view[4], wid, hei;
};
#endif // GLFRAMEBUFFER_H

200
qglengine/glmaterial.cpp Normal file
View File

@@ -0,0 +1,200 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gltypes.h"
#include "gltexture_manager.h"
#include "qglview.h"
using namespace QGLEngineShaders;
/*
bool CubeTexture::create() {
//qDebug("create");
destroy();
glGenTextures(1, &id_);
glBindTexture(GL_TEXTURE_CUBE_MAP, id_);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
//glClearError();
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
//qDebug() << glGetError();
changed_ = false;
return id_ > 0;
}
void CubeTexture::load() {
if (isEmpty()) return;
create();
if (!path(0).isEmpty()) loadFront(path(0));
if (!path(1).isEmpty()) loadBack(path(1));
if (!path(2).isEmpty()) loadLeft(path(2));
if (!path(3).isEmpty()) loadRight(path(3));
if (!path(4).isEmpty()) loadTop(path(4));
if (!path(5).isEmpty()) loadBottom(path(5));
}
void CubeTexture::loadFromDirectory(const QString & dir) {
QDir d(dir); QFileInfoList sl;
sl = d.entryInfoList(QStringList("front.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadFront(sl[0].absoluteFilePath());
sl = d.entryInfoList(QStringList("back.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadBack(sl[0].absoluteFilePath());
sl = d.entryInfoList(QStringList("left.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadLeft(sl[0].absoluteFilePath());
sl = d.entryInfoList(QStringList("right.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadRight(sl[0].absoluteFilePath());
sl = d.entryInfoList(QStringList("top.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadTop(sl[0].absoluteFilePath());
sl = d.entryInfoList(QStringList("bottom.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadBottom(sl[0].absoluteFilePath());
}
void CubeTexture::loadPathesFromDirectory(const QString & dir) {
QDir d(dir); QFileInfoList sl;
sl = d.entryInfoList(QStringList("front.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[0] = sl[0].absoluteFilePath();
sl = d.entryInfoList(QStringList("back.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[1] = sl[0].absoluteFilePath();
sl = d.entryInfoList(QStringList("left.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[2] = sl[0].absoluteFilePath();
sl = d.entryInfoList(QStringList("right.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[3] = sl[0].absoluteFilePath();
sl = d.entryInfoList(QStringList("top.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[4] = sl[0].absoluteFilePath();
sl = d.entryInfoList(QStringList("bottom.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[5] = sl[0].absoluteFilePath();
}
*/
Map::Map() {
bitmap_id = 0;
color_amount = 1.f;
color_offset = 0.f;
bitmap_scale = QPointF(1., 1.);
_changed = true;
_layer = 0;
}
void Map::setBitmapPath(const QString & p) {
bitmap_path = p;
_changed = true;
}
void Map::load(TextureManager * tm) {
if (bitmap_id == 0)
bitmap_id = tm->loadTexture(bitmap_path, true, _type == mtNormal);
}
void Map::copyToQGLMap(QGLMap & m) const {
m.amount = color_amount;
m.offset = color_offset;
m.scale = QVector2D(bitmap_scale);
if (hasBitmap()) {
m.array_index = tarMaps;
m.map_index = _layer;
} else {
m.array_index = tarEmpty;
m.map_index = (_type == mtNormal ? emrBlue : emrWhite);
}
}
Material::Material(const QString _name)/*: map_reflection(512)*/ {
setTypes();
name = _name;
color_diffuse = color_specular = Qt::darkGray;
color_emission = Qt::black;
glass = false;
transparency = reflectivity = 0.f;
map_roughness.color_amount = 0.75f;
map_specular.color_amount = 1.f;
iof = 1.f;
dispersion = 0.05f;
_changed = true;
_index = 0;
}
uint Material::hash() {
return qHash(name);
}
bool Material::hasTransparency() const {
return float(color_diffuse.alphaF()) * (1.f - transparency) < 1.f;
}
bool Material::isMapsChanged() const {
return map_diffuse ._changed ||
map_normal ._changed ||
map_specular ._changed ||
map_roughness._changed ||
map_emission ._changed ||
map_relief ._changed;
}
bool Material::isMapChanged(int type) const {
switch (type) {
case mtDiffuse : return map_diffuse ._changed;
case mtNormal : return map_normal ._changed;
case mtSpecular : return map_specular ._changed;
case mtRoughness: return map_roughness._changed;
case mtEmission : return map_emission ._changed;
case mtRelief : return map_relief ._changed;
}
return false;
}
void Material::load(TextureManager * tm) {
map_diffuse .load(tm);
map_normal .load(tm);
map_specular .load(tm);
map_roughness.load(tm);
map_emission .load(tm);
map_relief .load(tm);
}
void Material::setMapsChanged() {
map_diffuse ._changed = true;
map_normal ._changed = true;
map_specular ._changed = true;
map_roughness._changed = true;
map_emission ._changed = true;
map_relief ._changed = true;
}
void Material::setTypes() {
map_diffuse ._type = mtDiffuse;
map_normal ._type = mtNormal;
map_specular ._type = mtSpecular;
map_roughness._type = mtRoughness;
map_emission ._type = mtEmission;
map_relief ._type = mtRelief;
}

173
qglengine/glmaterial.h Normal file
View File

@@ -0,0 +1,173 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLMATERIAL_H
#define GLMATERIAL_H
#include "glshaders_types.h"
#include "chunkstream.h"
/*
class Texture {
public:
Texture(int _width, int _height, const GLenum & _format = GL_RGBA8, const GLenum & _target = GL_TEXTURE_2D) {wid = _width; hei = _height; format_ = _format; target_ = _target; id_ = 0;}
bool create() {destroy(); createGLTexture(id_, wid, hei, format_, target_); return id_ > 0;}
void destroy() {if (id_ > 0) glDeleteTextures(1, &id_); id_ = 0;}
void bind() {if (id_ > 0) glBindTexture(target_, id_);}
void release() {glBindTexture(target_, 0);}
int width() const {return wid;}
int height() const {return hei;}
GLenum format() const {return format_;}
GLenum target() const {return target_;}
GLuint id() const {return id_;}
private:
int wid, hei;
GLenum format_, target_;
GLuint id_;
};
class CubeTexture {
public:
CubeTexture(int _size, const GLenum & _format = GL_RGBA8) {size = _size; format_ = _format; id_ = 0; changed_ = false; pathes.resize(6);}
bool create();
void destroy() {if (id_ > 0) glDeleteTextures(1, &id_); id_ = 0;}
void bind() {if (changed_) {changed_ = false; create();} if (id_ > 0) glBindTexture(GL_TEXTURE_CUBE_MAP, id_);}
void release() {glBindTexture(GL_TEXTURE_CUBE_MAP, 0);}
void resize(int _size) {size = _size; changed_ = true;}
void loadFromDirectory(const QString & dir);
void loadFront(const QString & path) {bind(); pathes[0] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_X);}
void loadBack(const QString & path) {bind(); pathes[1] = path; createGLTexture(id_, rotateQImageRight(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_X);}
void loadLeft(const QString & path) {bind(); pathes[2] = path; createGLTexture(id_, QImage(path).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);}
void loadRight(const QString & path) {bind(); pathes[3] = path; createGLTexture(id_, rotateQImage180(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_Y);}
void loadTop(const QString & path) {bind(); pathes[4] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);}
void loadBottom(const QString & path) {bind(); pathes[5] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_Z);}
void load();
bool isEmpty() const {foreach (const QString & i, pathes) if (!i.isEmpty()) return false; return true;}
GLenum format() const {return format_;}
void setFormat(GLenum f) {format_ = f; changed_ = true;}
GLuint id() const {return id_;}
const QString & path(int side) const {return pathes[side];}
void setPath(int side, const QString & p) {pathes[side] = p;}
void loadPathesFromDirectory(const QString & dir);
private:
bool changed_;
int size;
GLenum format_;
GLuint id_;
QVector<QString> pathes;
};
*/
class Map {
public:
Map();
void setBitmapPath(const QString & p);
void clearBitmap() {setBitmapPath(QString());}
bool hasBitmap() const {return !bitmap_path.isEmpty();}
void load(TextureManager * tm);
void copyToQGLMap(QGLEngineShaders::QGLMap & m) const;
QString bitmap_path;
GLuint bitmap_id;
QPointF bitmap_offset;
QPointF bitmap_scale;
float color_amount;
float color_offset;
bool _changed;
int _type, _layer;
};
class Material {
public:
Material(const QString _name = QString());
uint hash();
bool hasTransparency() const;
bool isMapsChanged() const;
bool isMapChanged(int type) const;
void load(TextureManager * tm);
void setMapsChanged();
void setTypes();
QString name;
QColor color_diffuse;
QColor color_specular;
QColor color_emission;
bool glass;
float transparency;
float reflectivity;
float iof;
float dispersion;
Map map_diffuse ;
Map map_normal ;
Map map_specular ;
Map map_roughness;
Map map_emission ;
Map map_relief ;
bool _changed;
int _index;
//GLCubeTexture map_reflection;
};
inline QDataStream & operator <<(QDataStream & s, const Map & m) {
ChunkStream cs;
cs.add(1, m.bitmap_path).add(2, m.color_amount).add(3, m.color_offset).add(6, m.bitmap_scale);
s << cs.data(); return s;
}
inline QDataStream & operator >>(QDataStream & s, Map & m) {
ChunkStream cs(s);
cs.readAll();
cs.get(1, m.bitmap_path).get(2, m.color_amount).get(3, m.color_offset).get(6, m.bitmap_scale);
return s;
}
inline QDataStream & operator <<(QDataStream & s, const Material * m) {
ChunkStream cs;
cs.add(1, m->name).add(2, m->color_diffuse).add(3, m->color_specular).add(4, m->color_emission)
.add(5, m->transparency).add(6, m->reflectivity).add(7, m->glass).add(8, m->map_diffuse).add(9, m->map_normal)
.add(10, m->map_relief).add(11, m->map_specular).add(12, m->map_roughness).add(13, m->map_emission);
s << /*qCompress*/(cs.data()); return s;
}
inline QDataStream & operator >>(QDataStream & s, Material *& m) {
m = new Material();
//QByteArray ba;
//s >> ba;
//ba = qUncompres(ba);
ChunkStream cs(s);
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: cs.get(m->name); break;
case 2: cs.get(m->color_diffuse); break;
case 3: cs.get(m->color_specular); break;
case 4: cs.get(m->color_emission); break;
case 5: cs.get(m->transparency); break;
case 6: cs.get(m->reflectivity); break;
case 7: cs.get(m->glass); break;
case 8: cs.get(m->map_diffuse); break;
case 9: cs.get(m->map_normal); break;
case 10: cs.get(m->map_relief); break;
case 11: cs.get(m->map_specular); break;
case 12: cs.get(m->map_roughness); break;
case 13: cs.get(m->map_emission); break;
}
}
m->setTypes();
return s;
}
#endif // GLMATERIAL_H

422
qglengine/glmesh.cpp Normal file
View File

@@ -0,0 +1,422 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "glmesh.h"
#include "globject.h"
#include <QTime>
using namespace QGLEngineShaders;
static int _count = 0;
Mesh::Mesh(): buffer_geom(GL_ARRAY_BUFFER, GL_STATIC_DRAW),
buffer_ind (GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW),
buffer_obj (GL_ARRAY_BUFFER, GL_STREAM_DRAW),
buffer_sel (GL_ARRAY_BUFFER, GL_STREAM_DRAW) {
vao = 0;
hash_ = 0;
changed = hash_changed = objects_changed = selected_changed = true;
//qDebug() << "Mesh, now" << ++_count;
}
Mesh::~Mesh() {
//qDebug() << "~Mesh, now" << --_count;
//destroy();
}
Mesh * Mesh::clone() {
Mesh * c = new Mesh();
c->vertices_ = vertices_ ;
c->normals_ = normals_ ;
c->texcoords_ = texcoords_;
c->triangles_ = triangles_;
c->hash_ = hash_;
c->hash_changed = hash_changed;
//qDebug() << "clone VBO";
return c;
}
void Mesh::init(QOpenGLExtraFunctions * f) {
if (!isInit()) {
buffer_geom.init(f);
buffer_ind .init(f);
buffer_obj .init(f);
buffer_sel .init(f);
f->glGenVertexArrays(1, &vao);
}
changed = true;
}
void Mesh::destroy(QOpenGLExtraFunctions * f) {
if (vao != 0) {
f->glDeleteVertexArrays(1, &vao);
buffer_geom.destroy(f);
buffer_ind .destroy(f);
buffer_obj .destroy(f);
buffer_sel .destroy(f);
}
vao = 0;
}
void Mesh::calculateNormals() {
normals_.resize(vertices_.size());
QVector3D dv1, dv2, n;
foreach (const Vector3i & t, triangles_) {
QVector3D & v0(vertices_[t.p0]);
QVector3D & v1(vertices_[t.p1]);
QVector3D & v2(vertices_[t.p2]);
dv1 = v1 - v0, dv2 = v2 - v0;
n = QVector3D::crossProduct(dv1, dv2).normalized();
normals_[t.p0] = n;
normals_[t.p1] = n;
normals_[t.p2] = n;
}
}
void Mesh::calculateTangents() {
if (vertices_.isEmpty() || texcoords_.isEmpty()) return;
if (texcoords_.size() != vertices_.size()) return;
tangents_ .resize(vertices_.size());
bitangents_.resize(vertices_.size());
//qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "...";
QVector3D dv1, dv2;
QVector2D dt1, dt2;
QVector3D tan, bitan;
foreach (const Vector3i & t, triangles_) {
QVector3D & v0(vertices_ [t.p0]);
QVector3D & v1(vertices_ [t.p1]);
QVector3D & v2(vertices_ [t.p2]);
QVector2D & t0(texcoords_[t.p0]);
QVector2D & t1(texcoords_[t.p1]);
QVector2D & t2(texcoords_[t.p2]);
dv1 = v1 - v0, dv2 = v2 - v0;
dt1 = t1 - t0, dt2 = t2 - t0;
tan = (dv1 * dt2.y() - dv2 * dt1.y()).normalized();
bitan = (dv2 * dt1.x() - dv1 * dt2.x()).normalized();
tangents_ [t.p0] = tan;
tangents_ [t.p1] = tan;
tangents_ [t.p2] = tan;
bitangents_[t.p0] = bitan;
bitangents_[t.p1] = bitan;
bitangents_[t.p2] = bitan;
//qDebug() << " t" << t << vi << ti << dv1.toQVector3D() << "...";
}
//qDebug() << "calculateBinormals" << vcnt << tcnt << tangents_.size();
}
void Mesh::loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size) {
if (!isInit()) init(f);
if (!buf.isInit() || !data) return;
buf.bind(f);
buf.resize(f, size);
buf.load(f, data, size);
//qDebug() << "loadBuffer" << size << "bytes";
/*void * map = buf.map(f, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
qDebug() << map;
if (map)
memcpy(map, objects_.constData(), osize);
buf.unmap(f);*/
}
bool Mesh::rebuffer(QOpenGLExtraFunctions * f) {
changed = false;
if (vertices_.isEmpty()) return true;
if (normals_.isEmpty())
calculateNormals();
calculateTangents();
vert_count = qMin(vertices_.size(), normals_.size());
vert_count = qMin(vert_count, tangents_.size());
vert_count = qMin(vert_count, bitangents_.size());
vert_count = qMin(vert_count, texcoords_.size());
data_.resize(vert_count);
for (int i = 0; i < vert_count; ++i) {
Vertex & v(data_[i]);
v.pos = vertices_ [i];
v.normal = normals_ [i];
v.tangent = tangents_ [i];
v.bitangent = bitangents_[i];
v.tex = texcoords_ [i];
}
int gsize = data_.size() * sizeof(Vertex);
int isize = triangles_.size() * sizeof(Vector3i);
f->glBindVertexArray(vao);
buffer_geom.bind(f);
buffer_geom.resize(f, gsize);
buffer_geom.load(f, data_.constData(), gsize);
prepareDrawGeom(f);
buffer_ind.bind(f);
buffer_ind.resize(f, isize);
buffer_ind.load(f, triangles_.constData(), isize);
buffer_obj.bind(f);
prepareDrawObj(f);
buffer_sel.bind(f);
prepareDrawSel(f);
f->glBindVertexArray(0);
return !isEmpty();
}
void Mesh::prepareDrawGeom(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawGeom";
f->glEnableVertexAttribArray(pos_loc );
f->glEnableVertexAttribArray(normal_loc );
f->glEnableVertexAttribArray(tangent_loc );
f->glEnableVertexAttribArray(bitangent_loc);
f->glEnableVertexAttribArray(tex_loc );
int size = sizeof(Vertex);
f->glVertexAttribPointer(pos_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)pos_offset );
f->glVertexAttribPointer(normal_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)normal_offset );
f->glVertexAttribPointer(tangent_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)tangent_offset );
f->glVertexAttribPointer(bitangent_loc, 3, GL_FLOAT, GL_FALSE, size, (const void *)bitangent_offset);
f->glVertexAttribPointer(tex_loc , 2, GL_FLOAT, GL_FALSE, size, (const void *)tex_offset );
}
void Mesh::prepareDrawObj(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawObj";
f->glEnableVertexAttribArray(material_loc );
f->glEnableVertexAttribArray(object_id_loc);
f->glEnableVertexAttribArray(color_loc );
for (int i = 0; i < 4; ++i) {
f->glEnableVertexAttribArray(modelmatrix_loc + i);
}
GLsizei size = sizeof(Object);
f->glVertexAttribIPointer(material_loc , 1, GL_UNSIGNED_INT , size, (const void *)material_offset );
f->glVertexAttribIPointer(object_id_loc, 1, GL_UNSIGNED_INT , size, (const void *)object_id_offset);
f->glVertexAttribPointer (color_loc , 4, GL_FLOAT, GL_FALSE, size, (const void *)color_offset );
for (int i = 0; i < 4; ++i) {
f->glVertexAttribPointer(modelmatrix_loc + i, 4, GL_FLOAT, GL_FALSE, size, (const void *)(modelmatrix_offset + sizeof(QVector4D)*i));
}
f->glVertexAttribDivisor(material_loc , 1);
f->glVertexAttribDivisor(object_id_loc, 1);
f->glVertexAttribDivisor(color_loc , 1);
for (int i = 0; i < 4; ++i) {
f->glVertexAttribDivisor(modelmatrix_loc + i, 1);
}
}
void Mesh::prepareDrawSel(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawObj";
f->glEnableVertexAttribArray(is_selected_loc);
GLsizei size = 1;
f->glVertexAttribIPointer(is_selected_loc, 1, GL_UNSIGNED_BYTE, size, (const void *)is_selected_offset);
f->glVertexAttribDivisor(is_selected_loc, 1);
}
void Mesh::draw(QOpenGLExtraFunctions * f, int count) {
if (isEmpty()) return;
if (!isInit()) init(f);
if (changed) rebuffer(f);
//qDebug() << "draw" << vert_count << count;
f->glBindVertexArray(vao);
f->glDrawElementsInstanced(GL_TRIANGLES, triangles_.size() * 3, GL_UNSIGNED_INT, 0, count);
f->glBindVertexArray(0);
}
void Mesh::clear() {
vertices_.clear();
normals_.clear();
tangents_.clear();
bitangents_.clear();
texcoords_.clear();
triangles_.clear();
data_.clear();
changed = hash_changed = true;
}
void Mesh::loadObject(QOpenGLExtraFunctions * f, const Object & object) {
loadBuffer(f, buffer_obj, &object, sizeof(Object));
}
void Mesh::loadObjects(QOpenGLExtraFunctions * f, const QVector<Object> & objects) {
loadBuffer(f, buffer_obj, objects.constData(), objects.size() * sizeof(Object));
}
void Mesh::loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels) {
//qDebug() << "loadSelections" << sels;
loadBuffer(f, buffer_sel, sels.constData(), sels.size());
}
uint Mesh::hash() const {
if (hash_changed) {
hash_changed = false;
hash_ = qHashBits(vertices_ .constData(), vertices_ .size() * sizeof(QVector3D));
hash_ ^= qHashBits(normals_ .constData(), normals_ .size() * sizeof(QVector3D));
hash_ ^= qHashBits(texcoords_.constData(), texcoords_.size() * sizeof(QVector2D));
hash_ ^= qHashBits(triangles_.constData(), triangles_.size() * sizeof( Vector3i));
}
return hash_;
}
void Mesh::translatePoints(const QVector3D & dp) {
if (vertices_.isEmpty()) return;
int vcnt = vertices_.size();
for (int i = 0; i < vcnt; ++i) {
vertices_[i] += dp;
}
changed = hash_changed = true;
}
void Mesh::scalePoints(const QVector3D & dp) {
if (vertices_.isEmpty()) return;
int vcnt = vertices_.size();
for (int i = 0; i < vcnt; ++i) {
vertices_[i] *= dp;
}
changed = hash_changed = true;
}
void Mesh::append(const Mesh * m) {
if (!m) return;
if (m->isEmpty()) return;
if (normals_.isEmpty()) calculateNormals();
int vcnt = vertices_.size();
vertices_ .append(m->vertices_ );
normals_ .append(m->normals_ );
texcoords_.append(m->texcoords_);
QVector<Vector3i> tri = m->triangles_;
for (int i = 0; i < tri.size(); ++i)
tri[i] += vcnt;
triangles_.append(tri);
}
bool Mesh::saveToFile(const QString & filename) {
if (filename.isEmpty()) return false;
QFile f(filename);
QByteArray ba;
if (f.open(QFile::WriteOnly)) {
QDataStream out(&ba, QFile::WriteOnly);
out << vertices_ << normals_ << texcoords_ << triangles_;
ba = qCompress(ba);
f.resize(0);
f.write(ba);
f.close();
return true;
}
return false;
}
bool Mesh::loadFromFile(const QString & filename) {
if (filename.isEmpty()) return false;
QFile f(filename);
QByteArray ba;
if (f.open(QFile::ReadOnly)) {
ba = f.readAll();
if (ba.isEmpty()) return false;
ba = qUncompress(ba);
QDataStream in(ba);
in >> vertices_ >> normals_ >> texcoords_ >> triangles_;
changed = hash_changed = true;
f.close();
return !isEmpty();
}
return false;
}
Box3D Mesh::boundingBox() const {
if (vertices_.isEmpty()) return Box3D();
int vcnt = vertices_.size();
//qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "...";
GLfloat mix, miy, miz, max, may, maz;
QVector3D v0(vertices_[0]);
mix = max = v0.x();
miy = may = v0.y();
miz = maz = v0.z();
Box3D bound;
for (int i = 1; i < vcnt; ++i) {
const QVector3D & v(vertices_[i]);
if (mix > v.x()) mix = v.x();
if (max < v.x()) max = v.x();
if (miy > v.y()) miy = v.y();
if (may < v.y()) may = v.y();
if (miz > v.z()) miz = v.z();
if (maz < v.z()) maz = v.z();
}
bound.x = mix;
bound.y = miy;
bound.z = miz;
bound.length = max - mix;
bound.width = may - miy;
bound.height = maz - miz;
return bound;
}
QDataStream & operator <<(QDataStream & s, const Mesh * m) {
ChunkStream cs;
//qDebug() << "place VBO" << m.vertices_.size() << m.normals_.size() << m.texcoords_.size() << m.colors_.size() << "...";
cs.add(1, m->vertices_).add(2, m->normals_).add(3, m->texcoords_).add(6, m->triangles_);
//qDebug() << "place VBO done" << cs.data().size() << "...";
s << /*qCompress*/(cs.data()); return s;
}
QDataStream & operator >>(QDataStream & s, Mesh *& m) {
m = new Mesh();
//QByteArray ba;
//s >> ba;
//ba = qUncompress(ba);
ChunkStream cs(s);
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: cs.get(m->vertices_ ); break;
case 2: cs.get(m->normals_ ); break;
case 3: cs.get(m->texcoords_); break;
case 6: cs.get(m->triangles_); break;
}
}
m->changed = true;
return s;
}

98
qglengine/glmesh.h Normal file
View File

@@ -0,0 +1,98 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLMESH_H
#define GLMESH_H
#include <chunkstream.h>
#include "glbuffer.h"
#include "glshaders_types.h"
class Mesh
{
friend class ObjectBase;
friend class Scene;
friend class Renderer;
friend QDataStream & operator <<(QDataStream & s, const Mesh * m);
friend QDataStream & operator >>(QDataStream & s, Mesh *& m);
public:
Mesh();
~Mesh();
Mesh * clone();
//GLVBO & operator =(const GLVBO & o) {return *this;}
void init (QOpenGLExtraFunctions * f);
void destroy (QOpenGLExtraFunctions * f);
bool rebuffer(QOpenGLExtraFunctions * f);
void draw (QOpenGLExtraFunctions * f, int count);
void clear();
void loadObject (QOpenGLExtraFunctions * f, const QGLEngineShaders::Object & object);
void loadObjects (QOpenGLExtraFunctions * f, const QVector<QGLEngineShaders::Object> & objects);
void loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels);
int verticesCount() const {return vertices_.size();}
int trianglesCount() const {return triangles_.size();}
bool isInit() const {return vao != 0;}
bool isEmpty() const {return vertices_.isEmpty();}
uint hash() const;
QVector<QVector3D> & vertices () {changed = hash_changed = true; return vertices_;}
QVector<QVector3D> & normals () {changed = hash_changed = true; return normals_;}
QVector<QVector2D> & texcoords() {changed = hash_changed = true; return texcoords_;}
QVector< Vector3i> & indices () {changed = hash_changed = true; return triangles_;}
void translatePoints(const QVector3D & dp);
void scalePoints (const QVector3D & dp);
void append(const Mesh * m);
bool saveToFile(const QString & filename);
bool loadFromFile(const QString & filename);
Box3D boundingBox() const;
static void prepareDrawGeom(QOpenGLExtraFunctions * f);
static void prepareDrawObj (QOpenGLExtraFunctions * f);
static void prepareDrawSel (QOpenGLExtraFunctions * f);
private:
void calculateNormals();
void calculateTangents();
void loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size);
QVector<QVector3D> vertices_, normals_, tangents_, bitangents_;
QVector<QVector2D> texcoords_;
QVector< Vector3i> triangles_;
QVector<QGLEngineShaders::Vertex> data_;
GLenum vao;
Buffer buffer_geom, buffer_ind, buffer_obj, buffer_sel;
mutable uint hash_;
mutable bool hash_changed;
int vert_count;
bool changed, objects_changed, selected_changed;
};
QDataStream & operator <<(QDataStream & s, const Mesh * m);
QDataStream & operator >>(QDataStream & s, Mesh *& m);
#endif // GLMESH_H

624
qglengine/globject.cpp Normal file
View File

@@ -0,0 +1,624 @@
/*
GLObjectBase & Light
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "globject.h"
#include "glcamera.h"
#include "glscene.h"
#include "glmesh.h"
#include <chunkstream.h>
static int _count = 0;
ObjectBase::ObjectBase(Mesh * geom, Material * mat) {
type_ = glMesh;
render_mode = View;
pass_ = Solid;
scale_ = QVector3D(1., 1., 1.);
parent_ = nullptr;
color_ = Qt::white;
is_root = is_init = is_tex_loaded = selected_ = false;
visible_ = accept_fog = accept_light = cast_shadow = rec_shadow = select_ = true;
line_width = -1.;
id_ = 0;
blend_src = GL_SRC_ALPHA;
blend_dest = GL_ONE_MINUS_SRC_ALPHA;
type_ = glMesh;
raw_matrix = false;
mat_.setToIdentity();
scene_ = nullptr;
mesh_ = geom;
material_ = mat;
//qDebug() << "ObjectBase, now" << ++_count;
}
ObjectBase::~ObjectBase() {
//qDebug() << "~ObjectBase, now" << --_count;
if (parent_) parent_->children_.removeAll(this);
if (scene_) {
scene_->__objectDeleted(this);
scene_->setTreeChanged();
}
foreach (ObjectBase * c, children_) {
c->parent_ = nullptr;
delete c;
}
}
ObjectBase * ObjectBase::clone(bool withChildren) {
ObjectBase * o = new ObjectBase();
o->pass_ = pass_;
o->is_init = false;
o->accept_light = accept_light;
o->accept_fog = accept_fog;
o->visible_ = visible_;
o->type_ = type_;
o->raw_matrix = raw_matrix;
o->mat_ = mat_;
o->pos_ = pos_;
o->angles_ = angles_;
o->scale_ = scale_;
o->itransform_ = itransform_;
o->bound = bound;
o->name_ = name_;// + "_copy";
o->blend_src = blend_src;
o->blend_dest = blend_dest;
o->pos_h = pos_h;
o->material_ = material_;
o->mesh_ = mesh_;
o->meta = meta;
o->scene_ = nullptr;
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
return o;
}
void ObjectBase::destroy() {
if (mesh_) delete mesh_;
}
void ObjectBase::init() {
calculateBoundingBox();
//material_.reflection.create();
//qDebug() << "init" << vbo.buffer_;
is_init = true;
}
void ObjectBase::setScene(Scene * v) {
scene_ = v;
foreach (ObjectBase * c, children_)
c->setScene(v);
}
void ObjectBase::addChild(ObjectBase * o) {
if (o == this) return;
if (o->parent_)
o->parent_->children_.removeAll(o);
children_ << o;
o->parent_ = this;
o->setScene(scene_);
o->buildTransform();
/*if (scene_) {
QList<ObjectBase*> cl = o->children(true);
cl << o;
//foreach (ObjectBase * i, cl) {
// emit view_->objectAdded(i);
//}
}*/
setSceneTreeChanged();
}
void ObjectBase::removeChild(ObjectBase * o) {
if (o == this) return;
children_.removeAll(o);
o->parent_ = nullptr;
o->buildTransform();
setSceneTreeChanged();
}
void ObjectBase::removeChild(int index) {
children_[index]->parent_ = nullptr;
children_[index]->buildTransform();
children_.removeAt(index);
setSceneTreeChanged();
}
void ObjectBase::clearChildren(bool deleteAll) {
foreach (ObjectBase * i, children_) {
i->scene_ = nullptr;
i->parent_ = nullptr;
i->clearChildren(deleteAll);
if (deleteAll) {
delete i;
} else {
i->buildTransform();
}
}
children_.clear();
setSceneTreeChanged();
}
ObjectBase * ObjectBase::child(int index) {
if (index < 0 || index >= children_.size()) return nullptr;
return children_[index];
}
ObjectBase * ObjectBase::child(const QString & name) {
foreach (ObjectBase * i, children_)
if (i->name_ == name) return i;
return nullptr;
}
const ObjectBase * ObjectBase::child(int index) const {
if (index < 0 || index >= children_.size()) return nullptr;
return children_[index];
}
const ObjectBase * ObjectBase::child(const QString & name) const {
foreach (ObjectBase * i, children_)
if (i->name_ == name) return i;
return nullptr;
}
QList<ObjectBase * > ObjectBase::children(bool all_) {
if (!all_) return children_;
QList<ObjectBase * > cl;
addChildren(cl, this);
return cl;
}
bool ObjectBase::isVisible(bool check_parents) const {
if (!check_parents) return visible_;
if (!visible_) return false;
ObjectBase * p = parent_;
while (p) {
if (!p->visible_) return false;
p = p->parent_;
}
return true;
}
void ObjectBase::setVisible(bool v) {
visible_ = v;
setSceneTreeChanged();
}
void ObjectBase::rotateX(GLfloat a) {
raw_matrix = false;
angles_.setX(angles_.x() + a);
buildTransform();
}
void ObjectBase::rotateY(GLfloat a) {
raw_matrix = false;
angles_.setY(angles_.y() + a);
buildTransform();
}
void ObjectBase::rotateZ(GLfloat a) {
raw_matrix = false;
angles_.setZ(angles_.z() + a);
while (angles_.z() < -360.f) angles_.setZ(angles_.z() + 360.f);
while (angles_.z() > 360.f) angles_.setZ(angles_.z() - 360.f);
buildTransform();
}
void ObjectBase::setRotationX(GLfloat a) {
raw_matrix = false;
angles_.setX(a);
buildTransform();
}
void ObjectBase::setRotationY(GLfloat a) {
raw_matrix = false;
angles_.setY(a);
buildTransform();
}
void ObjectBase::setRotationZ(GLfloat a) {
raw_matrix = false;
angles_.setZ(a);
while (angles_.z() < -360.f) angles_.setZ(angles_.z() + 360.f);
while (angles_.z() > 360.f) angles_.setZ(angles_.z() - 360.f);
buildTransform();
}
void ObjectBase::setRotation(const QVector3D & a) {
raw_matrix = false;
angles_= a;
buildTransform();
}
void ObjectBase::resetRotation() {
raw_matrix = false;
angles_ = QVector3D(0., 0., 0.);
buildTransform();
}
void ObjectBase::addChildren(QList<ObjectBase * > & list, ObjectBase * where) {
foreach (ObjectBase * i, where->children_) {
list << i;
addChildren(list, i);
}
}
void ObjectBase::loadTextures(bool with_children) {
if (with_children)
foreach (ObjectBase * i, children_) i->loadTextures();
is_tex_loaded = true;
checkPass();
}
void ObjectBase::calculateBoundingBox() {
bound = Box3D();
if (mesh_) {
bound = mesh_->boundingBox();
QVector<QVector3D> c = bound.corners(), tc;
foreach (QVector3D p, c)
tc << (itransform_ * QVector4D(p, 1)).toVector3D();
bound = Box3D(tc);
}
foreach (ObjectBase * i, children_) {
i->calculateBoundingBox();
bound |= i->boundingBox();
}
}
void ObjectBase::setProperty(const QString & pn, const QVariant & v) {
meta[pn] = v;
}
QVariant ObjectBase::property(const QString & pn, bool * exists) const {
if (exists) *exists = meta.contains(pn);
return meta.value(pn);
}
bool ObjectBase::hasProperty(const QString & pn) const {
return meta.contains(pn);
}
void ObjectBase::removeProperty(const QString & pn) {
meta.remove(pn);
}
void ObjectBase::setTransform(const QMatrix4x4 & t) {
raw_matrix = true;
mat_ = t;
pos_ = mat_.column(3).toVector3D();
mat_.setColumn(3, QVector4D(0., 0., 0., 1.));
buildTransform();
}
bool ObjectBase::isSelected(bool check_parents) const {
if (!check_parents) return selected_;
if (selected_) return true;
ObjectBase * p = parent_;
while (p) {
if (p->selected_) return true;
p = p->parent_;
}
return false;
}
void ObjectBase::setSelected(bool yes) {
//qDebug() << "select" << name() << view_;
if (select_)
selected_ = yes;
}
ObjectBase * ObjectBase::selectedParent() const {
ObjectBase * p = parent_;
while (p) {
if (p->selected_) return p;
p = p->parent_;
}
return 0;
}
void ObjectBase::setMaterial(Material * m, bool with_children) {
material_ = m;
if (with_children)
foreach (ObjectBase * i, children_) i->setMaterial(m, true);
checkPass();
is_tex_loaded = false;
setMeshChanged();
if (scene_) scene_->mat_changed = true;
}
void ObjectBase::setColor(QColor c, bool with_children) {
color_ = c;
if (with_children)
foreach (ObjectBase * i, children_) i->setColor(c, true);
setMeshChanged();
}
void ObjectBase::setMesh(Mesh * v) {
mesh_ = v;
setSceneTreeChanged();
setMeshChanged();
}
void ObjectBase::buildTransform() {
itransform_.setToIdentity();
ObjectBase * p = parent_;
if (p)
itransform_ = p->itransform_;
if (raw_matrix) {
itransform_.translate(pos_);
itransform_ *= mat_;
//qDebug() << "raw_matrix" << itransform_;
} else
localTransform(itransform_);
//qDebug() << name_ << itransform_;
foreach (ObjectBase * i, children_)
i->buildTransform();
setMeshChanged();
}
void ObjectBase::initInternal() {
init();
foreach (ObjectBase * i, children_) i->initInternal();
}
void ObjectBase::localTransform(QMatrix4x4 & m) {
m.translate(pos_);
m.rotate(angles_.z(), 0., 0., 1.);
m.rotate(angles_.y(), 0., 1., 0.);
m.rotate(angles_.x(), 1., 0., 0.);
m.scale(scale_);
}
void ObjectBase::checkPass() {
pass_ = Solid;
if (material_) {
if (material_->hasTransparency())
pass_ = Transparent;
}
}
void ObjectBase::setSceneTreeChanged() {
if (scene_) {
scene_->setTreeChanged();
scene_->setTreeStructChanged();
}
setMeshChanged();
}
void ObjectBase::setMeshChanged() {
if (mesh_) mesh_->objects_changed = true;
}
QMatrix4x4 ObjectBase::worldMatrix(QMatrix4x4 parent) const {
QMatrix4x4 mat;
mat.translate(pos_);
if (raw_matrix) {
mat *= mat_;
} else {
if (angles_.z() != 0.f) mat.rotate(angles_.z(), 0., 0., 1.);
if (angles_.y() != 0.f) mat.rotate(angles_.y(), 0., 1., 0.);
if (angles_.x() != 0.f) mat.rotate(angles_.x(), 1., 0., 0.);
mat.scale(scale_);
}
return parent * mat;
}
Light::Light(): ObjectBase(), shadow_map(0, true, GL_R16F) {
type_ = glLight;
light_type = Omni;
intensity = 1.;
angle_start = angle_end = 180.;
decay_linear = decay_quadratic = decay_start = 0.;
decay_const = decay_end = 1.;
direction.setZ(1.);
}
Light::Light(const QVector3D & p, const QColor & c, float i): ObjectBase(), shadow_map(0, true, GL_R16F) {
type_ = glLight;
light_type = Omni;
pos_ = p;
intensity = i;
color_ = c;
angle_start = angle_end = 180.;
decay_linear = decay_quadratic = decay_start = 0.;
decay_const = decay_end = 1.;
direction.setZ(1.);
}
ObjectBase * Light::clone(bool withChildren) {
Light * o = new Light(*this);
//GLObjectBase::clone(withChildren);
o->is_init = false;
o->name_ = name_;// + "_copy";
o->scene_ = nullptr;
o->children_.clear();
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
o->light_type = light_type;
o->direction = direction;
o->angle_start = angle_start;
o->angle_end = angle_end;
o->intensity = intensity;
o->decay_const = decay_const;
o->decay_linear = decay_linear;
o->decay_quadratic = decay_quadratic;
o->meta = meta;
return o;
}
void Light::apply() {
if (scene_) scene_->setLightsChanged();
}
QDataStream & operator <<(QDataStream & s, const ObjectBase * p) {
ChunkStream cs;
//qDebug() << "place" << p->name() << "...";
cs.add(1, int(p->type_)).add(2, p->accept_light).add(3, p->accept_fog).add(4, p->visible_)
.add(5, p->cast_shadow).add(6, p->rec_shadow).add(7, p->raw_matrix).add(8, p->line_width)
.add(9, int(p->render_mode)).add(11, p->pos_).add(12, p->angles_)
.add(13, p->scale_).add(14, p->mat_).add(16, p->children_.size())
.add(17, p->name_).add(18, p->meta).add(19, p->color_);
//qDebug() << "place self done";
if (p->type_ == ObjectBase::glLight) {
//qDebug() << "place light ...";
const Light * l = (const Light*)p;
cs.add(100, l->direction).add(101, l->angle_start).add(102, l->angle_end).add(103, l->intensity)
.add(104, l->decay_const).add(105, l->decay_linear).add(106, l->decay_quadratic)
.add(107, l->decay_start).add(108, l->decay_end).add(109, int(l->light_type));
}
if (p->type_ == ObjectBase::glCamera) {
//qDebug() << "place camera ...";
const Camera * c = (const Camera*)p;
cs.add(200, c->aim_).add(201, c->fov_).add(202, c->depth_start).add(203, c->depth_end)
.add(204, c->angle_limit_lower_xy).add(205, c->angle_limit_upper_xy)
.add(206, c->mirror_x).add(207, c->mirror_y);
}
//qDebug() << "place" << p->name() << cs.data().size() << s.device()->size();
s << cs.data();
foreach (const ObjectBase * c, p->children_)
s << c;
return s;
}
QDataStream & operator >>(QDataStream & s, ObjectBase *& p) {
ChunkStream cs(s);
p = nullptr;
int ccnt = 0;
Light * l = nullptr;
Camera * c = nullptr;
QVector3D cam_angles;
//qDebug() << "read obj ...";
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: {
ObjectBase::Type type = (ObjectBase::Type)cs.getData<int>();
switch (type) {
case ObjectBase::glMesh: p = new ObjectBase(); break;
case ObjectBase::glLight: p = new Light(); l = (Light*)p; break;
case ObjectBase::glCamera: p = new Camera(); c = (Camera*)p; break;
default : break;
}
if (p) p->type_ = type;
} break;
case 2: if (p) p->accept_light = cs.getData<bool>(); break;
case 3: if (p) p->accept_fog = cs.getData<bool>(); break;
case 4: if (p) p->visible_ = cs.getData<bool>(); break;
case 5: if (p) p->cast_shadow = cs.getData<bool>(); break;
case 6: if (p) p->rec_shadow = cs.getData<bool>(); break;
case 7: if (p) p->raw_matrix = cs.getData<bool>(); break;
case 8: if (p) p->line_width = cs.getData<float>(); break;
case 9: if (p) p->render_mode = (ObjectBase::RenderMode)cs.getData<int>(); break;
//case 10: if (p) p->material_ = cs.getData<Material>(); break;
case 11: if (p) p->pos_ = cs.getData<QVector3D>(); break;
case 12:
if (p) p->angles_ = cs.getData<QVector3D>();
if (c) {
c->setAngles(cs.getData<QVector3D>());
cam_angles = c->angles();
}
break;
case 13: if (p) p->scale_ = cs.getData<QVector3D>(); break;
case 14: if (p) p->mat_ = cs.getData<QMatrix4x4>(); break;
//case 15: if (p) p->vbo = cs.getData<VBO>(); break;
case 16: if (p) ccnt = cs.getData<int>(); break;
case 17: if (p) p->name_ = cs.getData<QString>(); break;
case 18: if (p) p->meta = cs.getData<QVariantMap>(); break;
case 19: if (p) p->color_ = cs.getData<QColor>(); break;
case 100: if (l) l->direction = cs.getData<QVector3D>(); break;
case 101: if (l) l->angle_start = cs.getData<GLfloat>(); break;
case 102: if (l) l->angle_end = cs.getData<GLfloat>(); break;
case 103: if (l) l->intensity = cs.getData<GLfloat>(); break;
case 104: if (l) l->decay_const = cs.getData<GLfloat>(); break;
case 105: if (l) l->decay_linear = cs.getData<GLfloat>(); break;
case 106: if (l) l->decay_quadratic = cs.getData<GLfloat>(); break;
case 107: if (l) l->decay_start = cs.getData<GLfloat>(); break;
case 108: if (l) l->decay_end = cs.getData<GLfloat>(); break;
case 109: if (l) l->light_type = (Light::Type)cs.getData<int>(); break;
case 200: if (c) c->setAim(cs.getData<QVector3D>()); break;
case 201: if (c) c->setFOV(cs.getData<GLfloat>()); break;
case 202: if (c) c->setDepthStart(cs.getData<GLfloat>()); break;
case 203: if (c) c->setDepthEnd(cs.getData<GLfloat>()); break;
case 204: if (c) c->setAngleLowerLimitXY(cs.getData<GLfloat>()); break;
case 205: if (c) c->setAngleUpperLimitXY(cs.getData<GLfloat>()); break;
case 206: if (c) c->mirror_x = cs.getData<bool>(); break;
case 207: if (c) c->mirror_y = cs.getData<bool>(); break;
}
}
if (c) c->setAngles(cam_angles);
//qDebug() << p->name() << ccnt;
for (int i = 0; i < ccnt; ++i) {
ObjectBase * c = nullptr;
s >> c;
if (!c) continue;
c->parent_ = p;
p->children_ << c;
}
return s;
}

275
qglengine/globject.h Normal file
View File

@@ -0,0 +1,275 @@
/*
GLObjectBase & Light
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLOBJECT_H
#define GLOBJECT_H
#include "glframebuffer.h"
#include "glmaterial.h"
#include "gltypes.h"
class ObjectBase
{
friend class QGLView;
friend class Scene;
friend class Renderer;
friend QDataStream & operator <<(QDataStream & s, const ObjectBase * p);
friend QDataStream & operator >>(QDataStream & s, ObjectBase *& p);
friend QDataStream & operator >>(QDataStream & s, Scene *& p);
public:
enum Type {glMesh, glLight, glCamera, glParticlesSystem};
enum Pass {Solid, Transparent, Reflection, User};
enum RenderMode {View = 0, Point = GL_POINT, Line = GL_LINE, Fill = GL_FILL};
explicit ObjectBase(Mesh * geom = 0, Material * mat = 0);
virtual ~ObjectBase();
virtual ObjectBase * clone(bool withChildren = true);
void destroy();
QString name() const {return name_;}
void setName(const QString & name) {name_ = name;}
//virtual GLuint hList() {return list;}
virtual void init();
virtual void update() {}
bool isInit() const {return is_init;}
bool isTexturesLoaded() const {return is_tex_loaded;}
Type type() const {return type_;}
RenderMode renderMode() const {return render_mode;}
void setRenderMode(RenderMode mode) {render_mode = mode;}
float lineWidth() const {return line_width;}
void setLineWidth(const float & width) {line_width = width;}
ObjectBase * parent() {return parent_;}
void setParent(ObjectBase * o) {parent_ = o;}
bool hasParent() const {return parent_ != nullptr;}
bool hasChildren() const {return children_.size() != 0;}
void setScene(Scene * v);
void addChild(ObjectBase * o);
void removeChild(ObjectBase * o);
void removeChild(int index);
void clearChildren(bool deleteAll = false);
int childCount() const {return children_.size();}
ObjectBase * child(int index);
ObjectBase * child(const QString & name);
const ObjectBase * child(int index) const;
const ObjectBase * child(const QString & name) const;
QList<ObjectBase * > children(bool all_ = false);
bool isVisible(bool check_parents = false) const;
bool isHidden(bool check_parents = false) const {return !isVisible(check_parents);}
void setVisible(bool v);
void setHidden(bool v) {setVisible(!v);}
void show() {setVisible(true);}
void hide() {setVisible(false);}
bool isReceiveShadows() const {return rec_shadow;}
bool isCastShadows() const {return cast_shadow;}
void setReceiveShadows(bool on) {rec_shadow = on;}
void setCastShadows(bool on) {cast_shadow = on;}
void move(const QVector3D & dv) {pos_ += dv; buildTransform();}
void moveTo(const QVector3D & dv) {pos_ = dv; buildTransform();}
void move(GLfloat dx, GLfloat dy, GLfloat dz = 0.) {move(QVector3D(dx, dy, dz)); buildTransform();}
void moveTo(GLfloat dx, GLfloat dy, GLfloat dz = 0.) {moveTo(QVector3D(dx, dy, dz)); buildTransform();}
void moveX(GLfloat o) {pos_.setX(pos_.x() + o); buildTransform();}
void moveY(GLfloat o) {pos_.setY(pos_.y() + o); buildTransform();}
void moveZ(GLfloat o) {pos_.setZ(pos_.z() + o); buildTransform();}
void setPosX(GLfloat o) {pos_.setX(o); buildTransform();}
void setPosY(GLfloat o) {pos_.setY(o); buildTransform();}
void setPosZ(GLfloat o) {pos_.setZ(o); buildTransform();}
void setPos(GLfloat x, GLfloat y, GLfloat z) {pos_ = QVector3D(x, y, z); buildTransform();}
void setPos(const QVector3D & p) {pos_ = p; buildTransform();}
void resetPos() {pos_ = QVector3D(0., 0., 0.); buildTransform();}
QVector3D pos() const {return pos_;}
float posX() const {return pos_.x();}
float posY() const {return pos_.y();}
float posZ() const {return pos_.z();}
QVector3D worldPos() const {return (itransform_ * QVector4D(0, 0, 0, 1.)).toVector3D();}
QMatrix4x4 worldTransform() const {return itransform_;}
QVector3D rotation() const {return angles_;}
float rotationX() const {return angles_.x();}
float rotationY() const {return angles_.y();}
float rotationZ() const {return angles_.z();}
void rotateX(GLfloat a);
void rotateY(GLfloat a);
void rotateZ(GLfloat a);
void setRotationX(GLfloat a);
void setRotationY(GLfloat a);
void setRotationZ(GLfloat a);
void setRotation(const QVector3D & a);
void resetRotation();
QVector3D scale() {return scale_;}
float scaleX() {return scale_.x();}
float scaleY() {return scale_.y();}
float scaleZ() {return scale_.z();}
void scale(const QVector3D & sv) {raw_matrix = false; scale_ *= sv; buildTransform();}
void scale(GLfloat sx, GLfloat sy, GLfloat sz) {raw_matrix = false; scale(QVector3D(sx, sy, sz)); buildTransform();}
void scale(GLfloat sx, GLfloat sy) {raw_matrix = false; scale(QVector3D(sx, sy, sy)); buildTransform();}
void scale(GLfloat sx) {raw_matrix = false; scale(QVector3D(sx, sx, sx)); buildTransform();}
void scaleX(GLfloat a) {raw_matrix = false; scale_.setX(scale_.x() + a); buildTransform();}
void scaleY(GLfloat a) {raw_matrix = false; scale_.setY(scale_.y() + a); buildTransform();}
void scaleZ(GLfloat a) {raw_matrix = false; scale_.setZ(scale_.z() + a); buildTransform();}
void setScale(const QVector3D & a) {raw_matrix = false; scale_ = a; buildTransform();}
void setScale(GLfloat a) {raw_matrix = false; scale_ = QVector3D(a, a, a); buildTransform();}
void setScaleX(GLfloat a) {raw_matrix = false; scale_.setX(a); buildTransform();}
void setScaleY(GLfloat a) {raw_matrix = false; scale_.setY(a); buildTransform();}
void setScaleZ(GLfloat a) {raw_matrix = false; scale_.setZ(a); buildTransform();}
void resetScale() {raw_matrix = false; scale_ = QVector3D(1., 1., 1.); buildTransform();}
QMatrix4x4 transform() {return mat_;}
void setTransform(const QMatrix4x4 & t);
bool isRawMatrix() {return raw_matrix;}
bool isAcceptLight() const {return accept_light;}
void setAcceptLight(bool yes) {accept_light = yes;}
bool isAcceptFog() const {return accept_fog;}
void setAcceptFog(bool yes) {accept_fog = yes;}
bool isSelected(bool check_parents = false) const;
void setSelected(bool yes);
void select() {setSelected(true);}
void deselect() {setSelected(false);}
ObjectBase * selectedParent() const;
bool isSelectable() const {return select_;}
void setSelectable(bool yes) {select_ = yes;}
/*
bool isWriteDepth() const {return write_depth_;}
void setWriteDepth(bool yes) {write_depth_ = yes;}*/
GLenum srcAlpha() const {return blend_src;}
GLenum destAlpha() const {return blend_dest;}
void setSrcAlpha(GLenum mode) {blend_src = mode;}
void setDestAlpha(GLenum mode) {blend_dest = mode;}
void setMaterial(Material * m, bool with_children = false);
Material * material() {return material_;}
void setColor(QColor c, bool with_children = false);
QColor color() {return color_;}
const Box3D & boundingBox() const {return bound;}
void setMesh(Mesh * v);
Mesh * mesh() {return mesh_;}
void calculateBoundingBox();
void setProperty(const QString & pn, const QVariant & v);
QVariant property(const QString & pn, bool * exists = 0) const;
bool hasProperty(const QString & pn) const;
void removeProperty(const QString & pn);
QVector3D pos_h;
//QVector<GLfloat> d_vertices, d_normals, d_uvs;
protected:
void addChildren(QList<ObjectBase * > & list, ObjectBase * where);
void loadTextures(bool with_children = false);
//void deleteTextures() {foreach (GLuint i, textures) currentQGLView->deleteTexture(i); textures.clear();}
void buildTransform();
void initInternal();
void checkPass();
void setSceneTreeChanged();
void setMeshChanged();
virtual void localTransform(QMatrix4x4 & m);
QMatrix4x4 worldMatrix(QMatrix4x4 parent) const;
int pass_; // Pass
bool is_init, is_tex_loaded, accept_light, accept_fog, /*write_depth_,*/ visible_, cast_shadow, rec_shadow, select_, selected_, raw_matrix;
bool is_root;
float line_width;
QColor color_;
uint id_;
Type type_;
RenderMode render_mode;
Box3D bound;
QVector3D pos_, angles_, scale_;
QList<ObjectBase * > children_;
QMatrix4x4 itransform_, mat_;
QString name_;
GLenum blend_src, blend_dest;
ObjectBase * parent_;
Scene * scene_;
Material * material_;
Mesh * mesh_;
QVariantMap meta;
};
inline bool operator <(const ObjectBase & f, const ObjectBase & s) {return f.pos_h.z() < s.pos_h.z();}
class AimedObject: public ObjectBase {
friend class QGLView;
friend class GLRendererBase;
public:
AimedObject();
~AimedObject();
};
class Light: public ObjectBase {
friend class QGLView;
friend class RendererBase;
public:
enum Type {Omni, Directional, Cone};
Light();
Light(const QVector3D & p, const QColor & c = Qt::white, float i = 1.);
virtual ObjectBase * clone(bool withChildren = true);
virtual void init() {shadow_map.resize(512, 512); is_init = true;}
void apply();
QVector3D direction, dir0, dir1;
float angle_start;
float angle_end;
float intensity;
float decay_const;
float decay_linear;
float decay_quadratic;
float decay_start;
float decay_end;
Type light_type;
Framebuffer shadow_map;
QMatrix4x4 shadow_matrix;
protected:
};
template <class T>
inline T globject_cast(ObjectBase * object) {return reinterpret_cast<T>(object);}
template <class T>
inline T globject_cast(const ObjectBase * object) {return reinterpret_cast<T>(object);}
QDataStream & operator <<(QDataStream & s, const ObjectBase * p);
QDataStream & operator >>(QDataStream & s, ObjectBase *& p);
#endif // GLOBJECT_H

263
qglengine/glprimitives.cpp Normal file
View File

@@ -0,0 +1,263 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "glprimitives.h"
#include "glmesh.h"
Mesh * Primitive::plane(float width, float length) {
Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ());
QVector<QVector3D> & n(ret->normals ());
QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & i(ret->indices ());
float hw = width / 2.f, hl = length / 2.f;
for (int j = 0; j < 4; ++j) n << QVector3D(0., 0., 1.);
t << QVector2D(0., 0.) << QVector2D(0., 1.) << QVector2D(1., 1.) << QVector2D(1., 0.);
v << QVector3D(-hw, -hl, 0.) << QVector3D(-hw, hl, 0.) << QVector3D(hw, hl, 0.) << QVector3D(hw, -hl, 0.);
i << Vector3i(0, 2, 1) << Vector3i(0, 3, 2);
return ret;
}
Mesh * Primitive::cube(float width, float length, float height) {
Mesh * ret = new Mesh();
QVector3D scale(width, length, height);
QVector<QVector3D> & v(ret->vertices ());
QVector<QVector3D> & n(ret->normals ());
QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & i(ret->indices ());
float hs = 0.5f;
int si = 0;
QMatrix4x4 mat;
si = v.size();
for (int j = 0; j < 4; ++j) n << QVector3D(0., -1., 0.);
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
v << QVector3D(-hs, -hs, -hs) << QVector3D(hs, -hs, -hs) << QVector3D(hs, -hs, hs) << QVector3D(-hs, -hs, hs);
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
for (int r = 0; r < 3; ++r) {
si = v.size();
mat.rotate(90., 0., 0., 1.);
QVector3D cn = mat.map(n[0]);
for (int j = 0; j < 4; ++j) {
n << cn;
v << mat.map(QVector4D(v[j])).toVector3D();
}
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
}
mat.setToIdentity();
mat.rotate(90., 1., 0.,0.);
for (int r = 0; r < 2; ++r) {
si = v.size();
mat.rotate(180., 1., 0.,0.);
QVector3D cn = mat.map(n[0]);
for (int j = 0; j < 4; ++j) {
n << cn;
v << mat.map(QVector4D(v[j])).toVector3D();
}
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
}
for (int i = 0; i < v.size(); ++i)
v[i] *= scale;
return ret;
}
Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float width, float length, float height) {
Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ());
QVector<QVector3D> & n(ret->normals ());
QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indices());
double hh = height / 2.f;
int hseg = segments_h + 1, wlseg = segments_wl + 1;
double crw, crl, a, ch, twl;
QVector3D cp;
for (int i = 0; i <= hseg; i++) {
ch = -cos((double)i / hseg * M_PI);
cp.setZ(ch * hh);
twl = sqrt(1. - ch * ch) / 2.;
crw = twl * width;
crl = twl * length;
int cvcnt = wlseg * 2;
for (int j = 0; j < cvcnt; j++) {
a = (double)j / (cvcnt - 1) * M_2PI;
cp.setX(crl * cos(a));
cp.setY(crw * sin(a));
v << cp; t << QVector2D((double)j / (cvcnt - 1), ch/2.f + 0.5f);
int si = v.size() - 1;
if (j > 0 && i > 0) {
ind << Vector3i(si - cvcnt - 1, si, si - 1);
ind << Vector3i(si - cvcnt, si, si - cvcnt - 1);
}
}
}
n.resize(v.size());
for (int i = 0; i < v.size(); i++)
n[i] = v[i].normalized();
return ret;
}
Mesh * Primitive::disc(int segments, float width, float length, bool up) {
Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ());
QVector<QVector3D> & n(ret->normals ());
QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indices());
segments = qMax(segments + 1, 4);
QVector3D cp;
v << QVector3D();
t << QVector2D(0.5f, 0.5f);
for (int i = 0; i < segments; i++) {
double a = (double)i / (segments - 1) * M_2PI;
cp.setX(length / 2. * cos(a));
cp.setY(width / 2. * sin(a));
v << cp;
t << QVector2D(cp.x() / width + 0.5f, cp.y() / length + 0.5f);
int si = v.size() - 1;
if (i > 0) {
if (up)
ind << Vector3i(si - 1, si, 0);
else
ind << Vector3i(si, si - 1, 0);
}
}
n.resize(v.size());
for (int i = 0; i < v.size(); i++)
n[i] = QVector3D(0, 0, up ? 1 : -1);
return ret;
}
QVector3D coneNormal(double rx, double ry, double height, double ang) {
QVector3D norm;
norm.setX(rx * cos(ang));
norm.setY(ry * sin(ang));
norm.setZ(0.);
double rl = norm.length();
double ca = atan2(rl, height);
norm *= cos(ca);
norm.setZ(norm.length() * tan(ca));
return norm.normalized();
}
Mesh * Primitive::cone(int segments, float width, float length, float height) {
Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ());
QVector<QVector3D> & n(ret->normals ());
QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indices());
int seg = qMax(segments + 1, 4);
double rx = width / 2., ry = length / 2.;
QVector3D cp;
for (int i = 0; i < seg; i++) {
double a = (double)i / (seg - 1) * M_2PI;
cp.setX(ry * cos(a));
cp.setY(rx * sin(a));
if (i > 0) {
v << QVector3D(0, 0, height);
t << QVector2D((double)(i - 1) / (seg - 1), 1.f);
double ta = ((double)i - 0.5) / (seg - 1) * M_2PI;
n << coneNormal(rx, ry, height, ta);
}
v << cp;
t << QVector2D((double)i / (seg - 1), 0.f);
n << coneNormal(rx, ry, height, a);
int si = v.size() - 1;
if (i > 0)
ind << Vector3i(si - 1, si - 2, si);
}
Mesh * cap = Primitive::disc(segments, width, length, false);
ret->append(cap);
delete cap;
return ret;
}
Mesh * Primitive::cylinder(int segments, float width, float length, float height) {
Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ());
QVector<QVector3D> & n(ret->normals ());
QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indices());
int seg = qMax(segments + 1, 4);
double rx = width / 2., ry = length / 2.;
QVector3D cp, norm;
for (int i = 0; i < seg; i++) {
double a = (double)i / (seg - 1) * M_2PI;
cp.setX(ry * cos(a));
cp.setY(rx * sin(a));
cp.setZ(0.);
norm = cp.normalized();
v << cp;
cp.setZ(height);
v << cp;
t << QVector2D((double)i / (seg - 1), 0.f);
t << QVector2D((double)i / (seg - 1), 1.f);
n << norm; n << norm;
int si = v.size() - 1;
if (i > 0) {
ind << Vector3i(si - 2, si - 1, si);
ind << Vector3i(si - 1, si - 2, si - 3);
}
}
Mesh * cap = Primitive::disc(segments, width, length, false);
ret->append(cap);
delete cap;
cap = Primitive::disc(segments, width, length, true);
cap->translatePoints(QVector3D(0., 0., height));
ret->append(cap);
delete cap;
return ret;
}
Mesh * Primitive::arrow(int segments, float thick, float angle) {
double cone_d = 3. * thick;
double cone_h = cone_d / tan(angle * deg2rad);
Mesh * ret = new Mesh();
Mesh * m = Primitive::cylinder(segments, thick, thick, 1. - cone_h);
ret->append(m);
delete m;
m = Primitive::cone(segments, cone_d, cone_d, cone_h);
m->translatePoints(QVector3D(0., 0., 1. - cone_h));
ret->append(m);
delete m;
return ret;
}

94
qglengine/glprimitives.h Normal file
View File

@@ -0,0 +1,94 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLPRIMITIVE_CUBE_H
#define GLPRIMITIVE_CUBE_H
#include "gltypes.h"
namespace Primitive {
Mesh * plane(float width = 1., float length = 1.);
Mesh * cube(float width = 1., float length = 1., float height = 1.);
Mesh * ellipsoid(int segments_wl, int segments_h, float width = 1., float length = 1., float height = 1.);
Mesh * disc(int segments, float width = 1., float length = 1., bool up = true);
Mesh * cone(int segments, float width = 1., float length = 1., float height = 1.);
Mesh * cylinder(int segments, float width = 1., float length = 1., float height = 1.);
Mesh * arrow(int segments = 16, float thick = 0.04, float angle = 30.); // length = 1
}
/*
class GLPrimitivePoint: public GLObjectBase
{
public:
GLPrimitivePoint(double size = 1., QVector3D pos = QVector3D()) {sz = 8.;}
virtual void draw(QOpenGLShaderProgram * prog, bool simplest = false);
private:
double sz;
};
class GLPrimitiveLine: public GLObjectBase
{
public:
GLPrimitiveLine(QVector3D p0_ = QVector3D(), QVector3D p1_ = QVector3D()) {p0 = p0_; p1 = p1_;}
virtual void draw(QOpenGLShaderProgram * prog, bool simplest = false);
QVector3D point0() const {return p0;}
QVector3D point1() const {return p1;}
void setPoint0(const QVector3D & p) {p0 = p;}
void setPoint1(const QVector3D & p) {p1 = p;}
private:
QVector3D p0, p1;
};
class GLPrimitiveEllipsoid: public GLObjectBase
{
public:
GLPrimitiveEllipsoid(float width = 1., float length = 1., float height = 1., int seg_wl = 10, int seg_h = 10, QVector3D pos = QVector3D());
virtual void init();
private:
void putTriangle(const QVector3D & v0, const QVector3D & v1, const QVector3D & v2);
float w, l, h;
int swl, sh;
};
class GLPrimitiveAxis: public GLObjectBase
{
public:
GLPrimitiveAxis() {accept_fog = accept_light = cast_shadow = rec_shadow = select_ = false;}
virtual void draw(QOpenGLShaderProgram * prog, bool simplest = false);
};
*/
#endif // GLPRIMITIVE_CUBE_H

View File

@@ -0,0 +1,296 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "glrendererbase.h"
#include "globject.h"
#include "qglview.h"
GLRendererBase::GLRendererBase(QGLView * view_): view(view_) {
white_image = QImage(1, 1, QImage::Format_ARGB32);
white_image.fill(0xFFFFFFFF);
white_image_id = 0;
violent_image = QImage(1, 1, QImage::Format_ARGB32);
violent_image.fill(QColor(127, 127, 255));
violent_image_id = 0;
}
void GLRendererBase::setupLight(const Light & l, int inpass_index, int gl_index) {
QVector3D lp = l.worldPos(), ld;// = (l.itransform_ * QVector4D(l.direction, 0.)).toVector3D().normalized();
GLfloat pos[] = {0.f, 0.f, 0.f, 0.f};
GLfloat dir[] = {0.f, 0.f, 0.f};
GLfloat col[] = {0.f, 0.f, 0.f};
pos[0] = l.light_type == Light::Directional ? -l.direction.x() : lp.x();
pos[1] = l.light_type == Light::Directional ? -l.direction.y() : lp.y();
pos[2] = l.light_type == Light::Directional ? -l.direction.z() : lp.z();
pos[3] = l.light_type == Light::Directional ? 0. : 1.;
dir[0] = ld.x();
dir[1] = ld.y();
dir[2] = ld.z();
//col[0] = l.visible_ ? l.color().redF() * l.intensity : 0.f;
//col[1] = l.visible_ ? l.color().greenF() * l.intensity : 0.f;
//col[2] = l.visible_ ? l.color().blueF() * l.intensity : 0.f;
glEnable(gl_index);
//glLightfv(gl_index, GL_AMBIENT, ambient);
glLightfv(gl_index, GL_DIFFUSE, col);
glLightfv(gl_index, GL_SPECULAR, col);
glLightfv(gl_index, GL_POSITION, pos);
glLightf(gl_index, GL_CONSTANT_ATTENUATION, l.decay_const);
glLightf(gl_index, GL_LINEAR_ATTENUATION, l.decay_linear);
glLightf(gl_index, GL_QUADRATIC_ATTENUATION, l.decay_quadratic);
if (l.light_type == Light::Cone) {
glLightfv(gl_index, GL_SPOT_DIRECTION, dir);
glLightf(gl_index, GL_SPOT_CUTOFF, l.angle_end / 2.f);
glLightf(gl_index, GL_SPOT_EXPONENT, (1.f - piClamp<float>((l.angle_end - l.angle_start) / (l.angle_end + 0.001f), 0., 1.f)) * 128.f);
} else {
glLightf(gl_index, GL_SPOT_CUTOFF, 180.);
}
}
void GLRendererBase::setupAmbientLight(const QColor & a, bool first_pass) {
GLfloat ambient[] = {0.0f, 0.0f, 0.0f, 1.f};
if (first_pass) {
ambient[0] = view->ambientColor_.redF();
ambient[1] = view->ambientColor_.greenF();
ambient[2] = view->ambientColor_.blueF();
}
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
}
void GLRendererBase::setupShadersLights(int lights_count) {
/*foreach (QOpenGLShaderProgram * i, view->shaders_ppl) {
i->bind();
i->setUniformValue("lightsCount", lights_count);
i->setUniformValue("acc_light", lights_count > 0);
//i->setUniformValue("mat", mvm);
}*/
}
#define BIND_TEXTURE(ch, map) if (rp.prev_tex[ch] != mat.map.bitmap_id) { \
rp.prev_tex[ch] = mat.map.bitmap_id; \
glActiveTexture(GL_TEXTURE0 + ch); glBindTexture(GL_TEXTURE_2D, mat.map.bitmap_id); \
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view->feature(QGLView::qglAnisotropicLevel).toInt());}
void GLRendererBase::setupTextures(ObjectBase & o, GLRendererBase::RenderingParameters & rp, bool first_object) {
}
#undef BIND_TEXTURE
void GLRendererBase::setupLights(int pass, int lights_per_pass) {
/*int light_start, light_end, lmax;
light_start = pass * lights_per_pass;
light_end = qMin<int>((pass + 1) * lights_per_pass, view->lights_.size());
setupAmbientLight(view->ambientColor_, pass == 0);
if (!view->lights_.isEmpty()) {
setupShadersLights(light_end - light_start);
for (int i = light_start; i < light_end; ++i)
setupLight(*view->lights_[i], i - light_start, GL_LIGHT0 + i - light_start);
lmax = light_start + 8;
for (int i = light_end; i < lmax; ++i)
glDisable(GL_LIGHT0 + i - light_start);
} else {
setupShadersLights(0);
for (int i = 0; i < 8; ++i)
glDisable(GL_LIGHT0 + i);
}*/
}
void GLRendererBase::applyFilteringParameters() {
/*if (view->isFeatureEnabled(QGLView::qglLinearFiltering)) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
}*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, view->feature(QGLView::qglAnisotropicLevel).toInt());
}
void GLRendererBase::renderObjects(int pass, int light_pass, void * shaders, bool textures, bool light, bool fog) {
/*RenderingParameters rpl;
rpl.pass = pass;
rpl.light_pass = light_pass;
rpl.shaders = shaders;
rpl.textures = textures;
rpl.light = rpl.prev_light = light;
rpl.fog = rpl.prev_fog = fog;
rpl.view_matrix = rp.view_matrix;
rpl.prev_view_matrix = rp.prev_view_matrix;
rpl.proj_matrix = rp.proj_matrix;
rpl.prev_proj_matrix = rp.prev_proj_matrix;
rpl.cam_offset_matrix = view->camera()->offsetMatrix();
//qDebug() << "view:" << rp.view_matrix;
for (int i = 0; i < 32; ++i) rpl.prev_tex[i] = 0;
setupTextures(view->objects_, rpl, true);
glSetCapEnabled(GL_TEXTURE_2D, rpl.textures);
glSetCapEnabled(GL_BLEND, pass == ObjectBase::Transparent);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_CUBE_MAP);
glPushMatrix();
renderSingleObject(view->objects_, rpl);
glPopMatrix();*/
}
void GLRendererBase::renderSingleObject(ObjectBase & o, RenderingParameters & rpl) {
// if (!o.isInit())
// o.init();
// if (!o.isTexturesLoaded())
// o.loadTextures();
// if (!o.visible_) return;
// if (rpl.pass == o.pass_) {
// //Material & mat(o.material_);
// QMatrix4x4 curview = rpl.view_matrix * rpl.cam_offset_matrix * o.itransform_, prevview = rpl.prev_view_matrix * rpl.cam_offset_matrix * o.itransform_;
// //setupTextures(o, rpl, false);
// //mat.apply((QOpenGLShaderProgram*)rpl.shaders);
// glSetPolygonMode(o.render_mode != ObjectBase::View ? o.render_mode : (view->rmode != ObjectBase::View ? view->rmode : GL_FILL));
// glLineWidth(o.line_width > 0.f ? o.line_width : view->lineWidth_);
// glPointSize(o.line_width > 0.f ? o.line_width : view->lineWidth_);
// o.update();
// /*if (o.pass_ == GLObjectBase::Transparent) {
// glActiveTexture(GL_TEXTURE0 + 3);
// if (mat.reflectivity > 0.f) {
// glEnable(GL_TEXTURE_CUBE_MAP);
// //if (!mat.map_reflection.isEmpty()) mat.map_reflection.bind();
// //else glDisable(GL_TEXTURE_CUBE_MAP);
// } else glDisable(GL_TEXTURE_CUBE_MAP);
// if (rpl.light_pass > 0) glDisable(GL_TEXTURE_CUBE_MAP);
// GLfloat gm[16], bc[4] = {mat.reflectivity, mat.reflectivity, mat.reflectivity, mat.reflectivity};
// glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
// glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT);
// glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
// glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, bc);
// glGetFloatv(GL_MODELVIEW_MATRIX, gm);
// glMatrixMode(GL_TEXTURE);
// ///glLoadTransposeMatrixf(gm);
// glScalef(-1., -1., -1.);
// glMatrixMode(GL_MODELVIEW);
// glActiveTexture(GL_TEXTURE0);
// }*/
// if (rpl.shaders) {
// //qDebug() << o.name() << curview << curview->determinant();
// //setUniformMatrices((QOpenGLShaderProgram*)rpl.shaders, rpl.proj_matrix, curview, rpl.prev_proj_matrix, prevview);
// } else {
// glMatrixMode(GL_MODELVIEW);
// //setGLMatrix(curview);
// }
// o.draw((QOpenGLShaderProgram*)rpl.shaders);
// }
// foreach (ObjectBase * i, o.children_)
// renderSingleObject(*i, rpl);
}
void GLRendererBase::renderShadow(Light * l, QOpenGLShaderProgram * prog, QMatrix4x4 mat) {
Camera cam;
QVector3D wp = l->worldPos();
cam.setPos(wp);
cam.setAim(wp + (l->worldTransform() * QVector4D(l->direction)).toVector3D());
cam.setDepthStart(view->camera()->depthStart());
cam.setDepthEnd(view->camera()->depthEnd());
cam.setFOV(l->angle_end);
cam.apply(1.);
/*cam.rotateXY(l->angle_end);
QVector3D rdir = l->direction * cos(l->angle_end / 2. * deg2rad);
l->dir0 = cam.direction() - rdir;
cam.rotateXY(-l->angle_end);
cam.rotateZ(l->angle_end);
l->dir1 = cam.direction() - rdir;*/
//qDebug() << rdir << l->dir0 << l->dir1;
RenderingParameters rpl;
rpl.pass = ObjectBase::Solid;
rpl.shaders = prog;
rpl.textures = rpl.light = rpl.fog = false;
//rpl.view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX);
//rpl.proj_matrix = getGLMatrix(GL_PROJECTION_MATRIX);
rpl.cam_offset_matrix = cam.offsetMatrix();
QMatrix4x4 mbias;
mbias.scale(0.5, 0.5, 0.5);
mbias.translate(1., 1., 1.);
l->shadow_matrix = mbias*rpl.proj_matrix*rpl.view_matrix*rpl.cam_offset_matrix*mat;//;// * mbias;
//qDebug() << mbias;
//glPushMatrix();
//renderSingleShadow(view->objects_, rpl);
//glPopMatrix();
}
void GLRendererBase::renderSingleShadow(ObjectBase & o, RenderingParameters & rpl) {
// if (!o.isInit())
// o.init();
// if (!o.visible_) return;
// if (rpl.shaders) {
// //qDebug() << o.name() << curview << curview->determinant();
// //setUniformMatrices((QOpenGLShaderProgram*)rpl.shaders, rpl.proj_matrix, rpl.view_matrix * rpl.cam_offset_matrix * o.itransform_);
// } else {
// glMatrixMode(GL_MODELVIEW);
// //setGLMatrix(rpl.view_matrix * rpl.cam_offset_matrix * o.itransform_);
// }
// glPolygonMode(GL_FRONT_AND_BACK, o.render_mode != ObjectBase::View ? o.render_mode : (view->rmode != ObjectBase::View ? view->rmode : GL_FILL));
// glLineWidth(o.line_width > 0.f ? o.line_width : view->lineWidth_);
// glPointSize(o.line_width > 0.f ? o.line_width : view->lineWidth_);
// o.draw((QOpenGLShaderProgram*)rpl.shaders, true);
// foreach (ObjectBase * i, o.children_)
// renderSingleShadow(*i, rpl);
}
GLRendererBase::RenderingParameters::RenderingParameters() {
shaders = nullptr;
cur_shader = nullptr;
}
void GLRendererBase::RenderingParameters::prepare() {
//proj_matrix = getGLMatrix(GL_PROJECTION_MATRIX);
//view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX);
viewproj_matrix = proj_matrix * view_matrix;
normal_matrix = view_matrix.normalMatrix();
proj_matrix_i = proj_matrix.inverted();
view_matrix_i = view_matrix.inverted();
viewproj_matrix_i = viewproj_matrix.inverted();
}
void GLRendererBase::RenderingParameters::setUniform(QOpenGLShaderProgram * prog) {
if (!prog) return;
prog->setUniformValue("qgl_ModelViewMatrix", view_matrix);
prog->setUniformValue("qgl_ProjectionMatrix", proj_matrix);
prog->setUniformValue("qgl_ModelViewProjectionMatrix", viewproj_matrix);
prog->setUniformValue("qgl_NormalMatrix", normal_matrix);
prog->setUniformValue("qgl_ModelViewMatrixInverse", view_matrix_i);
prog->setUniformValue("qgl_ProjectionMatrixInverse", proj_matrix_i);
prog->setUniformValue("qgl_ModelViewProjectionMatrixInverse", viewproj_matrix_i);
prog->setUniformValue("qgl_ModelViewMatrixTranspose", view_matrix.transposed());
prog->setUniformValue("qgl_ProjectionMatrixTranspose", proj_matrix.transposed());
prog->setUniformValue("qgl_ModelViewProjectionMatrixTranspose", viewproj_matrix.transposed());
prog->setUniformValue("qgl_ModelViewMatrixInverseTranspose", view_matrix_i.transposed());
prog->setUniformValue("qgl_ProjectionMatrixInverseTranspose", proj_matrix_i.transposed());
prog->setUniformValue("qgl_ModelViewProjectionMatrixInverseTranspose", viewproj_matrix_i.transposed());
}

View File

@@ -0,0 +1,80 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLRENDERERBASE_H
#define GLRENDERERBASE_H
#include "glcamera.h"
#include "glshaders.h"
class GLRendererBase: public QObject , protected QOpenGLExtraFunctions
{
friend class QGLView;
Q_OBJECT
public:
GLRendererBase(QGLView * view_);
virtual void prepareScene() {;}
virtual void renderScene() = 0;
struct RenderingParameters {
RenderingParameters();
void prepare();
void setUniform(QOpenGLShaderProgram * prog);
int pass;
int light_pass;
bool light;
bool fog;
bool textures;
bool prev_light;
bool prev_fog;
GLuint prev_tex[32];
void * shaders;
QMatrix4x4 view_matrix, view_matrix_i, prev_view_matrix;
QMatrix4x4 proj_matrix, proj_matrix_i, prev_proj_matrix;
QMatrix4x4 viewproj_matrix, viewproj_matrix_i;
QMatrix3x3 normal_matrix;
QMatrix4x4 cam_offset_matrix;
QOpenGLShaderProgram * cur_shader;
};
RenderingParameters rp;
protected:
virtual void setupLight(const Light & l, int inpass_index, int gl_index);
virtual void setupAmbientLight(const QColor & a, bool first_pass);
virtual void setupShadersLights(int lights_count);
virtual void setupTextures(ObjectBase & object, GLRendererBase::RenderingParameters & rp, bool first_object = false);
virtual void setupShadersTextures(ObjectBase & object, GLRendererBase::RenderingParameters & rp) {}
virtual void reloadShaders() {}
virtual void init(int width, int height) {}
virtual void resize(int width, int height) {}
void setupLights(int pass, int lights_per_pass);
inline void applyFilteringParameters();
void renderObjects(int pass, int light_pass, void * shaders = 0, bool textures = true, bool light = true, bool fog = true);
void renderSingleObject(ObjectBase & o, RenderingParameters & rpl);
void renderShadow(Light * l, QOpenGLShaderProgram * prog = 0, QMatrix4x4 mat = QMatrix4x4());
void renderSingleShadow(ObjectBase & o, RenderingParameters & rpl);
QGLView * view;
QImage white_image, violent_image;
GLuint white_image_id, violent_image_id;
};
#endif // GLRENDERERBASE_H

471
qglengine/glscene.cpp Normal file
View File

@@ -0,0 +1,471 @@
/*
GLObjectBase & Light
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "glscene.h"
#include "glcamera.h"
#include "glmesh.h"
#include "qglview.h"
#include <chunkstream.h>
Scene::Scene() {
root_ = new ObjectBase();
root_->setScene(this);
tree_changed = mat_changed = lights_changed = true;
destroying = false;
need_reload_materials = tree_struct_changed = true;
sel_mode_ = smSingleSelection;
}
Scene::~Scene() {
destroying = true;
destroy();
delete root_;
}
Scene * Scene::clone() {
Scene * ret = new Scene();
ObjectBase * o = root_->clone();
foreach (ObjectBase * co, o->children())
ret->addObject(co);
o->clearChildren();
delete o;
return ret;
}
void Scene::addObject(ObjectBase * o) {
QList<ObjectBase*> aol = o->children(true);
attachObject(o);
foreach (ObjectBase * c, aol)
attachObject(c);
root_->addChild(o);
tree_changed = tree_struct_changed = true;
}
void Scene::addScene(const Scene * s) {
if (!s) return;
//qDebug() << "addScene clone ...";
ObjectBase * o = s->root_->clone();
o->setName(s->name());
//qDebug() << "addScene clone ok" << o << o->children(true).size();
addObject(o);
makeMaterialsUniqueNames();
//qDebug() << "addScene add ok" << o;
}
void Scene::assignFrom(const Scene * s) {
destroy();
setName(s->name());
foreach (Material * m, s->materials) {
Material * nm = new Material();
*nm = *m;
nm->_changed = true;
nm->setMapsChanged();
materials << nm;
}
for (int i = 0; i < s->root_->childCount(); ++i) {
addObject(s->root_->child(i)->clone());
//qDebug() << i << o->child(i)->pos();
}
tree_changed = mat_changed = lights_changed = need_reload_materials = tree_struct_changed = true;
}
void Scene::objectsCountInternal(int * cnt, ObjectBase * where) {
++(*cnt);
foreach (ObjectBase * i, where->children_)
objectsCountInternal(cnt, i);
}
int Scene::objectsCount(bool all) {
if (!all) return root_->childCount();
int cnt = 0;
objectsCountInternal(&cnt, root_);
return cnt;
}
void Scene::removeObjectInternal(ObjectBase * o, ObjectBase * where) {
if (destroying) return;
foreach (ObjectBase * i, where->children_) {
if (o == i) {
where->removeChild(i);
setObjectMeshChanged(i);
} else
removeObjectInternal(o, i);
}
}
void Scene::emitSelectionChanged() {
selected_top.clear();
foreach (ObjectBase * o, selected_) {
ObjectBase * po = o->selectedParent();
if (!po) po = o;
if (!selected_top.contains(po))
selected_top << po;
}
foreach (Mesh * m, geometries)
m->selected_changed = true;
selectionChanged();
}
QString Scene::uniqueName(QString n, const QSet<QString> & names) {
if (!names.contains(n))
return n;
QString num;
while (!n.isEmpty()) {
if (n.right(1)[0].isDigit()) {
num.push_front(n.right(1));
n.chop(1);
} else break;
}
if (!n.endsWith('_')) n += '_';
int in = num.toInt() + 1;
QString nn = n + QString::number(in).rightJustified(3, '0');
while (names.contains(nn))
nn = n + QString::number(++in).rightJustified(3, '0');
return nn;
}
void Scene::removeObject(ObjectBase * o, bool inChildren) {
if (destroying) return;
o->setScene(nullptr);
setObjectMeshChanged(o);
if (inChildren)
removeObjectInternal(o, root_);
else
root_->removeChild(o);
__objectDeleted(o);
setTreeStructChanged();
}
void Scene::removeObject(ObjectBase & o, bool inChildren) {
if (destroying) return;
removeObject(&o, inChildren);
}
void Scene::clearObjects(bool deleteAll) {
root_->clearChildren(deleteAll);
setTreeStructChanged();
emitSelectionChanged();
}
void Scene::selectObject(ObjectBase * o, bool add_to_selection) {
//qDebug() << "selectObject" << o << add_to_selection;
if (!add_to_selection || (sel_mode_ == smSingleSelection)) clearSelection();
if (o) {
if (!add_to_selection) o->setSelected(true);
else o->setSelected(!o->isSelected());
gatherSelection();
}
foreach (Mesh * m, geometries)
m->selected_changed = true;
emitSelectionChanged();
}
void Scene::selectObjects(QList<ObjectBase *> ol, bool add_to_selection) {
if (!add_to_selection || (sel_mode_ == smSingleSelection)) clearSelection();
foreach (ObjectBase * o, ol) {
if (!o) continue;
o->setSelected(true);
}
gatherSelection();
foreach (Mesh * m, geometries)
m->selected_changed = true;
emitSelectionChanged();
}
void Scene::clearSelection() {
selected_.clear();
QList<ObjectBase * > ol = root_->children(true);
foreach (ObjectBase * o, ol) {
o->selected_ = false;
}
emitSelectionChanged();
}
QList<ObjectBase * > Scene::selectedObjects(bool top_only) const {
return top_only ? selected_top : selected_;
}
ObjectBase * Scene::selectedObject() const {
if (selected_.isEmpty()) return 0;
return selected_[0];
}
const Box3D & Scene::boundingBox() const {
root_->calculateBoundingBox();
return root_->boundingBox();
}
Material * Scene::newMaterial() {
materials << new Material();
makeMaterialsUniqueNames();
mat_changed = true;
return materials.back();
}
void Scene::removeMaterial(Material * m) {
if (!m || !materials.contains(m)) return;
QList<ObjectBase * > ol = root_->children(true);
foreach (ObjectBase * o, ol)
if (o->material_ == m)
o->setMaterial(0);
materials.removeAll(m);
materials_used.remove(m);
changed_materials.removeAll(m);
mat_changed = true;
}
void Scene::makeMaterialsUniqueNames() {
QSet<QString> names;
foreach (Material * m, materials) {
if (m->name.isEmpty()) m->name = "default_000";
m->name = uniqueName(m->name, names);
names << m->name;
}
}
QList<ObjectBase *> Scene::objects(bool all) {
return root_->children(all);
}
void Scene::removeLight(Light * l) {
removeObject(l);
}
void Scene::dump() {
qDebug() << "Scene" << name();
qDebug() << "Meshes:" << geometries.size();
qDebug() << "Objects:" << root_->children(true).size();
}
void Scene::gatherSelection() {
selected_.clear();
QList<ObjectBase * > ol = root_->children(true);
foreach (ObjectBase * o, ol)
if (o->selected_)
selected_ << o;
}
void Scene::attachObject(ObjectBase * o) {
if (!o) return;
o->setScene(this);
if (o->mesh()) { // search suitable mesh in this scene
uint ohash = o->mesh()->hash();
bool need_new = true;
foreach (Mesh * m, geometries) {
if (m == o->mesh()) { // already exists by ptr
need_new = false;
setObjectMeshChanged(o);
break;
}
if (m->hash() == ohash) { // already exists by hash
need_new = false;
o->setMesh(m);
break;
}
}
if (need_new) { // need to clone mesh and add to scene
Mesh * nmesh = o->mesh()->clone();
o->setMesh(nmesh);
geometries << nmesh;
}
}
if (o->material()) { // search suitable material in this scene
uint ohash = o->material()->hash();
bool need_new = true;
foreach (Material * m, materials) {
if (m == o->material()) { // already exists by ptr
need_new = false;
break;
}
if (m->hash() == ohash) { // already exists by hash
need_new = false;
o->setMaterial(m);
break;
}
}
if (need_new) { // need to clone material and add to scene
Material * nmat = new Material();
*nmat = *(o->material());
nmat->setMapsChanged();
o->setMaterial(nmat);
materials << nmat;
}
}
}
void Scene::setTreeChanged() {
if (destroying) return;
tree_changed = true;
foreach (Mesh * m, geometries)
m->selected_changed = true;
gatherSelection();
}
void Scene::setTreeStructChanged() {
tree_struct_changed = true;
}
void Scene::setObjectMeshChanged(ObjectBase * o) {
if (o) o->setMeshChanged();
}
void Scene::prepareTree(ObjectBase * o) {
foreach (ObjectBase * co, o->children_) {
if (co->isHidden()) continue;
switch (co->type_) {
case ObjectBase::glLight:
lights_used << globject_cast<Light * >(co);
break;
case ObjectBase::glMesh:
if (co->mesh()) {
geometries_used[co->mesh()] << co;
co->mesh()->objects_changed = co->mesh()->selected_changed = true;
}
break;
default: break;
}
prepareTree(co);
}
}
bool Scene::prepare() {
changed_materials.clear();
foreach (Material * m, materials) {
if (m->_changed) {
need_reload_materials = true;
changed_materials << m;
}
}
QList<ObjectBase*> aol;
if (!tree_changed && !mat_changed) return false;
aol = root_->children(true);
if (tree_changed) {
tree_changed = false;
lights_changed = true;
if (tree_struct_changed) {
tree_struct_changed = false;
QMetaObject::invokeMethod(this, "treeChanged", Qt::QueuedConnection);
}
geometries_used.clear();
lights_used.clear();
prepareTree(root_);
}
if (mat_changed) {
mat_changed = false;
materials_used.clear();
foreach (ObjectBase * o, aol) {
Material * m = o->material();
if (!m) continue;
materials_used << m;
}
}
return true;
}
void Scene::destroy() {
root_->clearChildren(true);
qDeleteAll(geometries);
qDeleteAll(materials);
geometries.clear();
materials.clear();
emit __destroyed();
emit treeChanged();
}
QDataStream & operator <<(QDataStream & s, const Scene * p) {
ChunkStream cs;
//qDebug() << "place" << p->name() << "...";
QVector<short> geom_ind, mat_ind;
QList<ObjectBase*> cl = p->root_->children(true);
geom_ind.reserve(cl.size());
mat_ind.reserve(cl.size());
foreach (ObjectBase * c, cl) {
geom_ind << p->geometries.indexOf(c->mesh());
mat_ind << p->materials.indexOf(c->material());
}
cs.add(1, p->name_).add(10, p->geometries).add(11, p->materials)
.add(20, p->root_).add(21, geom_ind).add(22, mat_ind);
s << qCompress(cs.data());
//s << cs.data();
return s;
}
QDataStream & operator >>(QDataStream & s, Scene *& p) {
p = new Scene();
//ChunkStream cs(s);
QByteArray ba;
s >> ba;
ba = qUncompress(ba);
ChunkStream cs(ba);
QVector<short> geom_ind, mat_ind;
while (!cs.atEnd()) {
switch (cs.read()) {
case 1 : cs.get(p->name_); break;
case 10: cs.get(p->geometries); break;
case 11: cs.get(p->materials); break;
case 20: cs.get(p->root_); p->root_->setScene(p); break;
case 21: cs.get(geom_ind); break;
case 22: cs.get(mat_ind); break;
}
}
p->makeMaterialsUniqueNames();
QList<ObjectBase*> cl = p->root_->children(true);
int cnt = qMin(qMin(cl.size(), geom_ind.size()), mat_ind.size());
for (int i = 0; i < cnt; ++i) {
ObjectBase * c(cl[i]);
if (geom_ind[i] >= 0) c->mesh_ = p->geometries[geom_ind[i]];
if (mat_ind [i] >= 0) c->material_ = p->materials [mat_ind [i]];
}
return s;
}

139
qglengine/glscene.h Normal file
View File

@@ -0,0 +1,139 @@
/*
GLObjectBase & Light
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLSCENE_H
#define GLSCENE_H
#include "gltypes.h"
class Scene: public QObject {
Q_OBJECT
friend class QGLView;
friend class RendererBase;
friend class Renderer;
friend class RendererMaterial;
friend class RendererService;
friend class ObjectBase;
friend class Light;
friend QDataStream & operator <<(QDataStream & s, const Scene * p);
friend QDataStream & operator >>(QDataStream & s, Scene *& p);
public:
explicit Scene();
virtual ~Scene();
enum SelectionMode {
smNoSelection,
smSingleSelection,
smMultiSelection,
};
Q_ENUMS(SelectionMode)
QString name() const {return name_;}
void setName(const QString & name) {name_ = name;}
bool prepare();
Scene * clone();
/// Add object \"o\" to scene and take its ownership
/// All materials and geometries used by \"o\" tree
/// copied into this scene
void addObject(ObjectBase * o);
void addScene(const Scene * s);
void assignFrom(const Scene * s);
int objectsCount(bool all = false);
QList<ObjectBase * > objects(bool all = false);
ObjectBase * rootObject() {return root_;}
void removeObject(ObjectBase * o, bool inChildren = true);
void removeObject(ObjectBase & o, bool inChildren = true);
void clearObjects(bool deleteAll = false);
SelectionMode selectionMode() const {return sel_mode_;}
void setSelectionMode(SelectionMode mode) {sel_mode_ = mode;}
void selectObject(ObjectBase * o, bool add_to_selection = false);
void selectObjects(QList<ObjectBase * > ol, bool add_to_selection = false);
void clearSelection();
QList<ObjectBase * > selectedObjects(bool top_only = false) const;
ObjectBase * selectedObject() const;
const Box3D & boundingBox() const;
QVector<Material*> getMaterials() const {return materials;}
Material * newMaterial();
void removeMaterial(Material * m);
void makeMaterialsUniqueNames();
void removeLight(Light * l);
void dump();
void destroy();
protected:
void prepareTree(ObjectBase * o);
void gatherSelection();
void objectsCountInternal(int * cnt, ObjectBase * where);
void removeObjectInternal(ObjectBase * o, ObjectBase * where);
void emitSelectionChanged();
QString uniqueName(QString n, const QSet<QString> & names);
void attachObject(ObjectBase * o);
void setTreeChanged();
void setTreeStructChanged();
void setMaterialsChanged() {mat_changed = true;}
void setLightsChanged() {lights_changed = true;}
void setObjectMeshChanged(ObjectBase * o);
QString name_;
ObjectBase * root_;
bool tree_changed, mat_changed, lights_changed, destroying;
bool need_reload_materials, tree_struct_changed;
QVector<bool> mat_map_changed;
QVector<Mesh*> geometries;
QVector<Material*> materials;
QMap<Mesh*, QList<ObjectBase*> > geometries_used;
QSet<Material*> materials_used;
QList<Light*> lights_used;
QVector<Material*> changed_materials;
SelectionMode sel_mode_;
QList<ObjectBase*> selected_, selected_top;
protected slots:
signals:
void __objectDeleted(ObjectBase * o);
void __destroyed();
void treeChanged();
//void treeStructChanged();
void selectionChanged();
};
QDataStream & operator <<(QDataStream & s, const Scene * p);
QDataStream & operator >>(QDataStream & s, Scene *& p);
#endif // GLSCENE_H

182
qglengine/glshaders.cpp Normal file
View File

@@ -0,0 +1,182 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gltypes.h"
#include "qglview.h"
#include "glshaders.h"
#include "glshaders_headers.h"
using namespace QGLEngineShaders;
bool addShader(QOpenGLShaderProgram * prog, QOpenGLShader::ShaderType type, QString & content, const QString & file) {
if (type == 0 || content.isEmpty()) {
content.clear();
return true;
}
//qDebug() << "[QGLView] Shader" << file << "found" << (QOpenGLShader::ShaderTypeBit)(int)type << "section ...";
switch (type) {
case QOpenGLShader::Fragment:
content.prepend(qgl_fragment_head);
content.prepend(qgl_uniform);
content.prepend(qgl_structs);
break;
case QOpenGLShader::Vertex :
content.prepend(qgl_vertex_head );
break;
case QOpenGLShader::Geometry:
content.prepend(qgl_geometry_head);
break;
}
content.prepend(qgl_common_head);
bool ret = prog->addShaderFromSourceCode(type, content.toLatin1());
if (!ret) qDebug() << "[QGLView] Shader" << file << "Compile error:\n" << prog->log();
content.clear();
return ret;
}
bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog, const QString & file) {
if (!prog)
prog = new QOpenGLShaderProgram();
prog->removeAllShaders();
QFile f(file);
if (!f.open(QIODevice::ReadOnly)) return false;
QTextStream ts(&f);
QString cur_shader, line, pl;
QOpenGLShader::ShaderType type = 0;
while (!ts.atEnd()) {
line = ts.readLine();
pl = line.trimmed().remove(' ').remove('\t').mid(2).toLower();
pl.chop(2);
if (pl == "vertex" || pl == "vert") {
if (!addShader(prog, type, cur_shader, file)) return false;
type = QOpenGLShader::Vertex;
continue;
}
if (pl == "fragment" || pl == "frag") {
if (!addShader(prog, type, cur_shader, file)) return false;
type = QOpenGLShader::Fragment;
continue;
}
if (pl == "geometry" || pl == "geom") {
if (!addShader(prog, type, cur_shader, file)) return false;
type = QOpenGLShader::Geometry;
continue;
}
if (pl == "tessellation_control") {
if (!addShader(prog, type, cur_shader, file)) return false;
type = QOpenGLShader::TessellationControl;
continue;
}
if (pl == "tessellation_evaluation") {
if (!addShader(prog, type, cur_shader, file)) return false;
type = QOpenGLShader::TessellationEvaluation;
continue;
}
cur_shader.append("\n");
cur_shader.append(line);
}
if (!addShader(prog, type, cur_shader, file)) return false;
/// WARNING
/*prog->bindAttributeLocation("qgl_Vertex" , 1 );
prog->bindAttributeLocation("qgl_Normal" , 2 );
prog->bindAttributeLocation("qgl_Tangent" , 3 );
prog->bindAttributeLocation("qgl_Bitangent" , 4 );
prog->bindAttributeLocation("qgl_Texture" , 5 );
prog->bindAttributeLocation("qgl_Material" , 6 );
prog->bindAttributeLocation("qgl_Color" , 7 );
prog->bindAttributeLocation("qgl_ModelViewMatrix" , 8 );
prog->bindAttributeLocation("qgl_ModelViewProjectionMatrix", 12);
prog->bindAttributeLocation("qgl_NormalMatrix" , 16);*/
if (!prog->link()) {
qDebug() << "[QGLView] Shader" << file << "Link error:\n" << prog->log();
return false;
}
qDebug() << "[QGLView] Shader" << file << "ok";
return true;
}
void QGLEngineShaders::setUniformMatrices(QOpenGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj, QMatrix4x4 prevview) {
if (!prog) return;
if (!prog->isLinked()) return;
QMatrix4x4 mvpm = proj * view;
QMatrix4x4 pmvpm = prevproj * prevview;
QMatrix3x3 nm = view.normalMatrix();
//nm.in;
prog->setUniformValue("qgl_ModelViewMatrix", view);
prog->setUniformValue("qgl_ProjectionMatrix", proj);
prog->setUniformValue("prev_ModelViewProjectioMatrix", pmvpm);
prog->setUniformValue("prev_ModelViewMatrix", prevview);
prog->setUniformValue("qgl_ModelViewProjectionMatrix", mvpm);
prog->setUniformValue("qgl_NormalMatrix", nm);
//prog->setUniformValue("qgl_BumpMatrix", nm.);
prog->setUniformValue("qgl_ModelViewMatrixTranspose", view.transposed());
prog->setUniformValue("qgl_ProjectionMatrixTranspose", proj.transposed());
prog->setUniformValue("qgl_ModelViewProjectionMatrixTranspose", mvpm.transposed());
}
void QGLEngineShaders::setUniformLights(QOpenGLShaderProgram * prog, const QVector<Light*> & lights, const QMatrix4x4 & mat, int shadow_start) {
for (int i = 0; i < lights.size(); ++i)
;//setUniformLight(prog, lights[i], QString("qgl_Light[%1]").arg(i), mat, shadow_start + i);
}
/*
" vec3 position;\n"
" vec3 direction;\n"
" vec4 color;\n"
" float intensity;\n"
" float startAngle;\n"
" float endAngle;\n"
" float constantAttenuation;\n"
" float linearAttenuation;\n"
" float quadraticAttenuation;\n"
" sampler2DShadow shadow;\n"
" mat4 shadowMatrix;\n"
*/
void QGLEngineShaders::setUniformLight(QOpenGLShaderProgram * prog, Light * light, QString ulightn, const QMatrix4x4 & mat, int shadow) {
if (!prog) return;
if (!prog->isLinked()) return;
QMatrix4x4 m = mat * light->worldTransform();
QVector4D pos(0, 0, 0, 1.), dir(light->direction, 1);//, dir0(light->dir0), dir1(light->dir1);
pos = m * pos;
dir = ((m * dir) - pos).normalized();
float ang_start = light->angle_start / 2.f, ang_end = light->angle_end / 2.f;
if (light->light_type == Light::Omni)
ang_start = ang_end = 180.;
//qDebug() << "light" << light->name() << ulightn << pos;
prog->setUniformValue((ulightn + ".position").toLatin1().constData(), pos);
prog->setUniformValue((ulightn + ".direction").toLatin1().constData(), dir);
prog->setUniformValue((ulightn + ".intensity").toLatin1().constData(), GLfloat(light->intensity));
prog->setUniformValue((ulightn + ".startAngle").toLatin1().constData(), GLfloat(ang_start));
prog->setUniformValue((ulightn + ".startAngleCos").toLatin1().constData(), GLfloat(cosf(ang_start * deg2rad)));
prog->setUniformValue((ulightn + ".endAngle").toLatin1().constData(), GLfloat(ang_end));
prog->setUniformValue((ulightn + ".endAngleCos").toLatin1().constData(), GLfloat(cosf(ang_end * deg2rad)));
//prog->setUniformValue((ulightn + ".color").toLatin1().constData(), light->color());
prog->setUniformValue((ulightn + ".constantAttenuation").toLatin1().constData(), GLfloat(light->decay_const));
prog->setUniformValue((ulightn + ".linearAttenuation").toLatin1().constData(), GLfloat(light->decay_linear));
prog->setUniformValue((ulightn + ".quadraticAttenuation").toLatin1().constData(), GLfloat(light->decay_quadratic));
prog->setUniformValue((ulightn + ".shadow").toLatin1().constData(), shadow);
prog->setUniformValue((ulightn + ".shadowColor").toLatin1().constData(), shadow);
prog->setUniformValue((ulightn + ".shadowMatrix").toLatin1().constData(), light->shadow_matrix);
//qDebug() << light->shadow_matrix;
//prog->setUniformValue((ulightn + ".shadowDir0").toLatin1().constData(), (mat * dir0));
//prog->setUniformValue((ulightn + ".shadowDir1").toLatin1().constData(), (mat * dir1));
//qDebug() << light->direction << light->dir0 << light->dir1;
}

34
qglengine/glshaders.h Normal file
View File

@@ -0,0 +1,34 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLSHADERS_H
#define GLSHADERS_H
#include "gltypes.h"
namespace QGLEngineShaders {
bool loadShadersMulti(QOpenGLShaderProgram *& prog, const QString & file);
void setUniformMatrices(QOpenGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj = QMatrix4x4(), QMatrix4x4 prevview = QMatrix4x4());
void setUniformLights(QOpenGLShaderProgram * prog, const QVector<Light*> & lights, const QMatrix4x4 & mat, int shadow_start);
void setUniformLight(QOpenGLShaderProgram * prog, Light * light, QString ulightn, const QMatrix4x4 & mat = QMatrix4x4(), int shadow = 0);
}
#endif // GLSHADERS_H

View File

@@ -0,0 +1,133 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLSHADERS_HEADERS_H
#define GLSHADERS_HEADERS_H
namespace QGLEngineShaders {
const int max_materials = 128;
const int max_lights = 64 ;
const char qgl_common_head[] =
"#version 400 core\n"
//"#extension GL_EXT_texture_aray: require\n"
"";
const char qgl_vertex_head[] =
"layout(location = 1 ) in vec3 qgl_Vertex ;\n"
"layout(location = 2 ) in vec3 qgl_Normal ;\n"
"layout(location = 3 ) in vec3 qgl_Tangent ;\n"
"layout(location = 4 ) in vec3 qgl_Bitangent ;\n"
"layout(location = 5 ) in vec2 qgl_Texture ;\n"
"layout(location = 6 ) in uint qgl_Material ;\n"
"layout(location = 7 ) in uint qgl_ObjectSelected;\n"
"layout(location = 8 ) in uint qgl_ObjectID ;\n"
"layout(location = 9 ) in vec4 qgl_ObjectColor ;\n"
"layout(location = 10) in mat4 qgl_ModelMatrix ;\n"
"out vec2 qgl_FragTexture;\n"
"flat out uint qgl_MaterialIndex;\n"
"uniform mat4 qgl_ViewMatrix;\n"
"uniform mat4 qgl_ViewProjMatrix;\n"
"mat3 qgl_getNormalMatrix() {return mat3(qgl_ViewMatrix * qgl_ModelMatrix);}\n"
"vec4 qgl_ftransform() {return qgl_ViewProjMatrix * (qgl_ModelMatrix * vec4(qgl_Vertex, 1));}\n"
"";
const char qgl_fragment_head[] =
"in vec2 qgl_FragTexture;\n"
"flat in uint qgl_MaterialIndex;\n"
"out vec4 qgl_FragData[gl_MaxDrawBuffers];\n"
"vec4 qgl_materialTexture(uint type, vec2 coord, vec4 tex_shift) {\n"
" coord *= qgl_material[qgl_MaterialIndex].map[type].scale;\n"
" vec4 t = texture(qgl_texture_array[qgl_material[qgl_MaterialIndex].map[type].array_index],\n"
" vec3(coord, qgl_material[qgl_MaterialIndex].map[type].map_index));\n"
" t += tex_shift;\n"
" t = t * qgl_material[qgl_MaterialIndex].map[type].amount + qgl_material[qgl_MaterialIndex].map[type].offset;\n"
" return t;\n"
"}\n"
"#define qgl_FragColor qgl_FragData[0]\n"
"";
const char qgl_geometry_head[] =
"";
const char qgl_structs[] =
"#define QGL_MAPS_COUNT 6\n"
"#define QGL_MAP_DIFFUSE 0\n"
"#define QGL_MAP_NORMAL 1\n"
"#define QGL_MAP_SPECULAR 2\n"
"#define QGL_MAP_ROUGHNESS 3\n"
"#define QGL_MAP_EMISSION 4\n"
"#define QGL_MAP_RELIEF 5\n"
"#define QGL_TEXTURE_ARRAY_EMPTY 0\n"
"#define QGL_TEXTURE_ARRAY_MAPS 1\n"
"struct QGLMap {\n"
" float offset;\n"
" float amount;\n"
" vec2 scale;\n"
" uint array_index;\n"
" uint map_index;\n"
"};\n"
"struct QGLMaterial {\n"
" vec4 color_diffuse;\n"
" vec4 color_specular;\n"
" vec4 color_emission;\n"
" float transparency;\n"
" float reflectivity;\n"
" float iof;\n"
" float dispersion;\n"
" QGLMap map[QGL_MAPS_COUNT];\n"
"};\n"
"struct QGLLightParameter {\n"
" vec4 color;\n"
" float intensity;\n"
" float startAngle;\n"
" float startAngleCos;\n"
" float endAngle;\n"
" float endAngleCos;\n"
" float constantAttenuation;\n"
" float linearAttenuation;\n"
" float quadraticAttenuation;\n"
//" sampler2DShadow shadow;\n"
//" sampler2D shadowColor\n"
//" mat4 shadowMatrix;\n"
//" vec4 shadowDir0;\n"
//" vec4 shadowDir1;\n"
"};\n"
"struct QGLLightPosition {\n"
" vec4 position;\n"
" vec4 direction;\n"
"};\n"
"";
const char qgl_uniform[] =
"layout (std140) uniform QGLMaterialData {\n"
" QGLMaterial qgl_material[128];\n"
"};\n"
"layout (std140) uniform QGLLightParameterData {\n"
" QGLLightParameter qgl_light_parameter[64];\n"
"};\n"
"layout (std140) uniform QGLLightPositionData {\n"
" QGLLightPosition qgl_light_position[64];\n"
"};\n"
"uniform sampler2DArray qgl_texture_array[2];\n"
"";
}
#endif // GLSHADERS_HEADERS_H

View File

@@ -0,0 +1,41 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "glshaders_types.h"
QGLEngineShaders::QGLMap::QGLMap() {
offset = 0.;
amount = 1.;
scale = QVector2D(1., 1.);
array_index = map_index = 0;
}
QGLEngineShaders::QGLMaterial::QGLMaterial() {
color_diffuse = QVector4D(.5, .5, .5, 0.);
color_specular = QVector4D(.5, .5, .5, 0.);
color_emission = QVector4D(0., 0., 0., 0.);
transparency = 0.;
reflectivity = 0.;
iof = 0.;
dispersion = 0.;
map[mtNormal].map_index = emrBlue;
map[mtRoughness].amount = 0.75;
}

148
qglengine/glshaders_types.h Normal file
View File

@@ -0,0 +1,148 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLSHADERS_TYPES_H
#define GLSHADERS_TYPES_H
#include "gltypes.h"
namespace QGLEngineShaders {
/// VBO
// geometry
const GLsizei pos_offset = 0;
const GLsizei normal_offset = sizeof(QVector3D) + pos_offset ;
const GLsizei tangent_offset = sizeof(QVector3D) + normal_offset ;
const GLsizei bitangent_offset = sizeof(QVector3D) + tangent_offset ;
const GLsizei tex_offset = sizeof(QVector3D) + bitangent_offset;
// object
const GLsizei material_offset = 0;
const GLsizei object_id_offset = sizeof(GLuint ) + material_offset ;
const GLsizei color_offset = sizeof(GLuint ) + object_id_offset ;
const GLsizei modelmatrix_offset = sizeof(QVector4D) + color_offset;
const GLsizei is_selected_offset = 0;
const GLuint pos_loc = 1 ; // qgl_Vertex
const GLuint normal_loc = 2 ; // qgl_Normal
const GLuint tangent_loc = 3 ; // qgl_Tangent
const GLuint bitangent_loc = 4 ; // qgl_Bitangent
const GLuint tex_loc = 5 ; // qgl_Texture
const GLuint material_loc = 6 ; // qgl_Material
const GLuint object_id_loc = 8 ; // qgl_ObjectID
const GLuint color_loc = 9 ; // qgl_ObjectColor
const GLuint modelmatrix_loc = 10; // qgl_ModelViewProjectionMatrix
const GLuint is_selected_loc = 7 ; // qgl_ObjectSelected
#pragma pack(push, 1)
struct Vertex {
QVector3D pos;
QVector3D normal;
QVector3D tangent;
QVector3D bitangent;
QVector2D tex;
};
struct Object {
Object() {
material = object_id = 0;
color = QVector4D(1,1,1,1);
QMatrix4x4().copyDataTo(modelmatrix);
}
GLuint material;
GLuint object_id;
QVector4D color;
GLfloat modelmatrix[16];
};
#pragma pack(pop)
/// UBO
enum BindingPoints {
bpMaterials,
bpLightParameters,
bpLightPositions,
};
enum MapType {
mtDiffuse = 0,
mtNormal = 1,
mtSpecular = 2,
mtRoughness = 3,
mtEmission = 4,
mtRelief = 5,
};
enum TextureArrayRole {
tarEmpty = 0,
tarMaps = 1,
};
enum EmptyMapRole {
emrWhite = 0,
emrBlue = 1,
};
#define QGL_MAPS_COUNT 6
#pragma pack(push, 1)
struct QGLMap {
QGLMap();
GLfloat offset;
GLfloat amount;
QVector2D scale;
GLuint array_index;
GLuint map_index;
GLfloat __res_2[2];
};
struct QGLMaterial {
QGLMaterial();
QVector4D color_diffuse;
QVector4D color_specular;
QVector4D color_emission;
GLfloat transparency;
GLfloat reflectivity;
GLfloat iof;
GLfloat dispersion;
QGLMap map[QGL_MAPS_COUNT];
};
struct QGLLightParameter {
QVector4D color;
//QVector4D shadowColor;
GLfloat intensity;
GLfloat startAngle;
GLfloat startAngleCos;
GLfloat endAngle;
GLfloat endAngleCos;
GLfloat constantAttenuation;
GLfloat linearAttenuation;
GLfloat quadraticAttenuation;
//GLfloat shadow;
//GLfloat shadowMatrix[16];
};
struct QGLLightPosition {
QVector4D position;
QVector4D direction;
};
#pragma pack(pop)
}
#endif // GLSHADERS_TYPES_H

View File

@@ -0,0 +1,201 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gltexture_manager.h"
#include "gltypes.h"
QStringList TextureManager::search_pathes(".");
QVector3D colorVector(QRgb c) {
return QVector3D(((uchar*)(&c))[0] / 255.f, ((uchar*)(&c))[1] / 255.f, ((uchar*)(&c))[2] / 255.f);
}
QString TextureManager::findFile(const QString & path) {
return ::findFile(path, search_pathes);
}
GLuint TextureManager::loadTexture(const QString & path, bool ownership, bool bump) {
QString p = findFile(path);
if (p.isEmpty()) return 0;
int tid = textureID(p, bump);
if (tid > 0) {
//qDebug() << "[TextureManager] Found" << path << "as" << tid;
return tid;
}
QImage image(p);
if (bump) convertToNormal(image);
//qDebug() << p << image.width() << image.height() << image.format() << bump;
GLuint tid_ = tid;
createGLTexture(f, tid_, image);///currentQGLView->bindTexture(image, GL_TEXTURE_2D);
tid = tid_;
if (tid == 0) {
qDebug() << "[TextureManager] Can`t load" << p;
return tid;
}
qDebug() << "[TextureManager] Loaded" << p << "as" << tid;
if (ownership) {
tex_ids[bump ? 1 : 0].insert(p, tid);
tex_im [bump ? 1 : 0].insert(p, image);
}
return tid;
}
GLuint TextureManager::loadTexture(const QImage & im, bool ownership, bool bump) {
if (im.isNull()) return 0;
QImage image(im);
if (bump) convertToNormal(image);
GLuint tid = 0;
createGLTexture(f, tid, im);///currentQGLView->bindTexture(image, GL_TEXTURE_2D);
if (tid == 0) {
qDebug() << "[TextureManager] Can`t load image";
return tid;
}
//qDebug() << "[TextureManager] Loaded image as" << tid;
return tid;
}
QImage TextureManager::loadTextureImage(const QString & path, bool bump) {
QString p = findFile(path);
if (p.isEmpty()) return QImage();
QImage ret = tex_im[bump ? 1 : 0].value(p);
if (!ret.isNull()) return ret;
ret = QImage(p);
if (bump) convertToNormal(ret);
tex_im[bump ? 1 : 0].insert(p, ret);
return ret;
}
void TextureManager::reloadTexture(GLuint tid, const QString & path) {
QString p = findFile(path);
if (p.isEmpty() || (tid == 0)) return;
QImage image(p);
createGLTexture(f, tid, image);
if (tid == 0) {
qDebug() << "[TextureManager] Can`t load" << p;
return;
}
qDebug() << "[TextureManager] Reloaded" << p << "as" << tid;
}
void TextureManager::reloadTexture(GLuint tid, const QImage & im) {
if (im.isNull() || (tid == 0)) return;
QImage image(im);
createGLTexture(f, tid, image);
qDebug() << "[TextureManager] Reloaded" << tid;
}
void TextureManager::convertToNormal(QImage & im) {
if (im.isNull()) return;
QImage sim = im.convertToFormat(QImage::Format_ARGB32);
float sum[3] = {0., 0., 0.};
llong a = 0;
const uchar * sd = sim.constBits();
for (int i = 0; i < sim.height(); i++) {
for (int j = 0; j < sim.width(); j++) {
sum[2] += sd[a] / 255.f - 0.5f; ++a;
sum[1] += sd[a] / 255.f - 0.5f; ++a;
sum[0] += sd[a] / 255.f - 0.5f; ++a;
++a;
}
}
float wh = sim.width() * sim.height();
sum[0] /= wh;
sum[1] /= wh;
sum[2] /= wh;
//qDebug() << sum[0] << sum[1] << sum[2];
if ((qAbs(sum[0]) <= 0.05f) && (qAbs(sum[1]) <= 0.05f) && (sum[2] >= 0.25f)) /// already normal
return;
//qDebug() << "convert to normal";
QImage dim = QImage(sim.width(), sim.height(), QImage::Format_ARGB32);
int tx, ty, w = sim.width(), h = sim.height();
a = 0;
uchar * dd = dim.bits();
for (int i = 0; i < sim.height(); i++) {
for (int j = 0; j < sim.width(); j++) {
tx = j - 1;
tx = tx < 0 ? w + tx : tx % w;
ty = i - 1;
ty = ty < 0 ? h + ty : ty % h;
QVector3D p[3], res;
p[0] = colorVector(sim.pixel(j, i));
p[1] = colorVector(sim.pixel(j, ty));
p[2] = colorVector(sim.pixel(tx, i));
res.setY(piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f));
res.setX(piClamp(0.5f - (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f));
tx = (j + 1) % w;
ty = (i + 1) % h;
p[1] = colorVector(sim.pixel(j, ty));
p[2] = colorVector(sim.pixel(tx, i));
res.setY(piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f));
res.setX(piClamp(0.5f - (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f));
res.setZ(1.f);
dd[a] = res.z() * 255; ++a;
dd[a] = res.y() * 255; ++a;
dd[a] = res.x() * 255; ++a;
dd[a] = 255; ++a;
}
}
im = dim;
//im.save("_normal.png");
}
bool TextureManager::loadTextures() {
QFileInfoList fil;
foreach (const QString & i, tex_pathes)
loadTexture(i, true);
tex_pathes.clear();
return true;
}
void TextureManager::deleteTextures() {
for (int i = 0; i < 2; ++i) {
QList<GLuint> texs = tex_ids[i].values();
qDebug() << "[TextureManager] Delete" << texs.size() << "textures";
if (!texs.isEmpty()) f->glDeleteTextures(texs.size(), &texs[0]);
tex_ids[i].clear();
tex_im [i].clear();
}
}
void TextureManager::deleteTexture(const QString & name) {
for (int i = 0; i < 2; ++i) {
if (tex_ids[i].contains(name)) {
GLuint id = tex_ids[i][name];
f->glDeleteTextures(1, &id);
tex_ids[i].remove(name);
tex_im [i].remove(name);
}
}
}
void TextureManager::clearImageCache() {
tex_im[0].clear();
tex_im[1].clear();
}

View File

@@ -0,0 +1,64 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLTEXTUREMANAGER_H
#define GLTEXTUREMANAGER_H
#include <QOpenGLExtraFunctions>
#include <QDir>
#include <QMap>
#include <QFileInfo>
#include <QImage>
class TextureManager {
public:
TextureManager(QOpenGLExtraFunctions * f_): f(f_) {}
virtual ~TextureManager() {}
void addSearchPath(const QString & path) {search_pathes << path;}
static QStringList searchPathes() {return search_pathes;}
QString findFile(const QString & path);
GLuint loadTexture(const QString & path, bool ownership = true, bool bump = false);
GLuint loadTexture(const QImage & image, bool ownership = true, bool bump = false);
QImage loadTextureImage(const QString & path, bool bump = false);
void reloadTexture(GLuint tid, const QString & path);
void reloadTexture(GLuint tid, const QImage & image);
int textureID (const QString & path, bool bump = false) {return tex_ids[bump ? 1 : 0][path];}
QImage textureImage(const QString & path, bool bump = false) {return tex_im [bump ? 1 : 0][path];}
void addTexture(const QString & path) {tex_pathes << path;}
bool loadTextures();
void deleteTextures();
void deleteTexture(const QString & name);
void clearImageCache();
protected:
static void convertToNormal(QImage & im);
static QStringList search_pathes;
QMap<QString, GLuint> tex_ids[2];
QMap<QString, QImage> tex_im [2];
QStringList tex_pathes;
QOpenGLExtraFunctions * f;
};
#endif // GLTEXTUREMANAGER_H

View File

@@ -0,0 +1,96 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "gltexturearray.h"
Texture2DArray::Texture2DArray(bool filter) {
target_ = GL_TEXTURE_2D_ARRAY;
texture_ = 0;
layers_ = 0;
filtering_ = filter;
}
Texture2DArray::~Texture2DArray() {
}
void Texture2DArray::init(QOpenGLExtraFunctions * f) {
if (!isInit()) {
f->glGenTextures(1, &texture_);
}
}
void Texture2DArray::destroy(QOpenGLExtraFunctions * f) {
if (texture_ != 0) {
f->glDeleteTextures(1, &texture_);
}
texture_ = 0;
}
void Texture2DArray::bind(QOpenGLExtraFunctions * f, int channel) {
f->glActiveTexture(GL_TEXTURE0 + channel);
f->glBindTexture(target_, texture_);
}
void Texture2DArray::release(QOpenGLExtraFunctions * f) {
f->glBindTexture(target_, 0);
}
bool Texture2DArray::resize(QOpenGLExtraFunctions * f, QSize new_size, int layers_count) {
if (new_size.isNull() || layers_count <= 0) return false;
if ((size_ == new_size) && (layers_ >= layers_count)) return false;
size_ = new_size;
layers_ = layers_count;
f->glBindTexture(target_, texture_);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_REPEAT);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (filtering_) {
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
f->glTexParameteri(target_, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
} else {
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
f->glTexImage3D(target_, 0, GL_RGBA8, size_.width(), size_.height(), layers_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
return true;
}
void Texture2DArray::load(QOpenGLExtraFunctions * f, const QImage & image, int layer) {
if (image.isNull() || size_.isNull() || layer < 0 || layer >= layers_) return;
QImage im = image.mirrored(false, true)
.scaled(size_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)
.convertToFormat(QImage::Format_RGBA8888);
//qDebug() << "Texture2DArray::load image" << image.size() << "to layer" << layer;
f->glTexSubImage3D(target_, 0, 0, 0, layer, size_.width(), size_.height(), 1, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
}
void Texture2DArray::mipmaps(QOpenGLExtraFunctions * f) {
f->glBindTexture(target_, texture_);
f->glGenerateMipmap(target_);
}

View File

@@ -0,0 +1,56 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLTEXTUREARRAY_H
#define GLTEXTUREARRAY_H
#include "gltypes.h"
class Texture2DArray
{
friend class ObjectBase;
public:
Texture2DArray(bool filter);
~Texture2DArray();
void init (QOpenGLExtraFunctions * f);
void destroy (QOpenGLExtraFunctions * f);
void bind (QOpenGLExtraFunctions * f, int channel = 0);
void release (QOpenGLExtraFunctions * f);
// returns true if size changed
bool resize (QOpenGLExtraFunctions * f, QSize new_size, int layers_count);
void load (QOpenGLExtraFunctions * f, const QImage & image, int layer);
void mipmaps (QOpenGLExtraFunctions * f);
GLuint ID() const {return texture_;}
bool isInit() const {return texture_ != 0;}
private:
GLenum target_;
GLuint texture_;
QSize size_;
int layers_;
bool filtering_;
};
#endif // GLTEXTUREARRAY_H

365
qglengine/gltypes.cpp Normal file
View File

@@ -0,0 +1,365 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "glcamera.h"
#include "qglview.h"
#include "gltexture_manager.h"
#include <QPainter>
//__GLWidget__ * currentQGLView;
//QMutex globMutex;
QString readCharsUntilNull(QDataStream & s) {
QString str;
char ch;
s.readRawData(&ch, 1);
while (ch != '\0') {
str += ch;
s.readRawData(&ch, 1);
}
return str;
}
QString findFile(const QString & file, const QStringList & pathes) {
QFileInfo fi(QString(file).replace("\\", "/"));
//qDebug() << "search" << file << "in" << pathes;
if (fi.exists()) return fi.absoluteFilePath();
QString fn = fi.fileName();
if (fn.contains("/")) fn = fn.mid(fn.lastIndexOf("/"));
foreach (QString p, pathes) {
QFileInfoList fil = QDir(p).entryInfoList(QStringList(fn), QDir::Files | QDir::NoDotAndDotDot);
//qDebug() << "findFile" << fn << "in" << p << "->" << fil.size();
if (!fil.isEmpty())
return fil[0].absoluteFilePath();
}
return QString();
}
void glDrawQuad(QOpenGLShaderProgram * prog, QVector4D * corner_dirs, GLfloat x, GLfloat y, GLfloat w, GLfloat h) {
//glResetAllTransforms();
glSetPolygonMode(GL_FILL);
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
int loc = prog ? prog->attributeLocation("qgl_Color") : -1,
locv = prog ? prog->attributeLocation("qgl_Vertex") : -1,
loct = prog ? prog->attributeLocation("qgl_Texture") : -1,
locc = prog ? prog->attributeLocation("view_corner") : -1;
//if (prog) {qDebug() << locv << loct << locc;}
QOpenGLFunctions * glFuncs = QOpenGLContext::currentContext()->functions();
if (prog) {
static const GLfloat cols [] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
static const GLfloat verts[] = {x, y, x+w, y, x, y+h, x+w, y+h};
static const GLfloat texs [] = {0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f};
GLfloat vcs[] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
if (corner_dirs) {
vcs[0] = corner_dirs[0].x(); vcs[1] = corner_dirs[0].y(); vcs[2] = corner_dirs[0].z();
vcs[3] = corner_dirs[1].x(); vcs[4] = corner_dirs[1].y(); vcs[5] = corner_dirs[1].z();
vcs[6] = corner_dirs[2].x(); vcs[7] = corner_dirs[2].y(); vcs[8] = corner_dirs[2].z();
vcs[9] = corner_dirs[3].x(); vcs[10] = corner_dirs[3].y(); vcs[11] = corner_dirs[3].z();
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glFuncs->glBindBuffer(GL_ARRAY_BUFFER, 0);
glFuncs->glEnableVertexAttribArray(loc);
glFuncs->glVertexAttribPointer(loc, 3, GL_FLOAT, 0, 0, cols);
glFuncs->glEnableVertexAttribArray(locv);
glFuncs->glVertexAttribPointer(locv, 2, GL_FLOAT, 0, 0, verts);
glFuncs->glEnableVertexAttribArray(loct);
glFuncs->glVertexAttribPointer(loct, 2, GL_FLOAT, 0, 0, texs);
glFuncs->glEnableVertexAttribArray(locc);
glFuncs->glVertexAttribPointer(locc, 3, GL_FLOAT, 0, 0, vcs);
glFuncs->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glFuncs->glDisableVertexAttribArray(loc);
glFuncs->glDisableVertexAttribArray(locv);
glFuncs->glDisableVertexAttribArray(loct);
glFuncs->glDisableVertexAttribArray(locc);
} else {
glBegin(GL_TRIANGLE_STRIP);
glColor4f(1.f, 1.f, 1.f, 1.f);
glTexCoord2f(0.f, 0.f); glVertex2f(x, y);
glTexCoord2f(1.f, 0.f); glVertex2f(x+w, y);
glTexCoord2f(0.f, 1.f); glVertex2f(x, y+h);
glTexCoord2f(1.f, 1.f); glVertex2f(x+w, y+h);
glEnd();
}
}
QMatrix4x4 getGLMatrix(GLenum matrix) {
GLfloat gm[16];
glGetFloatv(matrix, gm);
float qm[16];
for (int i = 0; i < 16; ++i)
qm[i] = gm[i];
return QMatrix4x4(qm).transposed();
}
void setGLMatrix(QMatrix4x4 matrix) {
GLfloat gm[16];
float qm[16];
matrix.transposed().copyDataTo(qm);
for (int i = 0; i < 16; ++i)
gm[i] = qm[i];
glLoadMatrixf(gm);
}
void qglMultMatrix(const QMatrix4x4 & m) {
GLfloat gm[16];
float qm[16];
m.transposed().copyDataTo(qm);
for (int i = 0; i < 16; ++i)
gm[i] = qm[i];
glMultMatrixf(gm);
}
void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, int width, int height, const GLenum & format, const GLenum & target) {
//glClearError();
if (tex == 0) {
f->glGenTextures(1, &tex);
f->glBindTexture(target, tex);
}
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_COMPONENT16 || format == GL_DEPTH_COMPONENT24 || format == GL_DEPTH_COMPONENT32)
f->glTexImage2D(target, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr);
else {
int type = GL_UNSIGNED_BYTE;
int fmt = GL_RGBA;
if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGBA32F || format == GL_RGBA16F)
type = GL_FLOAT;
if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGB8 || format == GL_RGB)
fmt = GL_RGB;
f->glTexImage2D(target, 0, format, width, height, 0, fmt, type, nullptr);
//glGenerateMipmap(target);
//qDebug() << "glTexImage2D" << width << height << QString::number(t, 16);
}
//qDebug() << QString::number(glGetError(), 16);
}
void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, const QImage & image, const GLenum & format, const GLenum & target) {
if (tex == 0) {
f->glGenTextures(1, &tex);
}
f->glBindTexture(target, tex);
QImage im = image.mirrored(false, true).convertToFormat(QImage::Format_RGBA8888);
//const QImage & cim(im);
f->glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
f->glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
f->glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_3D) {
f->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
f->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
f->glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
} else {
f->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
f->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glClearError();
f->glTexImage2D(target, 0, format, im.width(), im.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_3D) {
f->glGenerateMipmap(target);
}
//qDebug() << target << format << tex << im.width() << im.height() << im.bits() << QString::number(glGetError(), 16);
}
QMatrix4x4 glMatrixPerspective(float angle, float aspect, float near_, float far_) {
QMatrix4x4 ret;
float t = 1.f / (tanf(angle * deg2rad / 2.f)), e = 2.4e-7f;
if (aspect >= 1.) {
ret(0, 0) = t / aspect;
ret(1, 1) = t;
} else {
ret(0, 0) = t;
ret(1, 1) = t * aspect;
}
ret(2, 2) = e - 1.f;//far_ / (far_ - near_) - 1.;
ret(2, 3) = (e - 2.f) * near_;//2. * far_ * near_ / (far_ - near_);
ret(3, 2) = -1.f;
ret(3, 3) = 0.f;
return ret;
}
QImage rotateQImageLeft(const QImage & im) {
QImage ri(im.height(), im.width(), im.format());
QPainter p(&ri);
p.rotate(90);
p.drawImage(0, -im.height(), im);
p.end();
return ri;
}
QImage rotateQImageRight(const QImage & im) {
QImage ri(im.height(), im.width(), im.format());
QPainter p(&ri);
p.rotate(-90);
p.drawImage(-im.width(), 0, im);
p.end();
return ri;
}
QColor colorFromString(const QString & str) {
QString s = str.trimmed();
int i = s.indexOf("\t");
float r, g, b;
r = s.left(i).toFloat(); s = s.right(s.length() - i - 1); i = s.indexOf("\t");
g = s.left(i).toFloat(); s = s.right(s.length() - i - 1);
b = s.toFloat();
return QColor(r * 255.f, g * 255.f, b * 255.f);
}
QVector3D orthToVector(const QVector3D & v, const float & scale) {
if (v.isNull()) return QVector3D();
QVector3D rv, fn, sn;
if (v.x() != 0.f) rv.setZ(1.);
else if (v.y() != 0.f) rv.setX(1.);
else rv.setY(1.);
fn = QVector3D::crossProduct(v, rv).normalized();
sn = QVector3D::crossProduct(v, fn).normalized();
return fn * urand(scale) + sn * urand(scale);
}
QVector3D rotateVector(const QVector3D & v, const QVector3D & a) {
QMatrix4x4 m;
m.rotate(a.z(), 0., 0., 1.);
m.rotate(a.y(), 0., 1., 0.);
m.rotate(a.x(), 1., 0., 0.);
return m * v;
}
void setVectorLength(QVector3D & v, const float & l) {
float vl = v.length();
if (vl == 0.f) return;
float c = l / vl;
v *= c;
}
void lengthenVector(QVector3D & v, const float & l) {
float vl = v.length();
if (l == 0.f || vl == 0.f) return;
float c = 1.f + l / vl;
v *= c;
}
Vector3i::Vector3i(const QString & str) {
QString s = str.trimmed();
int i = s.indexOf("\t");
p0 = s.left(i).toInt(); s = s.right(s.length() - i - 1); i = s.indexOf("\t");
p1 = s.left(i).toInt(); s = s.right(s.length() - i - 1);
p2 = s.toInt();
}
void glEnableDepth() {
glEnable(GL_DEPTH_TEST);
//glDepthFunc(GL_GREATER);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
}
void glDisableDepth() {
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
}
void glClearFramebuffer(const QColor & color, bool depth) {
glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
//glClearDepth(0.);
if (depth)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
else
glClear(GL_COLOR_BUFFER_BIT);
}
Box3D::Box3D(const QVector<QVector3D> & points) {
x = y = z = width = length = height = angle_z = angle_xy = angle_roll = 0.f;
if (points.isEmpty()) return;
float ix, iy, iz, ax, ay, az;
ix = ax = points[0].x();
iy = ay = points[0].y();
iz = az = points[0].z();
for (int i = 1; i < points.size(); ++i) {
ix = qMin<float>(ix, points[i].x()); ax = qMax<float>(ax, points[i].x());
iy = qMin<float>(iy, points[i].y()); ay = qMax<float>(ay, points[i].y());
iz = qMin<float>(iz, points[i].z()); az = qMax<float>(az, points[i].z());
}
x = ix;
y = iy;
z = iz;
length = ax - ix;
width = ay - iy;
height = az - iz;
}
QVector<QVector3D> Box3D::corners() const {
QVector<QVector3D> ret;
ret << QVector3D(x, y, z) << QVector3D(x, y + width, z) << QVector3D(x, y, z + height) << QVector3D(x, y + width, z + height)
<< QVector3D(x + length, y, z) << QVector3D(x + length, y + width, z)
<< QVector3D(x + length, y, z + height) << QVector3D(x + length, y + width, z + height);
return ret;
}
Box3D & Box3D::operator |=(const Box3D & o) {
if (o.isEmpty()) return *this;
if (isEmpty()) *this = o;
else {
GLfloat mx = x + length, my = y + width, mz = z + height;
GLfloat omx = o.x + o.length, omy = o.y + o.width, omz = o.z + o.height;
x = qMin(x, o.x); y = qMin(y, o.y); z = qMin(z, o.z);
mx = qMax(mx, omx); my = qMax(my, omy); mz = qMax(mz, omz);
length = mx - x; width = my - y; height = mz - z;
}
return *this;
}
QVector3D vectorFromString(const QString & str) {
QTextStream s(const_cast<QString*>(&str), QIODevice::ReadOnly);
QVector3D ret;
float f(0.f);
s >> f; ret.setX(f);
s >> f; ret.setY(f);
s >> f; ret.setZ(f);
return ret;
}

259
qglengine/gltypes.h Normal file
View File

@@ -0,0 +1,259 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLTYPES_H
#define GLTYPES_H
#if WIN32 || WIN64 || _WIN32 || _WIN64 || __WIN32__ || __WIN64__
# define WINDOWS
#endif
#if __QNX__ || __QNXNTO__
# define QNX
#endif
#ifdef __APPLE__
# define MAC
#endif
#ifndef WINDOWS
# ifndef QNX
# ifndef MAC
# define LINUX
# endif
# endif
#endif
#if __GNUC__
# define CC_GCC
#elif _MSC_VER
# define CC_VC
#endif
#include <QObject>
//#ifndef WINDOWS
//# ifdef MAC
//# include <OpenGL/gl.h>
//# include <OpenGL/glu.h>
//# include <GLUT/glut.h>
//# else
//# include <GL/gl.h>
//# include <GL/glext.h>
//# include <GL/glu.h>
//# endif
//#endif
#include <QOpenGLExtraFunctions>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <qopenglext.h>
#include <cmath>
#include <float.h>
#include <QMatrix4x4>
#include <QDebug>
#include <QDataStream>
#include <QColor>
#include <QVector2D>
#include <QVector3D>
#include <QImage>
#include <QMutex>
#include <QFile>
#include <QDir>
#ifndef QNX
# include <cmath>
# include <complex>
#else
# include <math.h>
# include <complex.h>
#endif
#include <iostream>
//#ifdef WINDOWS
//# define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
//# define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
//#endif
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
#ifndef M_2PI
# define M_2PI 6.28318530717958647692
#endif
#ifndef M_PI_3
# define M_PI_3 1.04719755119659774615
#endif
#ifndef GL_RGBA16F
# define GL_RGBA16F GL_RGBA16F_ARB
#endif
using std::complex;
#ifndef PIP_VERSION
typedef long long llong;
typedef unsigned char uchar;
typedef unsigned short int ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ullong;
typedef long double ldouble;
const float deg2rad = atanf(1.f) / 45.f;
const float rad2deg = 45.f / atanf(1.f);
# ifdef WINDOWS
inline int random() {return rand();}
# endif
#else
#define random randomi
#endif
#ifdef CC_VC
inline float round(const float & v) {return floor(v + 0.5);}
#endif
inline float randomu() {return float(random()) / RAND_MAX;}
inline const QSizeF operator *(const QSizeF & f, const QSizeF & s) {return QSizeF(f.width() * s.width(), f.height() * s.height());}
#ifndef PIP_VERSION
template<typename Type> inline void piSwap(Type & f, Type & s) {Type t = f; f = s; s = t;}
template<typename Type> inline Type piMin(const Type & f, const Type & s) {return (f > s) ? s : f;}
template<typename Type> inline Type piMin(const Type & f, const Type & s, const Type & t) {return (f < s && f < t) ? f : ((s < t) ? s : t);}
template<typename Type> inline Type piMax(const Type & f, const Type & s) {return (f < s) ? s : f;}
template<typename Type> inline Type piMax(const Type & f, const Type & s, const Type & t) {return (f > s && f > t) ? f : ((s > t) ? s : t);}
template<typename Type> inline Type piClamp(const Type & v, const Type & min, const Type & max) {return (v > max ? max : (v < min ? min : v));}
inline ushort letobe_s(ushort v) {return (v << 8) | (v >> 8);}
inline uint letobe_i(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
#endif
// return [-1, 1]
inline float urand(const float & scale = 1.) {return ((float)rand() / RAND_MAX - .5f) * (scale + scale);}
// return [0, 1]
inline float uprand(const float & scale = 1.) {return ((float)rand() / RAND_MAX) * scale;}
QString readCharsUntilNull(QDataStream & s);
QString findFile(const QString & file, const QStringList & pathes);
inline QColor operator *(const QColor & c, float v) {return QColor(piClamp<int>(c.red() * v, 0, 255), piClamp<int>(c.green() * v, 0, 255), piClamp<int>(c.blue() * v, 0, 255), piClamp<int>(c.alpha() * v, 0, 255));}
inline QColor operator /(const QColor & c, float v) {return QColor(piClamp<int>(c.red() / v, 0, 255), piClamp<int>(c.green() / v, 0, 255), piClamp<int>(c.blue() / v, 0, 255), piClamp<int>(c.alpha() / v, 0, 255));}
inline void qglColor(const QColor & c) {glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());}
inline void glClearError() {int c = 100; while (glGetError() != GL_NO_ERROR && --c > 0) glGetError();}
inline void glSetCapEnabled(GLenum cap, bool on = true) {if (on) glEnable(cap); else glDisable(cap);}
inline void glSetPolygonMode(GLenum mode) {glPolygonMode(GL_FRONT_AND_BACK, mode);}
inline void deleteGLTexture(QOpenGLExtraFunctions * f, GLuint & tex) {if (tex != 0) f->glDeleteTextures(1, &tex); tex = 0;}
void glEnableDepth();
void glDisableDepth();
void glClearFramebuffer(const QColor & color = Qt::black, bool depth = true);
void glDrawQuad(QOpenGLShaderProgram * prog = nullptr, QVector4D * corner_dirs = nullptr, GLfloat x = -1.f, GLfloat y = -1.f, GLfloat w = 2.f, GLfloat h = 2.f);
void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, int width, int height, const GLenum & format = GL_RGBA, const GLenum & target = GL_TEXTURE_2D);
void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, const QImage & image, const GLenum & format = GL_RGBA, const GLenum & target = GL_TEXTURE_2D);
QMatrix4x4 glMatrixPerspective(float angle, float aspect, float near_, float far_);
QImage rotateQImageLeft(const QImage & im);
QImage rotateQImageRight(const QImage & im);
inline QImage rotateQImage180(const QImage & im) {return im.mirrored(true, true);}
class QGLView;
class ObjectBase;
class Light;
class Camera;
class Texture;
class CubeTexture;
class Map;
class Material;
class TextureManager;
class Texture2DArray;
class Mesh;
class Scene;
class RendererBase;
class Renderer;
class RendererMaterial;
class RendererService;
struct Box3D {
GLfloat x;
GLfloat y;
GLfloat z;
GLfloat width;
GLfloat length;
GLfloat height;
GLfloat angle_z;
GLfloat angle_xy;
GLfloat angle_roll;
Box3D() {x = y = z = width = length = height = angle_z = angle_xy = angle_roll = 0.f;}
Box3D(const QVector3D & center, GLfloat hwid, GLfloat hlen, GLfloat hhei) {x = center.x() - hwid; y = center.y() - hlen; z = center.z() - hhei; width = 2 * hwid; length = 2 * hlen; height = 2 * hhei; angle_z = angle_xy = angle_roll = 0.f;}
Box3D(const QVector<QVector3D> & points);
bool isEmpty() const {return (qAbs(width) < 1E-6f) && (qAbs(length) < 1E-6f) && (qAbs(height) < 1E-6f);}
QVector3D randomPoint() const {return QVector3D(uprand(length) + x, uprand(width) + y, uprand(height) + z);}
QVector3D pos() const {return QVector3D(x, y, z);}
QVector3D size() const {return QVector3D(length, width, height);}
QVector3D center() const {return QVector3D(length / 2.f + x, width / 2.f + y, height / 2.f + z);}
QVector3D angles() const {return QVector3D(angle_xy, angle_roll, angle_z);}
QVector<QVector3D> corners() const;
void setPos(const QVector3D & p) {x = p.x(); y = p.y(); z = p.z();}
void setAngles(const QVector3D & a) {angle_xy = a.x(); angle_roll = a.y(); angle_z = a.z();}
void setSize(const QVector3D & s) {length = s.x(); width = s.y(); height = s.z();}
Box3D & moveTo(const QVector3D & v) {x = v.x(); y = v.y(); z = v.z(); return *this;}
Box3D & move(const QVector3D & v) {x += v.x(); y += v.y(); z += v.z(); return *this;}
Box3D movedTo(const QVector3D & v) const {Box3D t(*this); t.x = v.x(); t.y = v.y(); t.z = v.z(); return t;}
Box3D moved(const QVector3D & v) const {Box3D t(*this); t.x += v.x(); t.y += v.y(); t.z += v.z(); return t;}
Box3D & operator |=(const Box3D & o);
};
inline QDebug operator <<(QDebug d, const Box3D & v) {d << "Box3D {start (" << v.x << "," << v.y << "," << v.z << "), size (" << v.length << "," << v.width << "," << v.height << ")}"; return d;}
#pragma pack(push, 1)
struct Vector3i {
Vector3i(int p0_ = 0, int p1_ = 0, int p2_ = 0) {p0 = p0_; p1 = p1_; p2 = p2_;}
Vector3i(const QString & str);
Vector3i movedX(const int & o) {return Vector3i(p0 + o, p1, p2);}
Vector3i movedY(const int & o) {return Vector3i(p0, p1 + o, p2);}
Vector3i movedZ(const int & o) {return Vector3i(p0, p1, p2 + o);}
Vector3i moved(const int & x, const int & y, const int & z) {return Vector3i(p0 + x, p1 + y, p2 + z);}
GLint p0;
GLint p1;
GLint p2;
bool operator ==(const Vector3i & o) const {return p0 == o.p0 && p1 == o.p1 && p2 == o.p2;}
bool operator !=(const Vector3i & o) const {return p0 != o.p0 || p1 != o.p1 || p2 != o.p2;}
void operator +=(int v) {p0 += v; p1 += v; p2 += v;}
QVector3D toQVector3D() const {return QVector3D(p0, p1, p2);}
};
#pragma pack(pop)
inline Vector3i operator +(const Vector3i & f, const Vector3i & s) {return Vector3i(f.p0 + s.p0, f.p1 + s.p1, f.p2 + s.p2);}
inline Vector3i operator -(const Vector3i & f, const Vector3i & s) {return Vector3i(f.p0 - s.p0, f.p1 - s.p1, f.p2 - s.p2);}
inline Vector3i operator /(const Vector3i & f, const int & s) {return Vector3i(f.p0 / s, f.p1 / s, f.p2 / s);}
inline uint qHash(const Vector3i & v) {return v.p0 ^ ((v.p1 << 8) | (v.p1 >> 24)) ^ ((v.p2 << 16) | (v.p2 >> 16));}
inline QDebug operator <<(QDebug d, const Vector3i & v) {d.nospace() << "{" << v.p0 << ", " << v.p1 << ", " << v.p2 << "}"; return d.space();}
inline QDataStream & operator <<(QDataStream & s, const Vector3i & v) {s << v.p0 << v.p1 << v.p2; return s;}
inline QDataStream & operator >>(QDataStream & s, Vector3i & v) {s >> v.p0 >> v.p1 >> v.p2; return s;}
QVector3D vectorFromString(const QString & str);
QColor colorFromString(const QString & str);
inline QVector4D QColor2QVector(const QColor & c) {return QVector4D(c.redF(), c.greenF(), c.blueF(), c.alphaF());}
inline float cosABV(const QVector3D & v0, const QVector3D & v1) {
float l = v0.length() * v1.length();
if (l == 0.f) return 0.;
return (QVector3D::dotProduct(v0, v1)) / l;
}
inline QVector3D projection(const QVector3D & v, const QVector3D & to) {return to.normalized() * v.length() * cosABV(v, to);}
QVector3D orthToVector(const QVector3D & v, const float & scale = 1.);
QVector3D rotateVector(const QVector3D & v, const QVector3D & a);
void setVectorLength(QVector3D & v, const float & l);
void lengthenVector(QVector3D & v, const float & l);
inline float squareLength(const QVector3D & from, const QVector3D & to) {return (to.x() - from.x())*(to.x() - from.x()) + (to.y() - from.y())*(to.y() - from.y()) + (to.z() - from.z())*(to.z() - from.z());}
inline QVector3D directionFromAngles(const QVector3D & a) {return rotateVector(QVector3D(1., 0., 0.), a);}
inline float frac(const float & x, const float & b) {return x - int(x / b) * b;}
#endif // GLTYPES_H

236
qglengine/glwidget.cpp Normal file
View File

@@ -0,0 +1,236 @@
#include "glwidget.h"
#include "qglview.h"
#include <QVBoxLayout>
GLWidget::GLWidget(QWidget *parent) : QWidget(parent) {
view_ = new QGLView();
view_->setFlag(Qt::FramelessWindowHint);
container = QWidget::createWindowContainer(view_, this);
lay = new QVBoxLayout(this);
lay->addWidget(container);
lay->setContentsMargins(0, 0, 0, 0);
lay->setSpacing(0);
setMouseTracking(true);
setWindowIcon(QIcon("://icons/qglview.png"));
connect(view_, &QGLView::doubleClick, this, &GLWidget::viewDoubleClicked);
}
QColor GLWidget::backColor() const {
return view_->backColor();
}
qreal GLWidget::lineWidth() const {
return view_->lineWidth();
}
qreal GLWidget::FOV() const {
return view_->FOV();
}
qreal GLWidget::depthStart() const {
return view_->depthStart();
}
qreal GLWidget::depthEnd() const {
return view_->depthEnd();
}
QColor GLWidget::ambientColor() const {
return view_->ambientColor();
}
bool GLWidget::isLightEnabled() const {
return view_->isLightEnabled();
}
bool GLWidget::isGrabMouseEnabled() const {
return view_->isGrabMouseEnabled();
}
bool GLWidget::isMouseRotateEnabled() const {
return view_->isMouseRotateEnabled();
}
bool GLWidget::isMouseSelectionEnabled() const {
return view_->isMouseSelectionEnabled();
}
bool GLWidget::isCameraOrbit() const
{
return view_->isCameraOrbit();
}
bool GLWidget::isHoverHaloEnabled() const {
return view_->isHoverHaloEnabled();
}
QColor GLWidget::hoverHaloColor() const {
return view_->hoverHaloColor();
}
qreal GLWidget::hoverHaloFillAlpha() const {
return view_->hoverHaloFillAlpha();
}
bool GLWidget::isSelectionHaloEnabled() const {
return view_->isSelectionHaloEnabled();
}
QColor GLWidget::selectionHaloColor() const {
return view_->selectionHaloColor();
}
qreal GLWidget::selectionHaloFillAlpha() const {
return view_->selectionHaloFillAlpha();
}
Scene * GLWidget::scene() {
return view_->scene();
}
void GLWidget::addObject(ObjectBase * o) {
view_->scene()->addObject(o);
}
QByteArray GLWidget::saveCamera() {
return view_->saveCamera();
}
void GLWidget::restoreCamera(const QByteArray &ba) {
view_->restoreCamera(ba);
}
void GLWidget::stop() {
view_->stop();
}
void GLWidget::start(float freq) {
view_->start(freq);
}
void GLWidget::setBackColor(const QColor & c) {
view_->setBackColor(c);
}
void GLWidget::setLineWidth(const qreal & arg) {
view_->setLineWidth(arg);
}
void GLWidget::setFOV(const qreal & arg) {
view_->setFOV(arg);
}
void GLWidget::setDepthStart(const qreal & arg) {
view_->setDepthStart(arg);
}
void GLWidget::setDepthEnd(const qreal & arg) {
view_->setDepthEnd(arg);
}
void GLWidget::setAmbientColor(const QColor & arg) {
view_->setAmbientColor(arg);
}
void GLWidget::setLightEnabled(const bool & arg) {
view_->setLightEnabled(arg);
}
void GLWidget::setGrabMouseEnabled(const bool & arg) {
view_->setGrabMouseEnabled(arg);
}
void GLWidget::setMouseRotateEnabled(const bool & arg) {
view_->setMouseRotateEnabled(arg);
}
void GLWidget::setMouseSelectionEnabled(const bool & arg) {
view_->setMouseSelectionEnabled(arg);
}
void GLWidget::setCameraOrbit(const bool & arg) {
view_->setCameraOrbit(arg);
}
void GLWidget::setHoverHaloEnabled(const bool & arg) {
view_->setHoverHaloEnabled(arg);
}
void GLWidget::setHoverHaloColor(const QColor & arg) {
view_->setHoverHaloColor(arg);
}
void GLWidget::setHoverHaloFillAlpha(const qreal & arg) {
view_->setHoverHaloFillAlpha(arg);
}
void GLWidget::setSelectionHaloEnabled(const bool & arg) {
view_->setSelectionHaloEnabled(arg);
}
void GLWidget::setSelectionHaloColor(const QColor & arg) {
view_->setSelectionHaloColor(arg);
}
void GLWidget::setSelectionHaloFillAlpha(const qreal & arg) {
view_->setSelectionHaloFillAlpha(arg);
}
void GLWidget::viewDoubleClicked() {
// qDebug() << "click widget!!";
if (view_->windowState() == Qt::WindowFullScreen) {
// view_->hide();
container = QWidget::createWindowContainer(view_, this);
lay->addWidget(container);
container->show();
// show();
} else {
// hide();
view_->setParent(nullptr);
view_->showFullScreen();
lay->removeWidget(container);
}
// qDebug() << "click widge done!";
}

89
qglengine/glwidget.h Normal file
View File

@@ -0,0 +1,89 @@
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QWidget>
class QGLView;
class ObjectBase;
class Scene;
class GLWidget : public QWidget
{
Q_OBJECT
Q_PROPERTY (QColor backColor READ backColor WRITE setBackColor)
Q_PROPERTY (qreal lineWidth READ lineWidth WRITE setLineWidth)
Q_PROPERTY (qreal FOV READ FOV WRITE setFOV)
Q_PROPERTY (qreal depthStart READ depthStart WRITE setDepthStart)
Q_PROPERTY (qreal depthEnd READ depthEnd WRITE setDepthEnd)
Q_PROPERTY (QColor ambientColor READ ambientColor WRITE setAmbientColor)
Q_PROPERTY (bool grabMouse READ isGrabMouseEnabled WRITE setGrabMouseEnabled)
Q_PROPERTY (bool mouseRotate READ isMouseRotateEnabled WRITE setMouseRotateEnabled)
Q_PROPERTY (bool mouseSelection READ isMouseSelectionEnabled WRITE setMouseSelectionEnabled)
Q_PROPERTY (bool cameraOrbit READ isCameraOrbit WRITE setCameraOrbit)
Q_PROPERTY (bool hoverHalo READ isHoverHaloEnabled WRITE setHoverHaloEnabled)
Q_PROPERTY (QColor hoverHaloColor READ hoverHaloColor WRITE setHoverHaloColor)
Q_PROPERTY (qreal hoverHaloFillAlpha READ hoverHaloFillAlpha WRITE setHoverHaloFillAlpha)
Q_PROPERTY (bool selectionHalo READ isSelectionHaloEnabled WRITE setSelectionHaloEnabled)
Q_PROPERTY (QColor selectionHaloColor READ selectionHaloColor WRITE setSelectionHaloColor)
Q_PROPERTY (qreal selectionHaloFillAlpha READ selectionHaloFillAlpha WRITE setSelectionHaloFillAlpha)
public:
explicit GLWidget(QWidget *parent = nullptr);
QGLView * view() {return view_;}
QColor backColor() const;
qreal lineWidth() const;
qreal FOV() const;
qreal depthStart() const;
qreal depthEnd() const;
QColor ambientColor() const;
bool isLightEnabled() const;
bool isGrabMouseEnabled() const;
bool isMouseRotateEnabled() const;
bool isMouseSelectionEnabled() const;
bool isCameraOrbit() const;
bool isHoverHaloEnabled() const;
QColor hoverHaloColor() const;
qreal hoverHaloFillAlpha() const;
bool isSelectionHaloEnabled() const;
QColor selectionHaloColor() const;
qreal selectionHaloFillAlpha() const;
Scene * scene();
void addObject(ObjectBase * o);
QByteArray saveCamera();
void restoreCamera(const QByteArray & ba);
public slots:
void stop();
void start(float freq = 60.0);
void setBackColor(const QColor & c);
void setLineWidth(const qreal & arg);
void setFOV(const qreal & arg);
void setDepthStart(const qreal & arg);
void setDepthEnd(const qreal & arg);
void setAmbientColor(const QColor & arg);
void setLightEnabled(const bool & arg);
void setGrabMouseEnabled(const bool & arg);
void setMouseRotateEnabled(const bool & arg);
void setMouseSelectionEnabled(const bool & arg);
void setCameraOrbit(const bool & arg);
void setHoverHaloEnabled(const bool & arg);
void setHoverHaloColor(const QColor & arg);
void setHoverHaloFillAlpha(const qreal & arg);
void setSelectionHaloEnabled(const bool & arg);
void setSelectionHaloColor(const QColor & arg);
void setSelectionHaloFillAlpha(const qreal & arg);
private slots:
void viewDoubleClicked();
private:
QWidget * container;
QGLView * view_;
QLayout * lay;
signals:
};
#endif // GLWIDGET_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
qglengine/icons/alpha.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
qglengine/icons/expand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
qglengine/icons/go-jump.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
qglengine/icons/go-top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
qglengine/icons/light-+.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
qglengine/icons/picker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
qglengine/icons/qglview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
qglengine/icons/qglview.xcf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,95 @@
#include "openglwindow.h"
#include <QCoreApplication>
#include <QOpenGLContext>
#include <QOpenGLPaintDevice>
#include <QPainter>
OpenGLWindow::OpenGLWindow(QWindow *parent)
: QWindow(parent)
, m_context(nullptr)
, m_device(nullptr)
{
setFlag(Qt::FramelessWindowHint);
setSurfaceType(QWindow::OpenGLSurface);
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
// qDebug() << format;
#ifdef QT_OPENGL_ES_2
format.setRenderableType(QSurfaceFormat::OpenGLES);
#else
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
format.setVersion(4, 0);
format.setProfile(QSurfaceFormat::CoreProfile);
}
#endif
format.setDepthBufferSize(24);
format.setSamples(8);
// format.setStencilBufferSize(8);
setFormat(format);
QSurfaceFormat::setDefaultFormat(format);
}
OpenGLWindow::~OpenGLWindow() {
delete m_device;
}
void OpenGLWindow::render(QPainter *painter) {
}
void OpenGLWindow::initialize() {
}
void OpenGLWindow::render() {
// if (!m_device) m_device = new QOpenGLPaintDevice;
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// m_device->setSize(size() * devicePixelRatio());
// m_device->setDevicePixelRatio(devicePixelRatio());
// QPainter painter(m_device);
// render(&painter);
}
void OpenGLWindow::renderLater() {
requestUpdate();
}
bool OpenGLWindow::event(QEvent *event) {
switch (event->type()) {
case QEvent::UpdateRequest:
renderNow();
return true;
default:
return QWindow::event(event);
}
}
void OpenGLWindow::exposeEvent(QExposeEvent *event) {
if (isExposed()) renderNow();
}
void OpenGLWindow::renderNow() {
if (!isExposed())
return;
bool needsInitialize = false;
if (!m_context) {
m_context = new QOpenGLContext(this);
m_context->setFormat(requestedFormat());
m_context->create();
needsInitialize = true;
}
m_context->makeCurrent(this);
if (needsInitialize) {
initializeOpenGLFunctions();
initialize();
}
render();
m_context->swapBuffers(this);
}

36
qglengine/openglwindow.h Normal file
View File

@@ -0,0 +1,36 @@
#include <QWindow>
#include <QOpenGLExtraFunctions>
class QPainter;
class QOpenGLContext;
class QOpenGLPaintDevice;
class OpenGLWindow: public QWindow, protected QOpenGLExtraFunctions
{
Q_OBJECT
public:
explicit OpenGLWindow(QWindow *parent = nullptr);
~OpenGLWindow();
virtual void render(QPainter *painter);
virtual void render();
virtual void initialize();
QOpenGLContext * context() {return m_context;}
public slots:
void renderLater();
void renderNow();
protected:
bool event(QEvent *event) override;
void exposeEvent(QExposeEvent *event) override;
private:
QOpenGLContext *m_context;
QOpenGLPaintDevice *m_device;
};

View File

@@ -0,0 +1,12 @@
project(qglengine_plugin)
include_directories("..")
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_NO_DEBUG)
add_definitions(-DQT_SHARED)
add_definitions(-DQDESIGNER_EXPORT_WIDGETS)
find_qt(${QtVersions} Core Designer Gui Widgets OpenGL)
qt_sources(SRC)
qt_wrap(${SRC} CPPS out_CPP QMS out_QM)
qt_add_library(${PROJECT_NAME} SHARED out_CPP)
qt_target_link_libraries(${PROJECT_NAME} qglengine)
qt_install(TARGETS ${PROJECT_NAME} DESTINATION QtPlugins/designer)

View File

@@ -0,0 +1,14 @@
#include "qglview_designerplugin.h"
#include "qglviewplugin.h"
QGLViewDesignerPlugin::QGLViewDesignerPlugin(QObject * parent): QObject(parent)
{
m_widgets.append(new QGLViewPlugin(this));
}
QList<QDesignerCustomWidgetInterface * > QGLViewDesignerPlugin::customWidgets() const {
return m_widgets;
}

View File

@@ -0,0 +1,22 @@
#ifndef QGLVIEW_DESIGNERPLUGIN_H
#define QGLVIEW_DESIGNERPLUGIN_H
#include <QtDesigner/QtDesigner>
#include <QtCore/qplugin.h>
class QGLViewDesignerPlugin: public QObject, public QDesignerCustomWidgetCollectionInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "qad.qglview")
Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
public:
QGLViewDesignerPlugin(QObject * parent = 0);
virtual QList<QDesignerCustomWidgetInterface * > customWidgets() const;
private:
QList<QDesignerCustomWidgetInterface * > m_widgets;
};
#endif // QGLVIEW_DESIGNERPLUGIN_H

View File

@@ -0,0 +1,95 @@
#include "../glwidget.h"
#include "qglviewplugin.h"
#include <QtCore/QtPlugin>
#include "glprimitives.h"
#include "qglview.h"
QGLViewPlugin::QGLViewPlugin(QObject * parent): QObject(parent) {
m_initialized = false;
}
void QGLViewPlugin::initialize(QDesignerFormEditorInterface * /* core */) {
if (m_initialized)
return;
// Add extension registrations, etc. here
m_initialized = true;
}
bool QGLViewPlugin::isInitialized() const {
return m_initialized;
}
QWidget * QGLViewPlugin::createWidget(QWidget * parent) {
GLWidget * w = new GLWidget(parent);
if (m_initialized) {
auto axis = new GLObjectBase();
GLObjectBase * obj;
float al = 1.;
obj = new GLPrimitiveLine(QVector3D(0, 0, -al), QVector3D(0, 0, al));
obj->material().color_diffuse = Qt::darkBlue; obj->setAcceptLight(false);
obj->setSelectable(false);
axis->addChild(obj);
obj = new GLPrimitiveLine(QVector3D(-al, 0, 0), QVector3D(al, 0, 0));
obj->material().color_diffuse = Qt::darkRed; obj->setAcceptLight(false);
obj->setSelectable(false);
axis->addChild(obj);
obj = new GLPrimitiveLine(QVector3D(0, -al, 0), QVector3D(0, al, 0));
obj->material().color_diffuse = Qt::darkGreen; obj->setAcceptLight(false);
obj->setSelectable(false);
axis->addChild(obj);
w->view()->addObject(axis);
auto cam_light = new Light();
cam_light->intensity = 0.5;
cam_light->setName("Camera_Light");
w->view()->camera()->addChild(cam_light);
w->start();
}
return w;
}
QString QGLViewPlugin::name() const {
return QLatin1String("GLWidget");
}
QString QGLViewPlugin::group() const {
return QLatin1String("Display Widgets");
}
QIcon QGLViewPlugin::icon() const {
return QIcon("://icons/qglview.png");
}
QString QGLViewPlugin::toolTip() const {
return QLatin1String("");
}
QString QGLViewPlugin::whatsThis() const {
return QLatin1String("");
}
bool QGLViewPlugin::isContainer() const {
return false;
}
QString QGLViewPlugin::domXml() const {
return QLatin1String("<widget class=\"GLWidget\" name=\"glview\">\n</widget>\n");
}
QString QGLViewPlugin::includeFile() const {
return QLatin1String("glwidget.h");
}

View File

@@ -0,0 +1,33 @@
#ifndef QGLVIEWPLUGIN_H
#define QGLVIEWPLUGIN_H
#include <QObject>
#include <QtUiPlugin/QDesignerCustomWidgetInterface>
class QGLViewPlugin: public QObject, public QDesignerCustomWidgetInterface
{
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
explicit QGLViewPlugin(QObject * parent = 0);
bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget * createWidget(QWidget * parent);
void initialize(QDesignerFormEditorInterface * core);
private:
bool m_initialized;
};
#endif //QGLVIEWPLUGIN_H

446
qglengine/qglview.cpp Normal file
View File

@@ -0,0 +1,446 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qglview.h"
#include "glmesh.h"
#include "gltexture_manager.h"
#include <chunkstream.h>
#include <QApplication>
#include <QOpenGLTexture>
#include <QKeyEvent>
using namespace QGLEngineShaders;
QGLView::QGLView(): OpenGLWindow(), renderer_(this) {
setIcon(QIcon(":/icons/qglview.png"));
deleting_ = false;
timer = 0;
need_init_ = is_first_draw = true;
backColor_ = Qt::darkGray;
hoverHaloColor_ = QColor(195, 140, 255);
selectionHaloColor_ = QColor(175, 255, 140);
ambientColor_ = QColor(10, 10, 10);
lastPos = QPoint(-1, -1);
lineWidth_ = 1.;
max_anisotropic = 1;
max_texture_chanels = 8;
cameraOrbit_ = lightEnabled_ = canSelect_ = true;
shaders_supported = selecting_ = customMouseMove_ = false;
sel_button = Qt::LeftButton;
sel_mod = Qt::ControlModifier;
fps_cnt = 0;
fps_tm = fps_ = 0.;
fogDensity_ = fogEnd_ = 1.;
fogStart_ = 0.;
hoverHaloFill_ = selectionHaloFill_ = 0.15f;
//lmode = Simple;
setFeature(qglFXAA, false);
setFeature(qglAnisotropicLevel, 8);
setFeature(qglEyeAccomodationEnabled, false);
setFeature(qglEyeAccomodationTime, 16.);
setFeature(qglEyeAccomodationMaxSpeed, 0.2);
setFeature(qglBloomEnabled, false);
setFeature(qglBloomThreshold, 0.9);
setFeature(qglBloomFactor, 1.);
setFeature(qglBloomRadius, 8);
setFeature(qglMotionBlurEnabled, false);
setFeature(qglMotionBlurFactor, 1.);
setFeature(qglMotionBlurSteps, 8);
setFeature(qglShadowsEnabled, false);
setFeature(qglShadowsMapSize, 512);
setFeature(qglShadowsSoftEnabled, true);
setFeature(qglReflectionsEnabled, false);
setFeature(qglReflectionsBlur, true);
setFeature(qglSSAOEnabled, false);
setFeature(qglSSAORadius, 5);
setFeature(qglDepthOfFieldEnabled, false);
setFeature(qglDepthOfFieldAutoFocusEnabled, true);
setFeature(qglDepthOfFieldAutoFocusSpeed, 0.1);
setFeature(qglDepthOfFieldFocus, 1.);
setFeature(qglDepthOfFieldDiaphragm, 8.);
mouse_first = mouseSelect_ = hoverHalo_ = selectionHalo_ = true;
mouseRotate_ = true;
fogEnabled_ = is_init = grabMouse_ = shaders_bind = changed_ = false;
rmode = ObjectBase::Fill;
// sel_pen = QPen(Qt::black, 1, Qt::DashLine);
// sel_brush = QBrush(QColor(170, 100, 255, 120));
scene_ = new Scene();
connect(scene_, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
connect(scene_, SIGNAL(__destroyed()), this, SLOT(__destroyed()));
camera_ = new Camera();
camera_->setAim(QVector3D());
camera_->setPos(QVector3D(2, 2, 2));
camera_->setName("Camera");
emit cameraPosChanged(camera_->pos());
//camera().aim_ = camera().pos_;
ktm_.restart();
Mesh * m = Primitive::cube();
ObjectBase * o = new ObjectBase(m);
o->setColor(Qt::cyan);
scene()->addObject(o);
delete m;
}
QGLView::~QGLView() {
deleting_ = true;
stop();
scene_->destroy();
delete scene_;
}
void QGLView::stop() {
if (timer) killTimer(timer);
}
void QGLView::start(float freq) {
timer = startTimer(freq <= 0.f ? 0 : int(1000.f / freq));
}
Scene::SelectionMode QGLView::selectionMode() const {
return scene_->selectionMode();
}
void QGLView::setSelectionMode(Scene::SelectionMode m) {
scene_->setSelectionMode(m);
}
void QGLView::selectObject(ObjectBase * o, bool add_to_selection) {
scene_->selectObject(o, add_to_selection);
}
void QGLView::clearSelection() {
scene_->clearSelection();
}
QList<ObjectBase * > QGLView::selectedObjects() const {
return scene_->selectedObjects();
}
ObjectBase * QGLView::selectedObject() const {
return scene_->selectedObject();
}
void QGLView::resizeEvent(QResizeEvent * e) {
renderLater();
}
void QGLView::timerEvent(QTimerEvent *) {
renderNow();
//if (ktm_.elapsed() < QApplication::keyboardInputInterval()) return;
Qt::KeyboardModifiers km = QApplication::keyboardModifiers();
foreach (int i, keys_)
emit keyEvent((Qt::Key)i, km);
}
void QGLView::render() {
resizeGL(width(), height());
emit glBeginPaint();
renderer_.mouse_pos = mapFromGlobal(QCursor::pos());
renderer_.renderScene();
emit glPainting();
emit glEndPaint();
fps_tm += time.elapsed();
time.restart();
fps_cnt++;
if (fps_tm < 1000.) return;
fps_ = fps_cnt / fps_tm * 1000.;
fps_tm = 0.;
fps_cnt = 0;
}
void QGLView::initialize() {
checkCaps();
renderer_.reloadShaders();
renderer_.init(width(), height());
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_MULTISAMPLE);
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_MAX_ANISOTROPY_EXT);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
is_init = true;
need_init_ = false;
emit glInitializeDone();
}
void QGLView::checkCaps() {
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropic);
shaders_supported = QOpenGLShaderProgram::hasOpenGLShaderPrograms();
}
void QGLView::__destroyed() {
renderer_.rend_mat.mat_thumbnails.clear();
hov_objects.clear();
}
void QGLView::resizeGL(int width, int height) {
if (!is_init) return;
if (width <= 0 || height <= 0) return;
if (prev_size == QSize(width, height)) return;
prev_size = QSize(width, height);
aspect = float(width) / float(height);
renderer_.resize(width, height);
mouse_first = true;
//qDebug() << "resize" << width << height;
iaspect = (aspect == 0.f) ? 0. : 1 / aspect;
glViewport(0, 0, width, height);
emit glResize(width, height);
}
void QGLView::mouseReleaseEvent(QMouseEvent * e) {
bool add_ts = e->modifiers().testFlag(sel_mod);
if (selecting_) {
selecting_ = false;
canSelect_ = true;
renderer_.mouse_rect = QRect();
scene_->selectObjects(hov_objects.toList(), add_ts);
return;
}
if (canSelect_ && mouseSelect_ && e->button() == Qt::LeftButton) {
if ((lastPos - downPos).manhattanLength() < QApplication::startDragDistance() && !hov_objects.isEmpty()) {
scene_->selectObject(hov_objects[0], add_ts);
}
}
canSelect_ = e->buttons() == 0;
emit glMouseReleaseEvent(e);
}
void QGLView::mousePressEvent(QMouseEvent * e) {
if (selecting_) {
downPos = e->pos();
selecting_ = false;
renderer_.mouse_rect = QRect();
return;
}
if (!QRect(QPoint(), size()).contains(e->pos())) return;
lastPos = e->pos();
downPos = lastPos;
emit glMousePressEvent(e);
}
void QGLView::mouseMoveEvent(QMouseEvent * e) {
QPoint cpos = e->pos();
if (selecting_) {
renderer_.mouse_rect = QRect(downPos, cpos).normalized();
return;
}
if (e->buttons().testFlag(Qt::LeftButton)) {
if ((cpos - downPos).manhattanLength() >= QApplication::startDragDistance()) {
selecting_ = true;
canSelect_ = false;
}
return;
}
QRect g_rect(QPoint(), size());
if (mouseRotate_) {
float dx = e->x() - lastPos.x();
float dy = e->y() - lastPos.y();
if (e->buttons().testFlag(Qt::MidButton)) {
if (cameraOrbit_) {
camera()->orbitZ(dx / 4.f);
camera()->orbitXY(dy / 4.f);
} else {
camera()->rotateZ(dx / 4.f);
camera()->rotateXY(dy / 4.f);
}
emit cameraPosChanged(camera()->pos());
} else if (e->buttons().testFlag(Qt::RightButton)) {
float ad = camera()->distance();
camera()->moveLeft(dx / 1000.f * ad);
camera()->moveUp(dy / 1000.f * ad);
emit cameraPosChanged(camera()->pos());
}
}
lastPos = e->pos();
if (customMouseMove_) emit customMouseMoveEvent(e->pos(), lastPos, e->buttons());
if (grabMouse_) {
QCursor::setPos(mapToGlobal(QRect(QPoint(), size()).center()));
static bool mouse_sec = false;
if (mouse_sec) {
mouse_sec = false;
return;
}
if (mouse_first) {
mouse_first = false;
mouse_sec = true;
return;
}
lastPos = g_rect.center();
int dx = e->x() - lastPos.x();
int dy = e->y() - lastPos.y();
emit glMouseMoveEvent(new QMouseEvent(QEvent::MouseMove, QPoint(dx, dy), e->button(), e->buttons(), e->modifiers()));
return;
}
emit glMouseMoveEvent(e);
}
void QGLView::wheelEvent(QWheelEvent * e) {
if (mouseRotate_) {
if (e->delta() > 0) camera()->flyCloser(0.1f);
if (e->delta() < 0) camera()->flyFarer(0.1f);
emit cameraPosChanged(camera()->pos());
}
emit glWheelEvent(e);
}
void QGLView::leaveEvent(QEvent * ) {
lastPos = QPoint(-1, -1);
//qDebug() << lastPos;
}
void QGLView::keyPressEvent(QKeyEvent * e) {
emit glKeyPressEvent(e);
if (e->key() > 0) keys_.insert(e->key());
if (e->key() == Qt::Key_F11) {
emit doubleClick();
}
}
void QGLView::keyReleaseEvent(QKeyEvent * e) {
emit glKeyReleaseEvent(e);
keys_.remove(e->key());
}
void QGLView::focusOutEvent(QFocusEvent *) {
keys_.clear();
}
void QGLView::mouseDoubleClickEvent(QMouseEvent * e) {
if (e->buttons().testFlag(Qt::MidButton))
emit doubleClick();
}
Camera * QGLView::camera() {
return camera_;
}
const Camera * QGLView::camera() const {
return camera_;
}
void QGLView::setCamera(Camera * camera) {
camera_ = camera;
}
TextureManager * QGLView::textureManager() {
return renderer_.textures_manager;
}
void QGLView::reloadTextures() {
renderer_.markReloadTextures();
}
void QGLView::focusOn(const Box3D & bb) {
if (bb.isEmpty() || !camera()) return;
double size = qMax(qMax(bb.width, bb.length), bb.height);
camera()->setAim(bb.center());
camera()->flyToDistance(size * 1.25);
}
void QGLView::setCameraLightOn(bool on) {
renderer_.setCameraLightOn(on);
}
bool QGLView::isCameraLightOn() const {
return renderer_.isCameraLightOn();
}
QByteArray QGLView::saveCamera() {
ChunkStream cs;
const Camera * c = camera();
cs.add(1, c->pos()).add(2, c->aim()).add(3, c->angles()).add(4, c->FOV());
return cs.data();
}
void QGLView::restoreCamera(const QByteArray & ba) {
if (ba.isEmpty()) return;
Camera * c = camera();
QVector3D pos(c->pos()), aim(c->aim()), ang(c->angles());
float fov(c->FOV());
ChunkStream cs(ba);
cs.readAll();
cs.get(1, pos).get(2, aim).get(3, ang).get(4, fov);
camera()->setPos(pos);
camera()->setAim(aim);
camera()->setAngles(ang);
camera()->setFOV(fov);
}
QByteArray QGLView::saveFeatures() {
QByteArray ba;
QDataStream ds(&ba, QIODevice::WriteOnly);
ds << features_;
return ba;
}
void QGLView::restoreFeatures(const QByteArray & ba) {
QHash<int, QVariant> f;
QDataStream ds(ba);
ds >> f;
features_ = f;
}
QImage QGLView::materialThumbnail(Material * m) {
return renderer_.materialThumbnail(m);
}

277
qglengine/qglview.h Normal file
View File

@@ -0,0 +1,277 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QGLVIEW_H
#define QGLVIEW_H
#include "openglwindow.h"
#include "glframebuffer.h"
#include "glprimitives.h"
#include "glcamera.h"
#include "glscene.h"
#include "glrendererbase.h"
#include "renderer.h"
#include <QTime>
class QGLView: public OpenGLWindow
{
friend class GLRendererBase;
friend class TextureManager;
friend class ObjectBase;
friend class Scene;
friend class RendererBase;
friend class Renderer;
friend class RendererMaterial;
friend class RendererService;
Q_OBJECT
Q_PROPERTY (QColor backColor READ backColor WRITE setBackColor)
Q_PROPERTY (float lineWidth READ lineWidth WRITE setLineWidth)
Q_PROPERTY (float FOV READ FOV WRITE setFOV)
Q_PROPERTY (float depthStart READ depthStart WRITE setDepthStart)
Q_PROPERTY (float depthEnd READ depthEnd WRITE setDepthEnd)
Q_PROPERTY (QColor ambientColor READ ambientColor WRITE setAmbientColor)
Q_PROPERTY (QColor fogColor READ fogColor WRITE setFogColor)
Q_PROPERTY (bool fogEnabled READ isFogEnabled WRITE setFogEnabled)
Q_PROPERTY (float fogDensity READ fogDensity WRITE setFogDensity)
Q_PROPERTY (float fogStart READ fogStart WRITE setFogStart)
Q_PROPERTY (float fogEnd READ fogEnd WRITE setFogEnd)
Q_PROPERTY (int renderMode READ renderMode WRITE setRenderMode)
Q_PROPERTY (bool grabMouse READ isGrabMouseEnabled WRITE setGrabMouseEnabled)
Q_PROPERTY (bool mouseRotate READ isMouseRotateEnabled WRITE setMouseRotateEnabled)
Q_PROPERTY (bool mouseSelection READ isMouseSelectionEnabled WRITE setMouseSelectionEnabled)
Q_PROPERTY (bool cameraOrbit READ isCameraOrbit WRITE setCameraOrbit)
Q_PROPERTY (bool hoverHalo READ isHoverHaloEnabled WRITE setHoverHaloEnabled)
Q_PROPERTY (QColor hoverHaloColor READ hoverHaloColor WRITE setHoverHaloColor)
Q_PROPERTY (float hoverHaloFillAlpha READ hoverHaloFillAlpha WRITE setHoverHaloFillAlpha)
Q_PROPERTY (bool selectionHalo READ isSelectionHaloEnabled WRITE setSelectionHaloEnabled)
Q_PROPERTY (QColor selectionHaloColor READ selectionHaloColor WRITE setSelectionHaloColor)
Q_PROPERTY (float selectionHaloFillAlpha READ selectionHaloFillAlpha WRITE setSelectionHaloFillAlpha)
Q_PROPERTY (Qt::MouseButton selectionButton READ selectionButton WRITE setSelectionButton)
Q_PROPERTY (Qt::KeyboardModifier selectionModifier READ selectionModifier WRITE setSelectionModifier)
Q_PROPERTY (Scene::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
public:
QGLView();
virtual ~QGLView();
enum Feature {
qglFXAA,
qglAnisotropicLevel,
qglEyeAccomodationEnabled,
qglEyeAccomodationTime,
qglEyeAccomodationMaxSpeed,
qglBloomEnabled,
qglBloomThreshold,
qglBloomFactor,
qglBloomRadius,
qglMotionBlurEnabled,
qglMotionBlurFactor,
qglMotionBlurSteps,
qglShadowsEnabled,
qglShadowsMapSize,
qglShadowsSoftEnabled,
qglReflectionsEnabled,
qglReflectionsBlur,
qglSSAOEnabled,
qglSSAORadius,
qglDepthOfFieldEnabled,
qglDepthOfFieldAutoFocusEnabled,
qglDepthOfFieldAutoFocusSpeed,
qglDepthOfFieldFocus,
qglDepthOfFieldDiaphragm
};
void stop();
void start(float freq = 60.);
QColor backColor() const {return backColor_;}
float lineWidth() const {return lineWidth_;}
float FOV() const {return camera()->fov_;}
float depthStart() const {return camera()->depth_start;}
float depthEnd() const {return camera()->depth_end;}
float currentFPS() const {return fps_;}
int maxAnisotropicLevel() const {return max_anisotropic;}
QColor ambientColor() const {return ambientColor_;}
QColor fogColor() const {return fogColor_;}
float fogDensity() const {return fogDensity_;}
float fogStart() const {return fogStart_;}
float fogEnd() const {return fogEnd_;}
bool isFogEnabled() const {return fogEnabled_;}
bool isLightEnabled() const {return lightEnabled_;}
bool isGrabMouseEnabled() const {return grabMouse_;}
bool isMouseRotateEnabled() const {return mouseRotate_;}
bool isMouseSelectionEnabled() const {return mouseSelect_;}
bool isCameraOrbit() const {return cameraOrbit_;}
bool isHoverHaloEnabled() const {return hoverHalo_;}
QColor hoverHaloColor() const {return hoverHaloColor_;}
float hoverHaloFillAlpha() const {return hoverHaloFill_;}
bool isSelectionHaloEnabled() const {return selectionHalo_;}
QColor selectionHaloColor() const {return selectionHaloColor_;}
float selectionHaloFillAlpha() const {return selectionHaloFill_;}
QVariant feature(Feature f) const {return features_.value(int(f));}
QVariant setFeature(Feature f, const QVariant & value) {QVariant ret = features_.value(int(f)); features_[int(f)] = value; return ret;}
bool isFeatureEnabled(Feature f) const {return features_[int(f)].toBool();}
int renderMode() const {return (int)rmode;}
void setRenderMode(int mode) {rmode = (ObjectBase::RenderMode)mode;}
// void addObject(GLObjectBase & o) {addObject(&o);}
Scene::SelectionMode selectionMode() const;
Qt::MouseButton selectionButton() const {return sel_button;}
Qt::KeyboardModifier selectionModifier() const {return sel_mod;}
void setSelectionMode(Scene::SelectionMode m);
void setSelectionButton(Qt::MouseButton v) {sel_button = v;}
void setSelectionModifier(Qt::KeyboardModifier v) {sel_mod = v;}
void selectObject(ObjectBase * o, bool add_to_selection = false);
void clearSelection();
QList<ObjectBase * > selectedObjects() const;
ObjectBase * selectedObject() const;
TextureManager * textureManager();
void reloadTextures();
Scene * scene() {return scene_;}
void focusOn(const Box3D & bb);
void setCameraLightOn(bool on);
bool isCameraLightOn() const;
Camera * camera();
const Camera * camera() const;
void setCamera(Camera * camera);
QByteArray saveCamera();
void restoreCamera(const QByteArray & ba);
QByteArray saveFeatures();
void restoreFeatures(const QByteArray & ba);
QImage materialThumbnail(Material * m);
GLfloat aspect, iaspect;
Renderer renderer_;
protected:
void render();
void resizeEvent(QResizeEvent * e);
void timerEvent(QTimerEvent * );
void initialize();
void resizeGL(int width, int height);
void mousePressEvent(QMouseEvent * e);
void mouseMoveEvent(QMouseEvent * e);
void mouseReleaseEvent(QMouseEvent * e);
void wheelEvent(QWheelEvent * e);
void leaveEvent(QEvent * );
void mouseDoubleClickEvent(QMouseEvent * e);
void keyPressEvent(QKeyEvent * e);
void keyReleaseEvent(QKeyEvent * e);
void focusOutEvent(QFocusEvent *);
void renderSelection();
void checkCaps();
private:
void processKeys();
bool setupViewport();
QPoint lastPos, downPos;
Scene * scene_;
Camera * camera_;
// uint cid;
QSet<int> keys_;
QColor backColor_, fogColor_, ambientColor_, hoverHaloColor_, selectionHaloColor_;
QTime time, ktm_;
GLint max_anisotropic, max_texture_chanels;
ObjectBase::RenderMode rmode;
QVector<ObjectBase * > hov_objects;
Qt::MouseButton sel_button;
Qt::KeyboardModifier sel_mod;
GLRendererBase::RenderingParameters start_rp;
QHash<int, QVariant> features_;
QSize prev_size;
float lineWidth_;
float fogDensity_, fogStart_, fogEnd_, fps_, fps_tm, hoverHaloFill_, selectionHaloFill_, m_motionBlurFactor;
int timer, fps_cnt, sh_id_loc, deleting_;
bool is_first_draw, is_init, fogEnabled_, lightEnabled_, grabMouse_, mouse_first, mouseRotate_, mouseSelect_, customMouseMove_, canSelect_;
bool shaders_supported, changed_, cameraOrbit_, need_init_;
bool hoverHalo_, selectionHalo_, shaders_bind, selecting_;
private slots:
void __destroyed();
public slots:
void setBackColor(const QColor & arg) {backColor_ = arg;}
void setLineWidth(const float & arg) {lineWidth_ = arg;}
void setFOV(const float & arg) {camera()->fov_ = arg;}
void setDepthStart(const float & arg) {camera()->depth_start = arg;}
void setDepthEnd(const float & arg) {camera()->depth_end = arg;}
void setAmbientColor(const QColor & arg) {ambientColor_ = arg;}
void setFogColor(const QColor & arg) {fogColor_ = arg;}
void setFogDensity(const float & arg) {fogDensity_ = arg;}
void setFogStart(const float & arg) {fogStart_ = arg;}
void setFogEnd(const float & arg) {fogEnd_ = arg;}
void setFogEnabled(const bool & arg) {fogEnabled_ = arg;}
void setLightEnabled(const bool & arg) {lightEnabled_ = arg;}
void setGrabMouseEnabled(const bool & arg) {grabMouse_ = arg; mouse_first = true;}
void setMouseRotateEnabled(const bool & arg) {mouseRotate_ = arg;}
void setMouseSelectionEnabled(const bool & arg) {mouseSelect_ = arg;}
void setCustomMouseMove(const bool & arg) {customMouseMove_ = arg;}
void setCameraOrbit(const bool & arg) {cameraOrbit_ = arg;}
void setHoverHaloEnabled(const bool & arg) {hoverHalo_ = arg;}
void setHoverHaloColor(const QColor & arg) {hoverHaloColor_ = arg;}
void setHoverHaloFillAlpha(const float & arg) {hoverHaloFill_ = arg;}
void setSelectionHaloEnabled(const bool & arg) {selectionHalo_ = arg;}
void setSelectionHaloColor(const QColor & arg) {selectionHaloColor_ = arg;}
void setSelectionHaloFillAlpha(const float & arg) {selectionHaloFill_ = arg;}
void reloadShaders() {renderer_.reloadShaders();}
signals:
void glBeforePaint();
void glBeginPaint();
void glPainting();
void glEndPaint();
void glKeyPressEvent(QKeyEvent * e);
void glKeyReleaseEvent(QKeyEvent * e);
void glMousePressEvent(QMouseEvent * e);
void glMouseMoveEvent(QMouseEvent * e);
void glMouseReleaseEvent(QMouseEvent * e);
void glWheelEvent(QWheelEvent * e);
void glResize(int, int);
void glInitializeDone();
void cameraPosChanged(QVector3D pos);
void keyEvent(Qt::Key key, Qt::KeyboardModifiers mod);
void customMouseMoveEvent(QPoint curpos, QPoint lastpos, Qt::MouseButtons buttons);
void hoverChanged(ObjectBase * cur, ObjectBase * prev);
void selectionChanged();
void materialsChanged();
void materialThumbnailCreated(Material*);
void doubleClick();
};
#endif // QGLVIEW_H

46
qglengine/qglview.qrc Normal file
View File

@@ -0,0 +1,46 @@
<RCC>
<qresource prefix="/">
<file>icons/add-type-camera.png</file>
<file>icons/add-type-geo.png</file>
<file>icons/add-type-light.png</file>
<file>icons/add-type-empty.png</file>
<file>icons/collapse.png</file>
<file>icons/expand.png</file>
<file>icons/edit-rename.png</file>
<file>icons/alpha.png</file>
<file>icons/application-exit.png</file>
<file>icons/configure.png</file>
<file>icons/dialog-close.png</file>
<file>icons/document-edit.png</file>
<file>icons/document-import.png</file>
<file>icons/document-new.png</file>
<file>icons/document-open.png</file>
<file>icons/document-save.png</file>
<file>icons/document-save-all.png</file>
<file>icons/edit-clear.png</file>
<file>icons/edit-clear-locationbar-rtl.png</file>
<file>icons/edit-copy.png</file>
<file>icons/edit-delete.png</file>
<file>icons/edit-find.png</file>
<file>icons/edit-paste.png</file>
<file>icons/go-jump.png</file>
<file>icons/go-top.png</file>
<file>icons/layer-visible-on.png</file>
<file>icons/layer-visible-off.png</file>
<file>icons/light-+.png</file>
<file>icons/list-add.png</file>
<file>icons/object-flip-horizontal.png</file>
<file>icons/object-flip-vertical.png</file>
<file>icons/picker.png</file>
<file>icons/qglview.png</file>
<file>icons/transform-move.png</file>
<file>icons/transform-rotate.png</file>
<file>icons/transform-scale.png</file>
<file>icons/type-camera.png</file>
<file>icons/type-geo.png</file>
<file>icons/type-light.png</file>
<file>icons/type-empty.png</file>
<file>icons/view-refresh.png</file>
<file>shaders/bloom_0.frag</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,34 @@
/*
Stanley Designer
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QApplication>
#include <QDebug>
#include <QDir>
#include "qglview_window.h"
int main(int argc, char ** argv) {
QApplication a(argc, argv);
a.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
QGLViewWindow w;
w.show();
QStringList al(a.arguments());
al.pop_front();
foreach (QString s, al)
w.loadFile(s);
return a.exec();
}

View File

@@ -0,0 +1,286 @@
/*
Stanley Designer
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qglview_window.h"
#include "renderer.h"
#include "glwidget.h"
#include <QGraphicsRectItem>
#include <QImageReader>
#include <QMessageBox>
QGLViewWindow::QGLViewWindow(QWidget * parent): QMainWindow(parent), Ui::QGLViewWindow() {
setupUi(this);
session.setFile("session_qglview_test.conf");
session.addEntry(this);
spinViewLineWidth->setValue(lineThickness()*2);
view->view()->camera()->setAim(QVector3D());
view->view()->camera()->setPos(QVector3D(2, 2, 2));
view->view()->camera()->flyToDistance(2.);
// view->setFrameShape(QFrame::NoFrame);
view->view()->setMouseRotateEnabled(true);
view->view()->setMouseSelectionEnabled(true);
view->view()->setSelectionHaloEnabled(true);
view->view()->setHoverHaloEnabled(true);
view->view()->setBackColor(Qt::lightGray);
view->view()->setDepthStart(0.1);
view->view()->setSelectionMode(Scene::smMultiSelection);
spinFOV->setValue(view->view()->FOV());
spinDepthStart->setValue(view->view()->depthStart());
spinDepthEnd->setValue(view->view()->depthEnd());
groupHoverHalo->setChecked(view->view()->isHoverHaloEnabled());
groupSelectionHalo->setChecked(view->view()->isSelectionHaloEnabled());
spinHoverHaloFill->setValue(view->view()->hoverHaloFillAlpha());
spinSelectionHaloFill->setValue(view->view()->selectionHaloFillAlpha());
colorHoverHalo->setColor(view->view()->hoverHaloColor());
colorSelectionHalo->setColor(view->view()->selectionHaloColor());
checkFXAA->setChecked(view->view()->isFeatureEnabled(QGLView::qglFXAA));
colorBack->setColor(view->view()->backColor());
colorAmbient->setColor(view->view()->ambientColor());
checkCameraOrbit->setChecked(view->view()->isCameraOrbit());
groupShadows->setChecked(view->view()->isFeatureEnabled(QGLView::qglShadowsEnabled));
groupEyeAccomodation->setChecked(view->view()->isFeatureEnabled(QGLView::qglEyeAccomodationEnabled));
groupBloom->setChecked(view->view()->isFeatureEnabled(QGLView::qglBloomEnabled));
groupMotionBlur->setChecked(view->view()->isFeatureEnabled(QGLView::qglMotionBlurEnabled));
groupReflections->setChecked(view->view()->isFeatureEnabled(QGLView::qglReflectionsEnabled));
checkSoftShadows->setChecked(view->view()->isFeatureEnabled(QGLView::qglShadowsSoftEnabled));
groupSSAO->setChecked(view->view()->isFeatureEnabled(QGLView::qglSSAOEnabled));
spinAccom->setValue(view->view()->feature(QGLView::qglEyeAccomodationTime).toDouble());
spinAccomMS->setValue(view->view()->feature(QGLView::qglEyeAccomodationMaxSpeed).toDouble());
checkReflectionsBlur->setChecked(view->view()->isFeatureEnabled(QGLView::qglReflectionsBlur));
spinShadowmapSize->setValue(view->view()->feature(QGLView::qglShadowsMapSize).toInt());
spinMotionBlurFactor->setValue(view->view()->feature(QGLView::qglMotionBlurFactor).toDouble());
spinMotionBlurSteps->setValue(view->view()->feature(QGLView::qglMotionBlurSteps).toInt());
spinBloomFactor->setValue(view->view()->feature(QGLView::qglBloomFactor).toDouble());
spinBloomRadius->setValue(view->view()->feature(QGLView::qglBloomRadius).toInt());
spinBloomThreshold->setValue(view->view()->feature(QGLView::qglBloomThreshold).toDouble());
spinSSAORadius->setValue(view->view()->feature(QGLView::qglSSAORadius).toInt());
groupDOF->setChecked(view->view()->isFeatureEnabled(QGLView::qglDepthOfFieldEnabled));
checkDOFAutoFocus->setChecked(view->view()->isFeatureEnabled(QGLView::qglDepthOfFieldAutoFocusEnabled));
spinDOFFocus->setValue(view->view()->feature(QGLView::qglDepthOfFieldFocus).toDouble());
spinDOFDiaphragm->setValue(view->view()->feature(QGLView::qglDepthOfFieldDiaphragm).toDouble());
spinDOFSpeed->setValue(view->view()->feature(QGLView::qglDepthOfFieldAutoFocusSpeed).toDouble());
view->view()->start(-1);
startTimer(1000/60);
connect(view->view(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
connect(view->view(), SIGNAL(keyEvent(Qt::Key, Qt::KeyboardModifiers)), this, SLOT(view_keyEvent(Qt::Key, Qt::KeyboardModifiers)));
//connect(matEditor, SIGNAL(changed()), this, SLOT(materialChanged()));
sceneTree->assignQGLView(view->view());
matEditor->assignQGLView(view->view());
session.load();
//matEditor->setMaterial(const_cast<ObjectBase*>(view->view()->scene()->rootObject()->child(0))->material());
/*Scene * sc = loadScene("truck.obj");
//view->view()->scene()->addScene(sc);
sc->rootObject()->moveY(-8);
for (int i = 0; i < 7; ++i) {
sc->rootObject()->moveY(2);
view->view()->scene()->addScene(sc);
}
//view->view()->scene()->dump();
delete sc;*/
}
QGLViewWindow::~QGLViewWindow() {
session.save();
//delete ps;
}
void QGLViewWindow::changeEvent(QEvent * e) {
QMainWindow::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
retranslateUi(this);
return;
}
}
void QGLViewWindow::timerEvent(QTimerEvent * ) {
//static double t = 0.;
//((RendererSimple*)(view->view()->renderer()))->mpos = view->view()->mapFromGlobal(QCursor::pos());
statusBar()->showMessage(QString("FPS: %1").arg(QString::number(view->view()->currentFPS(), 'f', 2)));
}
void QGLViewWindow::loadFile(const QString & path, bool import) {
prev_path = path;
QApplication::setOverrideCursor(Qt::WaitCursor);
QFileInfo fi(path);
Scene * s = nullptr;
if (fi.suffix().toLower() == "qgl") s = loadFromQGLFile(path);
else s = loadScene(path);
QApplication::restoreOverrideCursor();
if (!s) {
QMessageBox::critical(this, "Import", "Can`t load " + path + "!");
return;
}
s->setName(fi.baseName());
if (import) view->scene()->addScene(s);
else {
view->scene()->assignFrom(s);
view->view()->focusOn(view->scene()->boundingBox());
}
delete s;
}
void QGLViewWindow::selectionChanged() {
ObjectBase * sel_obj = view->view()->selectedObject();
//qDebug() << "selected" << (sel_obj ? sel_obj->name() : "0");
labelName->setText(sel_obj ? sel_obj->name() : "");
/**if (cur == 0) box->hide();
else {
box->setScale(cur->boundingBox().size());
box->setPos(cur->boundingBox().pos());
Box3D b = cur->boundingBox().movedTo(-cur->boundingBox().center());
b.z = -b.z - b.height;
ps->setEmitterRect(b);
cur->addChild(box);
box->show();
}*/
objectEditor->setObject(sel_obj);
//qDebug() << sel_obj->boundingBox();
}
void QGLViewWindow::on_actionReset_triggered() {
///view->view()->removeObject(axis, false);
view->view()->scene()->destroy();
///view->view()->addObject(axis);
}
void QGLViewWindow::on_actionImport_triggered() {
QStringList fl = QFileDialog::getOpenFileNames(this, "Select files", prev_path, "Supported types(*.qgl *.ase *.3ds *.obj *.dae);;"
"QGLView(*.qgl);;"
"Ascii Scene Export(*.ase);;"
"3D Studio(*.3ds);;"
"Wavefront OBJ(*.obj);;"
"Collada(*.dae)");
if (fl.isEmpty()) return;
prev_path = fl.back();
foreach (QString f, fl)
loadFile(f, true);
}
void QGLViewWindow::on_actionSave_triggered() {
QString f = QFileDialog::getSaveFileName(this, "Select file", prev_path, "QGLView(*.qgl)");
if (f.isEmpty()) return;
if (f.right(4).toLower() != ".qgl")
f += ".qgl";
prev_path = f;
QApplication::setOverrideCursor(Qt::WaitCursor);
saveToQGLFile(f, view->scene());
QApplication::restoreOverrideCursor();
}
void QGLViewWindow::on_actionSaveSelected_triggered() {
ObjectBase * sel_obj = view->view()->selectedObject();
if (!sel_obj) return;
QString f = QFileDialog::getSaveFileName(this, "Select file", prev_path, "QGLView(*.qgl)");
if (f.isEmpty()) return;
if (f.right(4).toLower() != ".qgl")
f += ".qgl";
prev_path = f;
QApplication::setOverrideCursor(Qt::WaitCursor);
///saveToQGLFile(f, sel_obj);
QApplication::restoreOverrideCursor();
}
void QGLViewWindow::on_actionOpen_triggered() {
QString f = QFileDialog::getOpenFileName(this, "Select file", prev_path, "Supported types(*.qgl *.ase *.3ds *.obj *.dae);;"
"QGLView(*.qgl);;"
"Ascii Scene Export(*.ase);;"
"3D Studio(*.3ds);;"
"Wavefront OBJ(*.obj);;"
"Collada(*.dae)");
if (f.isEmpty()) return;
prev_path = f;
loadFile(f);
}
void QGLViewWindow::view_keyEvent(Qt::Key k, Qt::KeyboardModifiers m) {
//qDebug() << k;
double spd = 0.2;
if (m.testFlag(Qt::ShiftModifier))
spd = 0.5;
switch (k) {
case Qt::Key_W: view->view()->camera()->moveForward(spd); break;
case Qt::Key_S: view->view()->camera()->moveBackward(spd); break;
case Qt::Key_A: view->view()->camera()->moveLeft(spd); break;
case Qt::Key_D: view->view()->camera()->moveRight(spd); break;
default: break;
}
}
\
void QGLViewWindow::on_pushButton_clicked() {
//view->view()->removeLight(view->view()->lightsCount() - 1);
//setWindowTitle(QString::number(view->view()->lightsCount()));
//QVector3D wp = view->view()->light(0)->worldPos();
//view->view()->camera()->setPos(wp);
//view->view()->camera()->setAim(wp + (view->view()->light(0)->worldTransform() * QVector4D(view->view()->light(0)->direction)).toVector3D()*100);
}
void QGLViewWindow::on_pushButton_3_clicked() {
/*QList<ObjectBase * > ol = view->view()->objects(true);
qDebug() << ol.size();
foreach (ObjectBase * i, ol) {
//i->VBO().rebuffer();
}*/
}
void QGLViewWindow::on_actionAdd_plane_triggered() {
ObjectBase * o = new ObjectBase(Primitive::plane());
o->setName("plane");
view->addObject(o->clone());
delete o;
}
void QGLViewWindow::on_actionAdd_cube_triggered() {
ObjectBase * o = new ObjectBase(Primitive::cube());
o->setName("cube");
view->addObject(o->clone());
delete o;
}
void QGLViewWindow::on_actionAdd_sphere_triggered() {
int seg_xy = 16, seg_z = 16;
seg_xy = QInputDialog::getInt(this, "New sphere", "XY segments:", seg_xy, 1, 200);
seg_z = QInputDialog::getInt(this, "New sphere", "Z segments:", seg_z , 1, 200);
ObjectBase * o = new ObjectBase(Primitive::ellipsoid(seg_xy, seg_z));
o->setName("sphere");
view->addObject(o->clone());
delete o;
}

View File

@@ -0,0 +1,131 @@
/*
Stanley Designer
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QGLVIEWWINDOW_H
#define QGLVIEWWINDOW_H
#include <QTranslator>
#include <QInputDialog>
#include <QFileDialog>
#include <QColorDialog>
#include <QCloseEvent>
#include <QClipboard>
#include <QRadioButton>
#include <QUrl>
#include <QThread>
#include <QTime>
#include <QSplitter>
#include "ui_qglview_window.h"
#include "formats/loader_qgl.h"
#include "formats/loader_assimp.h"
#include "session_manager.h"
//#include "renderer_rt.h"
#include "qglview.h"
#include "ui_qglview_window.h"
class QGLViewWindow: public QMainWindow, public Ui::QGLViewWindow
{
Q_OBJECT
public:
QGLViewWindow(QWidget * parent = 0);
~QGLViewWindow();
void loadFile(const QString & path, bool import = false);
private:
// Qt`s overloaded
void changeEvent(QEvent * e);
void timerEvent(QTimerEvent * );
QTranslator translator;
QString prev_path;
//GLPrimitiveCube * box;
Material m;
SessionManager session;
bool isChanged;
private slots:
void on_spinFOV_valueChanged(double val) {view->view()->setFOV(val);}
void on_spinDepthStart_valueChanged(double val) {view->view()->setDepthStart(val);}
void on_spinDepthEnd_valueChanged(double val) {view->view()->setDepthEnd(val);}
void on_comboViewRenderMode_currentIndexChanged(int val) {static int modes[] = {GL_POINT, GL_LINE, GL_FILL}; view->view()->setRenderMode((ObjectBase::RenderMode)modes[val]);}
void on_groupHoverHalo_clicked(bool val) {view->view()->setHoverHaloEnabled(val);}
void on_groupSelectionHalo_clicked(bool val) {view->view()->setSelectionHaloEnabled(val);}
void on_spinHoverHaloFill_valueChanged(double val) {view->view()->setHoverHaloFillAlpha(val);}
void on_spinSelectionHaloFill_valueChanged(double val) {view->view()->setSelectionHaloFillAlpha(val);}
void on_colorHoverHalo_colorChanged(QColor color) {view->view()->setHoverHaloColor(color);}
void on_colorSelectionHalo_colorChanged(QColor color) {view->view()->setSelectionHaloColor(color);}
void on_checkFXAA_clicked(bool val) {view->view()->setFeature(QGLView::qglFXAA, val);}
void on_colorBack_colorChanged(QColor color) {view->view()->setBackColor(color);}
void on_colorAmbient_colorChanged(QColor color) {view->view()->setAmbientColor(color);}
void on_checkCameraOrbit_clicked(bool val) {view->view()->setCameraOrbit(val);}
void on_checkCameraLight_clicked(bool val) {view->view()->setCameraLightOn(val);}
void on_spinViewLineWidth_valueChanged(double val) {view->view()->setLineWidth(val);}
void on_groupShadows_clicked(bool val) {view->view()->setFeature(QGLView::qglShadowsEnabled, val);}
void on_groupEyeAccomodation_clicked(bool val) {view->view()->setFeature(QGLView::qglEyeAccomodationEnabled, val);}
void on_groupBloom_clicked(bool val) {view->view()->setFeature(QGLView::qglBloomEnabled, val);}
void on_groupMotionBlur_clicked(bool val) {view->view()->setFeature(QGLView::qglMotionBlurEnabled, val);}
void on_groupReflections_clicked(bool val) {view->view()->setFeature(QGLView::qglReflectionsEnabled, val);}
void on_checkSoftShadows_clicked(bool val) {view->view()->setFeature(QGLView::qglShadowsSoftEnabled, val);}
void on_groupSSAO_clicked(bool val) {view->view()->setFeature(QGLView::qglSSAOEnabled, val);}
void on_groupDOF_clicked(bool val) {view->view()->setFeature(QGLView::qglDepthOfFieldEnabled, val);}
void on_checkDOFAutoFocus_clicked(bool val) {view->view()->setFeature(QGLView::qglDepthOfFieldAutoFocusEnabled, val);}
void on_spinDOFFocus_valueChanged(double val) {view->view()->setFeature(QGLView::qglDepthOfFieldFocus, val);}
void on_spinDOFDiaphragm_valueChanged(double val) {view->view()->setFeature(QGLView::qglDepthOfFieldDiaphragm, val);}
void on_spinDOFSpeed_valueChanged(double val) {view->view()->setFeature(QGLView::qglDepthOfFieldAutoFocusSpeed, val);}
void on_spinAccom_valueChanged(double val) {view->view()->setFeature(QGLView::qglEyeAccomodationTime, val);}
void on_spinAccomMS_valueChanged(double val) {view->view()->setFeature(QGLView::qglEyeAccomodationMaxSpeed, val);}
void on_checkReflectionsBlur_clicked(bool val) {view->view()->setFeature(QGLView::qglReflectionsBlur, val);}
void on_spinShadowmapSize_valueChanged(double val) {view->view()->setFeature(QGLView::qglShadowsMapSize, val);}
void on_spinMotionBlurFactor_valueChanged(double val) {view->view()->setFeature(QGLView::qglMotionBlurFactor, val);}
void on_spinMotionBlurSteps_valueChanged(int val) {view->view()->setFeature(QGLView::qglMotionBlurSteps, val);}
void on_spinBloomFactor_valueChanged(double val) {view->view()->setFeature(QGLView::qglBloomFactor, val);}
void on_spinBloomRadius_valueChanged(int val) {view->view()->setFeature(QGLView::qglBloomRadius, val);}
void on_spinBloomThreshold_valueChanged(double val) {view->view()->setFeature(QGLView::qglBloomThreshold, val);}
void on_spinSSAORadius_valueChanged(int val) {view->view()->setFeature(QGLView::qglSSAORadius, val);}
void on_actionExit_triggered() {close();}
void on_actionReset_triggered();
void on_actionImport_triggered();
void on_actionSave_triggered();
void on_actionSaveSelected_triggered();
void on_actionOpen_triggered();
void selectionChanged();
void view_keyEvent(Qt::Key k, Qt::KeyboardModifiers m);
void on_pushButton_clicked();
void on_pushButton_2_clicked() {view->view()->reloadShaders();}
void on_pushButton_3_clicked();
void on_actionAdd_plane_triggered();
void on_actionAdd_cube_triggered();
void on_actionAdd_sphere_triggered();
public slots:
signals:
private:
QMatrix4x4 cam_mat;
};
#endif // QGLVIEWWINDOW_H

View File

@@ -0,0 +1,1349 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QGLViewWindow</class>
<widget class="QMainWindow" name="QGLViewWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1125</width>
<height>1032</height>
</rect>
</property>
<property name="windowTitle">
<string>QGLView converter</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelName">
<property name="font">
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>View</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTabWidget" name="tabWidget_2">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_5">
<attribute name="title">
<string>Common</string>
</attribute>
<layout class="QFormLayout" name="formLayout_9">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>FOV</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SpinSlider" name="spinFOV">
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>179.900000000000006</double>
</property>
<property name="value">
<double>60.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Depth</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QDoubleSpinBox" name="spinDepthStart">
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string> - </string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinDepthEnd">
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Renderer</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboRenderer">
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Simple</string>
</property>
</item>
<item>
<property name="text">
<string>Deferred shading</string>
</property>
</item>
<item>
<property name="text">
<string>RT</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Draw mode</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboViewRenderMode">
<property name="currentIndex">
<number>2</number>
</property>
<item>
<property name="text">
<string>Point</string>
</property>
</item>
<item>
<property name="text">
<string>Wireframe</string>
</property>
</item>
<item>
<property name="text">
<string>Solid</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Back color</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="ColorButton" name="colorBack">
<property name="color">
<color>
<red>10</red>
<green>10</green>
<blue>10</blue>
</color>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Ambient</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="ColorButton" name="colorAmbient">
<property name="color">
<color>
<red>10</red>
<green>10</green>
<blue>10</blue>
</color>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="QCheckBox" name="checkMSAA">
<property name="text">
<string>MSAA</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QCheckBox" name="checkFXAA">
<property name="text">
<string>FXAA</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="QGroupBox" name="groupHoverHalo">
<property name="title">
<string>Hover halo</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<widget class="ColorButton" name="colorHoverHalo">
<property name="color">
<color>
<red>255</red>
<green>0</green>
<blue>251</blue>
</color>
</property>
<property name="useAlphaChannel">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Fill</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SpinSlider" name="spinHoverHaloFill">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.300000000000000</double>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="pageStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="10" column="0" colspan="2">
<widget class="QGroupBox" name="groupSelectionHalo">
<property name="title">
<string>Selection halo</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_8">
<item row="0" column="0" colspan="2">
<widget class="ColorButton" name="colorSelectionHalo">
<property name="color">
<color>
<red>0</red>
<green>143</green>
<blue>239</blue>
</color>
</property>
<property name="useAlphaChannel">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Fill</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SpinSlider" name="spinSelectionHaloFill">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.300000000000000</double>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="pageStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="11" column="0" colspan="2">
<widget class="QGroupBox" name="groupCamera">
<property name="title">
<string>Camera</string>
</property>
<layout class="QFormLayout" name="formLayout_10">
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="checkCameraOrbit">
<property name="text">
<string>Orbit</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="checkCameraLight">
<property name="text">
<string>Camera Light</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="6" column="1">
<widget class="QDoubleSpinBox" name="spinViewLineWidth">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Line width</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_6">
<attribute name="title">
<string>Features</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QScrollArea" name="scrollArea_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>960</width>
<height>737</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupShadows">
<property name="title">
<string>Shadows</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_3">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Shadowmap size</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SpinSlider" name="spinShadowmapSize">
<property name="minimum">
<double>16.000000000000000</double>
</property>
<property name="maximum">
<double>2048.000000000000000</double>
</property>
<property name="value">
<double>512.000000000000000</double>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="singleStep">
<double>16.000000000000000</double>
</property>
<property name="pageStep">
<double>512.000000000000000</double>
</property>
<property name="squareScale">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="checkSoftShadows">
<property name="text">
<string>Soft</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBloom">
<property name="title">
<string>Bloom</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_5">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Factror</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SpinSlider" name="spinBloomFactor">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="pageStep">
<double>1.000000000000000</double>
</property>
<property name="squareScale">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="SpinSlider" name="spinBloomRadius">
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>128.000000000000000</double>
</property>
<property name="value">
<double>8.000000000000000</double>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="pageStep">
<double>4.000000000000000</double>
</property>
<property name="squareScale">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Radius</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Threshold</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SpinSlider" name="spinBloomThreshold">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.900000000000000</double>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="pageStep">
<double>0.100000000000000</double>
</property>
<property name="squareScale">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupMotionBlur">
<property name="title">
<string>Motion blur</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Factror</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Steps</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SpinSlider" name="spinMotionBlurFactor">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="pageStep">
<double>1.000000000000000</double>
</property>
<property name="squareScale">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SpinSlider" name="spinMotionBlurSteps">
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>128.000000000000000</double>
</property>
<property name="value">
<double>8.000000000000000</double>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="pageStep">
<double>4.000000000000000</double>
</property>
<property name="squareScale">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupEyeAccomodation">
<property name="title">
<string>Eye accomodation</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_4">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Max speed</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SpinSlider" name="spinAccom">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>256.000000000000000</double>
</property>
<property name="value">
<double>32.000000000000000</double>
</property>
<property name="squareScale">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SpinSlider" name="spinAccomMS">
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.100000000000000</double>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="pageStep">
<double>1.000000000000000</double>
</property>
<property name="squareScale">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupDOF">
<property name="title">
<string>Depth of field</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_11">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="2" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Diaphragm</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Max speed</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="SpinSlider" name="spinDOFDiaphragm">
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>1024.000000000000000</double>
</property>
<property name="value">
<double>8.000000000000000</double>
</property>
<property name="squareScale">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="SpinSlider" name="spinDOFSpeed">
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>0.100000000000000</double>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="pageStep">
<double>1.000000000000000</double>
</property>
<property name="squareScale">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Focus</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SpinSlider" name="spinDOFFocus">
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
<property name="squareScale">
<bool>true</bool>
</property>
<property name="spinMaximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="checkDOFAutoFocus">
<property name="text">
<string>Auto focus</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupReflections">
<property name="title">
<string>Reflections</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_6">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="checkReflectionsBlur">
<property name="text">
<string>Blur</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupSSAO">
<property name="title">
<string>SSAO</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_7">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SpinSlider" name="spinSSAORadius">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>16.000000000000000</double>
</property>
<property name="value">
<double>5.000000000000000</double>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="pageStep">
<double>4.000000000000000</double>
</property>
<property name="squareScale">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>remove light</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>reload shaders</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>rebuff all</string>
</property>
</widget>
</item>
<item>
<widget class="ColorButton" name="colorMouse">
<property name="color">
<color>
<red>10</red>
<green>10</green>
<blue>10</blue>
</color>
</property>
<property name="useAlphaChannel">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>107</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Object</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="ObjectEditor" name="objectEditor" native="true"/>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Material</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>999</width>
<height>853</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="MaterialsEditor" name="matEditor" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>Страница</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="PropertyEditor" name="treeProps">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="GLWidget" name="view">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Scene</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="SceneTree" name="sceneTree" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionReset"/>
<addaction name="actionOpen"/>
<addaction name="actionSave"/>
<addaction name="actionSaveSelected"/>
<addaction name="actionImport"/>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1125</width>
<height>24</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionReset"/>
<addaction name="actionOpen"/>
<addaction name="actionSave"/>
<addaction name="actionSaveSelected"/>
<addaction name="separator"/>
<addaction name="actionImport"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuAdd">
<property name="title">
<string>Scene</string>
</property>
<addaction name="actionAdd_plane"/>
<addaction name="actionAdd_cube"/>
<addaction name="actionAdd_sphere"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuAdd"/>
</widget>
<widget class="QStatusBar" name="statusBar_"/>
<widget class="QToolBar" name="toolBar_2">
<property name="windowTitle">
<string>toolBar_2</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionAdd_plane"/>
<addaction name="actionAdd_cube"/>
<addaction name="actionAdd_sphere"/>
</widget>
<action name="actionExit">
<property name="icon">
<iconset resource="../../qad/application/qad_application.qrc">
<normaloff>:/icons/application-exit.png</normaloff>:/icons/application-exit.png</iconset>
</property>
<property name="text">
<string>Exit</string>
</property>
</action>
<action name="actionImport">
<property name="icon">
<iconset resource="../qglview.qrc">
<normaloff>:/icons/document-import.png</normaloff>:/icons/document-import.png</iconset>
</property>
<property name="text">
<string>Import ...</string>
</property>
<property name="shortcut">
<string>Ctrl+I</string>
</property>
</action>
<action name="actionOpen">
<property name="icon">
<iconset resource="../../qad/application/qad_application.qrc">
<normaloff>:/icons/document-open.png</normaloff>:/icons/document-open.png</iconset>
</property>
<property name="text">
<string>Open ...</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="actionSave">
<property name="icon">
<iconset resource="../../qad/application/qad_application.qrc">
<normaloff>:/icons/document-save-all.png</normaloff>:/icons/document-save-all.png</iconset>
</property>
<property name="text">
<string>Save ...</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actionReset">
<property name="icon">
<iconset resource="../../qad/application/qad_application.qrc">
<normaloff>:/icons/document-new.png</normaloff>:/icons/document-new.png</iconset>
</property>
<property name="text">
<string>Reset</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="actionSaveSelected">
<property name="icon">
<iconset resource="../../qad/utils/qad_utils.qrc">
<normaloff>:/icons/document-save.png</normaloff>:/icons/document-save.png</iconset>
</property>
<property name="text">
<string>Save selected ...</string>
</property>
<property name="toolTip">
<string>Save selected</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
<action name="actionAdd_cube">
<property name="text">
<string>Add cube</string>
</property>
</action>
<action name="actionAdd_sphere">
<property name="text">
<string>Add sphere</string>
</property>
</action>
<action name="actionAdd_plane">
<property name="text">
<string>Add plane</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>SpinSlider</class>
<extends>QWidget</extends>
<header>spinslider.h</header>
</customwidget>
<customwidget>
<class>ColorButton</class>
<extends>QPushButton</extends>
<header>colorbutton.h</header>
</customwidget>
<customwidget>
<class>GLWidget</class>
<extends>QWidget</extends>
<header>glwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ObjectEditor</class>
<extends>QWidget</extends>
<header>widgets/object_editor.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PropertyEditor</class>
<extends>QTreeWidget</extends>
<header>widgets/propertyeditor.h</header>
</customwidget>
<customwidget>
<class>SceneTree</class>
<extends>QWidget</extends>
<header>scene_tree.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>MaterialsEditor</class>
<extends>QWidget</extends>
<header>widgets/materials_editor.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../qad/utils/qad_utils.qrc"/>
<include location="../../qad/application/qad_application.qrc"/>
<include location="../qglview.qrc"/>
</resources>
<connections/>
</ui>

389
qglengine/renderer.cpp Normal file
View File

@@ -0,0 +1,389 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "renderer.h"
#include "qglview.h"
#include "glmesh.h"
#include "gltexture_manager.h"
#include <qad_types.h>
using namespace QGLEngineShaders;
Renderer::Renderer(QGLView * view_): RendererBase(view_),
fbo_selection(view_, 4),
fbo_ds (view_, 5, true , GL_RGBA16F),
fbo_out (view_, 3, false, GL_RGBA16F),
fbo_hsmall (view_, 1, false, GL_RGB16F ),
rend_mat(this), rend_service(this) {
quad = Primitive::plane(2., 2.);
sel_frame = quad->clone();
cam_light = new Light();
cam_light->intensity = 0.75;
cam_light->setName("Camera_Light");
line_thick_ = 2.;
id_hover = 0;
shader_files[srSelectionFill ] = "selection.glsl";
shader_files[srSelectionHalo ] = "selection_halo.glsl";
shader_files[srSelectionApply] = "selection_apply.glsl";
shader_files[srSelectionFrame] = "selection_frame.glsl";
shader_files[srService] = "service.glsl";
shader_files[srGeometryPass] = "ds_geom.glsl";
shader_files[srLightingPass] = "ds_light.glsl";
shader_files[srFinalPass ] = "ds_final.glsl";
/*shaders << ShaderPair("FXAA", &shader_fxaa)
<< ShaderPair("dsl_pass_0", &shader_ds_0)
<< ShaderPair("dsl_pass_1", &shader_ds_1)
<< ShaderPair("hdr", &shader_hdr)
<< ShaderPair("downscale", &shader_small)
<< ShaderPair("bloom_pass_0", &shader_bloom_0)
<< ShaderPair("bloom_pass_1", &shader_bloom_1)
<< ShaderPair("fbo_add", &shader_fbo_add)
<< ShaderPair("motion_blur", &shader_motion_blur)
<< ShaderPair("shadow", &shader_shadow)
<< ShaderPair("ssr", &shader_ssr)
<< ShaderPair("ssr_blur", &shader_ssr_blur)
<< ShaderPair("ssr_merge", &shader_ssr_merge)
<< ShaderPair("ssao_blur", &shader_ssao_blur)
<< ShaderPair("ssao_merge", &shader_ssao_merge)
<< ShaderPair("dof", &shader_dof);*/
exposure_ = 1.;
edit_mode = need_init_shaders = is_camera_light = true;
proc_sel_pbo = false;
}
Renderer::~Renderer() {
delete quad;
delete sel_frame;
delete cam_light;
qDeleteAll(shaders.values());
}
void Renderer::init(int width, int height) {
resize(width, height);
rend_mat.init(width, height);
rend_service.init(width, height);
initQuad(quad);
initTextureArrays();
need_init_shaders = true;
}
void Renderer::resize(int width, int height) {
rend_mat.resize(width, height);
rend_service.resize(width, height);
fbo_selection.enablePixelBuffer();
fbo_selection.resize(width, height);
fbo_ds .resize(width, height);
fbo_out .resize(width, height);
fbo_hsmall .resize(width / 16, height / 16);
line_thick_ = lineThickness() + 1.;
}
void Renderer::reloadShaders() {
QMapIterator<ShaderRole, QString> it(shader_files);
while (it.hasNext()) {
it.next();
loadShadersMulti(shaders[it.key()], "shaders/" + it.value());
}
need_init_shaders = true;
}
bool Renderer::bindShader(Renderer::ShaderRole role, QOpenGLShaderProgram ** ret) {
QOpenGLShaderProgram * prog = shaders.value(role);
if (ret) *ret = prog;
if (!prog) return false;
if (!prog->isLinked()) return false;
prog->bind();
return true;
}
void Renderer::initShaders() {
if (!need_init_shaders) return;
need_init_shaders = false;
initUniformBuffer(shaders.value(srGeometryPass), &buffer_materials , bpMaterials , "QGLMaterialData" );
initUniformBuffer(shaders.value(srLightingPass), &buffer_materials , bpMaterials , "QGLMaterialData" );
initUniformBuffer(shaders.value(srLightingPass), &buffer_lights , bpLightParameters, "QGLLightParameterData");
initUniformBuffer(shaders.value(srLightingPass), &buffer_lights_pos, bpLightPositions , "QGLLightPositionData" );
}
void Renderer::releaseShader() {
view->glUseProgram(0);
}
void Renderer::generateObjectsID(Scene & scene) {
ids.clear();
QMapIterator<Mesh*, QList<ObjectBase*> > it(scene.geometries_used);
while (it.hasNext()) {
it.next();
foreach (ObjectBase * o, it.value()) {
uint id = qHash(o);
ids[id] = o;
o->id_ = id;
}
}
}
void Renderer::fillSelectionsBuffer(const QList<ObjectBase *> & ol) {
cur_selections_.resize(ol.size());
for (int i = 0; i < ol.size(); ++i) {
cur_selections_[i] = (ol[i]->isSelected(true) ? 1 : 0);
}
}
void Renderer::fillObjectsBuffer(const QList<ObjectBase *> & ol, RenderPass pass) {
cur_objects_.resize(ol.size());
for (int i = 0; i < ol.size(); ++i) {
Object & so(cur_objects_[i]);
ObjectBase * o = ol[i];
if (o->material()) {
so.material = o->material()->_index;
so.color = QVector4D(1,1,1,1);
} else {
so.material = 0;
so.color = QColor2QVector(o->color_);
}
so.object_id = o->id_;
o->worldTransform().transposed().copyDataTo(so.modelmatrix);
//qDebug() << "load obj" << o->name() << o->worldTransform();
}
//qDebug() << "fillObjectsBuffer" << ol.size();
}
void Renderer::renderObjects(Scene & scene, RenderPass pass) {
QOpenGLExtraFunctions * f = view;
QMapIterator<Mesh*, QList<ObjectBase*> > it(scene.geometries_used);
while (it.hasNext()) {
it.next();
Mesh * mesh = it.key();
if (mesh->objects_changed) {
mesh->objects_changed = false;
fillObjectsBuffer(it.value(), pass);
mesh->loadObjects(f, cur_objects_);
}
if (mesh->selected_changed && edit_mode) {
mesh->selected_changed = false;
fillSelectionsBuffer(it.value());
mesh->loadSelections(f, cur_selections_);
}
mesh->draw(f, it.value().size());
}
}
void Renderer::renderSelection(Scene & scene) {
QOpenGLShaderProgram * prog = 0;
if (bindShader(srSelectionFill, &prog)) {
view->hov_objects.clear();
id_hover = 0;
if (fbo_selection.queriedPoints() > 0) {
if (fbo_selection.queriedPoints() == 1) {
id_hover = fbo_selection.getPoint();
view->hov_objects.resize(1);
view->hov_objects[0] = ids.value(id_hover);
//qDebug() << id_hover;
} else {
QVector<uint> points = fbo_selection.getPoints();
QSet<uint> ids_hover;
foreach (uint i, points)
ids_hover << i;
view->hov_objects.clear();
foreach (uint i, ids_hover)
view->hov_objects << ids.value(i);
//qDebug() << ids_hover;
}
}
fbo_selection.bind();
fbo_selection.setWriteBuffers();
glEnableDepth();
glClearFramebuffer(QColor(0,0,0,0));
setUniformCamera(prog, view->camera());
renderObjects(scene, rpSelection);
//mouse_rect = fbo_selection.rect();
if (mouse_rect.isNull())
fbo_selection.queryPoint(0, mouse_pos);
else
fbo_selection.queryPoints(0, mouse_rect);
//qDebug() << id_hover;
fbo_selection.bindColorTextures();
fbo_selection.setWriteBuffers();
if (!view->hoverHalo_ && !view->selectionHalo_)
glClearFramebuffer(QColor(0,0,0,0), false);
else {
bindShader(srSelectionHalo, &prog);
setUniformHalo(prog, "hover" , view->hoverHaloColor() , view->hoverHaloFillAlpha());
setUniformHalo(prog, "selection", view->selectionHaloColor(), view->selectionHaloFillAlpha());
prog->setUniformValue("has_hover" , view->hoverHalo_ && (id_hover > 0) ? 1.f : 0.f);
prog->setUniformValue("has_selection", view->selectionHalo_ ? 1.f : 0.f);
prog->setUniformValue("fb_hover" , (int)sbrSrcHover);
prog->setUniformValue("fb_selection", (int)sbrSrcSelect);
prog->setUniformValue("hover_id", QVector4D(float( id_hover & 0xFF) / 255.f,
float((id_hover >> 8 ) & 0xFF) / 255.f,
float((id_hover >> 16) & 0xFF) / 255.f,
float((id_hover >> 24) & 0xFF) / 255.f));
renderQuad(prog, quad, view->camera());
}
fbo_selection.release();
}
}
void Renderer::renderSelectionFrame() {
QOpenGLShaderProgram * prog = 0;
if (bindShader(srSelectionFrame, &prog)) {
QMatrix4x4 mat;
double mrx = mouse_rect.x(), mrw = mouse_rect.width() , vw = view->width();
double mry = mouse_rect.y(), mrh = mouse_rect.height(), vh = view->height();
mat.translate(-1. + (mrw + mrx*2) / vw, 1. - (mrh + mry*2) / vh, 0.);
mat.scale(mrw / vw, mrh / vh, 0.);
initQuad(sel_frame, mat);
prog->setUniformValue("size", QVector2D(mrw / vw, mrh / vh));
prog->setUniformValue("thickness", line_thick_);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
renderQuad(prog, sel_frame);
glDisable(GL_BLEND);
}
}
void Renderer::renderScene() {
initShaders();
QOpenGLExtraFunctions * f = view;
Scene & scene(*(view->scene_));
Camera * cam = view->camera();
QOpenGLShaderProgram * prog = 0;
bool scene_changed = scene.prepare();
/// reload materials on change
if (scene_changed || scene.need_reload_materials) {
if (scene.need_reload_materials)
maps_hash = 0;
generateObjectsID(scene);
reloadMaterials(scene);
if (edit_mode)
recreateMaterialThumbnails();
emit view->materialsChanged();
}
/// material thumbnails
if (edit_mode && !scene_changed) {
rend_mat.procQueue();
}
/// lights
QList<Light*> ll = scene.lights_used;
if (is_camera_light) {
ll << cam_light;
cam_light->setPos(cam->pos());
}
if (scene.lights_changed) {
scene.lights_changed = false;
reloadLightsParameters(ll);
}
reloadLightsPositions(ll, cam);
/// selection
if (edit_mode) {
renderSelection(scene);
}
/// geometry pass
fbo_ds.bind();
glEnableDepth();
glClearFramebuffer();
if (bindShader(srGeometryPass, &prog)) {
setUniformMaps(prog);
setUniformCamera(prog, cam);
textures_empty.bind(f, tarEmpty);
textures_maps .bind(f, tarMaps );
renderObjects(scene, rpSolid);
}
fbo_ds.release();
/// lighting pass
fbo_ds.bindColorTextures();
fbo_ds.bindDepthTexture(5);
fbo_out.bind();
if (bindShader(srLightingPass, &prog)) {
setUniformCamera(prog, cam);
setUniformViewCorners(prog, cam);
for (int i = 0; i < 5; ++i)
prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i);
prog->setUniformValue("tex_d", 5);
prog->setUniformValue("lights_count", ll.size());
glClearFramebuffer(view->backColor(), false);
renderQuad(prog, quad, cam);
/*QVector<float> _fb = fbo_out.grabF(0);
if (!_fb.isEmpty()) {
double sum = 0.;
foreach (float f, _fb) sum += f;
sum /= _fb.size();
qDebug() << "sum =" << sum;
}*/
}
fbo_out.release();
/// apply hovers and selection frame
if (edit_mode) {
if (bindShader(srSelectionApply, &prog)) {
fbo_selection.bindColorTextures();
fbo_out.bindColorTexture(0);
prog->setUniformValue("fb_out" , 0);
prog->setUniformValue("fb_hover" , (int)sbrHovered );
prog->setUniformValue("fb_select", (int)sbrSelected);
renderQuad(prog, quad, cam);
if (!mouse_rect.isNull()) {
renderSelectionFrame();
}
rend_service.renderService();
}
} else {
fbo_out.blit(0, 0, 0, fbo_out.rect(), QRect(QPoint(), view->size()));
}
}
void Renderer::setCameraLightOn(bool on) {
is_camera_light = on;
view->scene()->setLightsChanged();
}

123
qglengine/renderer.h Normal file
View File

@@ -0,0 +1,123 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RENDERER_H
#define RENDERER_H
#include "renderer_base.h"
#include "renderer_material.h"
#include "renderer_service.h"
#include <QQueue>
class Renderer: public RendererBase {
friend class QGLView;
friend class RendererMaterial;
friend class RendererService;
enum RenderPass {
rpSolid,
rpTransparent,
rpSelection,
rpShadow,
rpNoProc,
};
enum ShaderRole {
// Selection
srSelectionFill,
srSelectionHalo,
srSelectionApply,
srSelectionFrame,
// Service
srService,
// Deferred shading
srGeometryPass,
srLightingPass,
srFinalPass,
};
enum DeferredBufferRole {
dbrDiffuseRough,
dbrNormalReflect,
dbrSpecularHeight,
dbrEmissionBitangX,
dbrSpeedBitangXY,
};
enum SelectionBufferRole {
sbrSrcHover,
sbrSrcSelect,
sbrHovered,
sbrSelected
};
public:
Renderer(QGLView * view_);
virtual ~Renderer();
void init(int width, int height);
void resize(int width, int height);
void reloadShaders();
void renderScene();
void setCameraLightOn(bool on);
bool isCameraLightOn() const {return is_camera_light;}
QImage materialThumbnail(Material * m) {return rend_mat.materialThumbnail(m);}
void recreateMaterialThumbnails(bool force_all = false) {rend_mat.recreateMaterialThumbnails(force_all);}
protected:
void generateObjectsID(Scene & scene);
void fillSelectionsBuffer(const QList<ObjectBase *> & ol);
void fillObjectsBuffer(const QList<ObjectBase*> & ol, RenderPass pass);
void reloadObjects();
void renderObjects(Scene & scene, RenderPass pass);
void renderSelection(Scene & scene);
void renderSelectionFrame();
bool bindShader(ShaderRole role, QOpenGLShaderProgram ** ret = 0);
void initShaders();
void releaseShader();
private:
float exposure_, line_thick_;
bool edit_mode, proc_sel_pbo, need_init_shaders, is_camera_light;
Framebuffer fbo_selection, fbo_ds, fbo_out, fbo_hsmall;
/*QOpenGLShaderProgram * shader_fxaa, * shader_ds_0, * shader_ds_1, * shader_hdr, * shader_small;
QOpenGLShaderProgram * shader_bloom_0, * shader_bloom_1, * shader_motion_blur, * shader_fbo_add;
QOpenGLShaderProgram * shader_shadow, * shader_ssr, * shader_ssr_blur, * shader_ssr_merge;
QOpenGLShaderProgram * shader_ssao_blur, * shader_ssao_merge, * shader_dof;*/
QMap<ShaderRole, QString> shader_files;
QMap<ShaderRole, QOpenGLShaderProgram*> shaders;
RendererMaterial rend_mat;
RendererService rend_service;
Mesh * quad, * sel_frame;
Light * cam_light;
QHash<uint, ObjectBase * > ids;
uint id_hover;
QPoint mouse_pos;
QRect mouse_rect;
QMatrix4x4 prev_view, prev_proj;
QMatrix3x3 nm;
QVector4D corner_dirs[4];
QVector<QVector3D> hcontent;
};
#endif // RENDERER_H

275
qglengine/renderer_base.cpp Normal file
View File

@@ -0,0 +1,275 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "renderer_base.h"
#include "qglview.h"
#include "glmesh.h"
#include "gltexture_manager.h"
#include "glshaders_headers.h"
using namespace QGLEngineShaders;
RendererBase::RendererBase(QGLView * view_):
view(view_),
buffer_materials (GL_UNIFORM_BUFFER, GL_STREAM_DRAW),
buffer_lights (GL_UNIFORM_BUFFER, GL_STREAM_DRAW),
buffer_lights_pos(GL_UNIFORM_BUFFER, GL_STREAM_DRAW),
textures_empty(false),
textures_maps(true)
{
textures_manager = new TextureManager(view);
maps_size = QSize(512, 512);
maps_hash = 0;
}
RendererBase::~RendererBase() {
delete textures_manager;
}
void RendererBase::initTextureArrays() {
QOpenGLExtraFunctions * f = view;
textures_maps.init(f);
textures_empty.init(f);
textures_empty.resize(f, QSize(1, 1), 2);
textures_empty.bind(f);
QImage im(1, 1, QImage::Format_RGBA8888);
im.fill(0xFFFFFFFF);
textures_empty.load(f, im, emrWhite);
im.fill(0xFF8080);
textures_empty.load(f, im, emrBlue);
}
void RendererBase::initUniformBuffer(QOpenGLShaderProgram * prog, Buffer * buffer, int bind_point, const char * blockName) {
if (!prog || !buffer) return;
if (!prog->isLinked()) return;
QOpenGLExtraFunctions * f = view;
buffer->init(f);
//glClearError();
GLint ubo_ind = f->glGetUniformBlockIndex(prog->programId(), blockName);
f->glUniformBlockBinding(prog->programId(), ubo_ind, bind_point);
f->glBindBufferBase(GL_UNIFORM_BUFFER, bind_point, buffer->ID());
//qDebug() << "initUBO" << QString::number(f->glGetError(), 16);
}
void RendererBase::setUniformHalo(QOpenGLShaderProgram * prog, const char * type, QColor color, float fill) {
prog->setUniformValue((QString(type) + "_color").toLatin1().constData(), color);
prog->setUniformValue((QString(type) + "_fill" ).toLatin1().constData(), fill);
}
void RendererBase::setUniformMaps(QOpenGLShaderProgram * prog) {
prog->setUniformValue("qgl_texture_array[0]", (int)tarEmpty);
prog->setUniformValue("qgl_texture_array[1]", (int)tarMaps );
}
void RendererBase::setUniformCamera(QOpenGLShaderProgram * prog, Camera * cam, bool matrices, QSize viewport) {
double w = view->width(), h = view->height();
if (viewport.isValid()) {
w = viewport.width();
h = viewport.height();
}
QMatrix4x4 mat_view, mat_proj;
if (cam) {
if (matrices) {
mat_view = cam->viewMatrix() * cam->offsetMatrix();
mat_proj = cam->projectionMatrix(w / h);
}
prog->setUniformValue("z_near", cam->depthStart());
}
prog->setUniformValue("dt", QVector2D(1. / w, 1. / h));
prog->setUniformValue("qgl_ViewMatrix" , mat_view);
prog->setUniformValue("qgl_ViewProjMatrix", mat_proj * mat_view);
}
void RendererBase::setUniformViewCorners(QOpenGLShaderProgram * prog, Camera * cam, QSize viewport) {
double w = view->width(), h = view->height();
if (viewport.isValid()) {
w = viewport.width();
h = viewport.height();
}
QMatrix4x4 mproji = cam->projectionMatrix(w / h).inverted();
QVector4D corner_dirs[4];
corner_dirs[0] = (mproji * QVector4D(-1, -1, 0, 1));
corner_dirs[1] = (mproji * QVector4D(-1, 1, 0, 1));
corner_dirs[2] = (mproji * QVector4D( 1, 1, 0, 1));
corner_dirs[3] = (mproji * QVector4D( 1, -1, 0, 1));
for (int i = 0; i < 4; ++i)
prog->setUniformValue(QString("view_corners[%1]").arg(i).toLatin1().constData(), corner_dirs[i]);
}
void RendererBase::reloadMaterials(Scene & scene) {
//qDebug() << "reloadMaterias";
QList<Map*> maps[2];
QMap<QString, int> tex_layers[2];
foreach (Material * m, scene.materials) {
if (m->map_diffuse .hasBitmap()) maps[0] << &(m->map_diffuse );
if (m->map_normal .hasBitmap()) maps[1] << &(m->map_normal );
if (m->map_specular .hasBitmap()) maps[0] << &(m->map_specular );
if (m->map_roughness.hasBitmap()) maps[0] << &(m->map_roughness);
if (m->map_emission .hasBitmap()) maps[0] << &(m->map_emission );
if (m->map_relief .hasBitmap()) maps[0] << &(m->map_relief );
}
for (int i = 0; i < 2; ++i) {
foreach (Map * m, maps[i])
tex_layers[i][m->bitmap_path] = 0;
}
int layers_count = tex_layers[0].size() + tex_layers[1].size(), cl = -1;
uint cur_maps_hash = qHash(tex_layers[0].keys()) ^ qHash(tex_layers[1].keys());
if (maps_hash != cur_maps_hash) {
maps_hash = cur_maps_hash;
textures_maps.resize(view, maps_size, layers_count);
textures_maps.bind(view);
for (int i = 0; i < 2; ++i) {
QMutableMapIterator<QString, int> it(tex_layers[i]);
while (it.hasNext()) {
it.next();
QImage im = textures_manager->loadTextureImage(it.key(), i == 1);
textures_maps.load(view, im, ++cl);
it.value() = cl;
}
foreach (Map * m, maps[i]) {
m->_layer = tex_layers[i].value(m->bitmap_path);
//qDebug() << "assign" << m->bitmap_path << "layer" << m->_layer;
}
}
textures_maps.mipmaps(view);
qDebug() << "load" << (cl+1) << "bitmaps";
}
QGLMaterial glm;
cur_materials_.clear();
cur_materials_ << glm;
foreach (Material * m, scene.materials) {
if (cur_materials_.size() >= max_materials) {
qDebug() << "[QGLEngine] Warning: Too many materials! Maximum" << max_materials;
break;
}
//m->load(textures_manager);
m->_index = cur_materials_.size();
m->_changed = false;
glm.color_diffuse = QColor2QVector(m->color_diffuse );
glm.color_specular = QColor2QVector(m->color_specular);
glm.color_emission = QColor2QVector(m->color_emission);
glm.transparency = m->transparency;
glm.reflectivity = m->reflectivity;
glm.iof = m->iof ;
glm.dispersion = m->dispersion ;
m->map_diffuse .copyToQGLMap(glm.map[mtDiffuse ]);
m->map_normal .copyToQGLMap(glm.map[mtNormal ]);
m->map_specular .copyToQGLMap(glm.map[mtSpecular ]);
m->map_roughness.copyToQGLMap(glm.map[mtRoughness]);
m->map_emission .copyToQGLMap(glm.map[mtEmission ]);
m->map_relief .copyToQGLMap(glm.map[mtRelief ]);
cur_materials_ << glm;
}
//qDebug() << "load" << cur_materials_.size() << "materials";
//textures_maps.resize(maps_size, );
//cur_materials_[0].color_diffuse = QColor2QVector(Qt::red);
buffer_materials.bind(view);
buffer_materials.resize(view, cur_materials_.size() * sizeof(QGLMaterial));
buffer_materials.load(view, cur_materials_.constData(), cur_materials_.size() * sizeof(QGLMaterial));
scene.need_reload_materials = false;
}
void RendererBase::reloadLightsParameters(const QList<Light*> & lights) {
cur_lights_params_.resize(qMin(lights.size(), max_lights));
//qDebug() << "reloadLightsParameters" << cur_lights_params_.size();
for (int i = 0; i < cur_lights_params_.size(); ++i) {
QGLLightParameter & so(cur_lights_params_[i]);
Light * l = lights[i];
double ang_start = l->angle_start / 2.f, ang_end = l->angle_end / 2.f;
if (l->light_type == Light::Omni)
ang_start = ang_end = 180.;
//qDebug() << "light" << light->name() << ulightn << pos;
so.intensity = l->intensity;
so.startAngle = ang_start;
so.startAngleCos = cos(ang_start * deg2rad);
so.endAngle = ang_end;
so.endAngleCos = cos(ang_end * deg2rad);
so.color = QColor2QVector(l->color_);
so.constantAttenuation = l->decay_const;
so.linearAttenuation = l->decay_linear;
so.quadraticAttenuation = l->decay_quadratic;
//so.shadow = shadow;
//so.shadowColor = shadow;
}
buffer_lights.bind(view);
buffer_lights.resize(view, cur_lights_params_.size() * sizeof(QGLLightParameter));
buffer_lights.load(view, cur_lights_params_.constData(), cur_lights_params_.size() * sizeof(QGLLightParameter));
}
void RendererBase::reloadLightsPositions(const QList<Light *> & lights, Camera * cam) {
cur_lights_pos_.resize(qMin(lights.size(), max_lights));
QMatrix4x4 mat = cam->viewMatrix() * cam->offsetMatrix();
for (int i = 0; i < cur_lights_pos_.size(); ++i) {
QGLLightPosition & so(cur_lights_pos_[i]);
Light * l = lights[i];
QMatrix4x4 m = mat * l->worldTransform();
QVector4D pos(0, 0, 0, 1.), dir(l->direction, 1);//, dir0(light->dir0), dir1(light->dir1);
pos = m * pos;
dir = ((m * dir) - pos).normalized();
so.position = pos;
so.direction = dir;
//so.shadowMatrix = l->shadow_matrix;
}
buffer_lights_pos.bind(view);
buffer_lights_pos.resize(view, cur_lights_pos_.size() * sizeof(QGLLightPosition));
buffer_lights_pos.load(view, cur_lights_pos_.constData(), cur_lights_pos_.size() * sizeof(QGLLightPosition));
}
void RendererBase::markReloadTextures() {
maps_hash = 0;
textures_manager->clearImageCache();
view->scene_->need_reload_materials = true;
}
void RendererBase::setMapsSize(QSize sz) {
maps_size = sz;
markReloadTextures();
}
void RendererBase::initQuad(Mesh * mesh, QMatrix4x4 mat) {
QGLEngineShaders::Object quab_object;
mat.transposed().copyDataTo(quab_object.modelmatrix);
mesh->init(view);
mesh->loadObject(view, quab_object);
}
void RendererBase::renderQuad(QOpenGLShaderProgram * prog, Mesh * mesh, Camera * cam) {
glDisableDepth();
setUniformCamera(prog, cam, false);
mesh->draw(view, 1);
}

62
qglengine/renderer_base.h Normal file
View File

@@ -0,0 +1,62 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RENDERER_BASE_H
#define RENDERER_BASE_H
#include "glshaders_types.h"
#include "gltexturearray.h"
#include "glbuffer.h"
class RendererBase {
public:
RendererBase(QGLView * view_);
~RendererBase();
protected:
void initTextureArrays();
void initUniformBuffer (QOpenGLShaderProgram * prog, Buffer * buffer, int bind_point, const char * blockName);
void setUniformHalo (QOpenGLShaderProgram * prog, const char * type, QColor color, float fill);
void setUniformMaps (QOpenGLShaderProgram * prog);
void setUniformCamera (QOpenGLShaderProgram * prog, Camera * cam, bool matrices = true, QSize viewport = QSize());
void setUniformViewCorners(QOpenGLShaderProgram * prog, Camera * cam, QSize viewport = QSize());
void reloadMaterials(Scene & scene);
void reloadLightsParameters(const QList<Light*> & lights);
void reloadLightsPositions (const QList<Light*> & lights, Camera * cam);
void markReloadTextures();
void setMapsSize(QSize sz);
void initQuad(Mesh * mesh, QMatrix4x4 mat = QMatrix4x4());
void renderQuad(QOpenGLShaderProgram * prog, Mesh * mesh, Camera * cam = 0);
QGLView * view;
TextureManager * textures_manager;
QVector<QGLEngineShaders::Object> cur_objects_;
QVector<QGLEngineShaders::QGLMaterial> cur_materials_;
QVector<QGLEngineShaders::QGLLightParameter> cur_lights_params_;
QVector<QGLEngineShaders::QGLLightPosition> cur_lights_pos_;
QVector<uchar> cur_selections_;
Buffer buffer_materials;
Buffer buffer_lights, buffer_lights_pos;
Texture2DArray textures_empty, textures_maps;
QSize maps_size;
uint maps_hash;
};
#endif // RENDERER_BASE_H

View File

@@ -0,0 +1,131 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "renderer_material.h"
#include "renderer.h"
#include "qglview.h"
#include "glmesh.h"
#include "gltexture_manager.h"
#include <qad_types.h>
using namespace QGLEngineShaders;
RendererMaterial::RendererMaterial(Renderer * r_): r(r_),
fbo_mat_thumb(r->view, 6, true , GL_RGBA16F) {
mat_sphere = Primitive::ellipsoid(16, 16);
mat_camera = new Camera();
mat_camera->setAim(QVector3D());
mat_camera->setPos(QVector3D(1, 1, 1));
mat_camera->setFOV(45.);
mat_light = new Light();
mat_light->setPos(QVector3D(50, 100, 25));
last_thumb_material = 0;
}
RendererMaterial::~RendererMaterial() {
delete mat_sphere;
delete mat_camera;
delete mat_light;
}
void RendererMaterial::init(int width, int height) {
resize(width, height);
}
void RendererMaterial::resize(int width, int height) {
fbo_mat_thumb.enablePixelBuffer();
fbo_mat_thumb.resize(256, 256);
}
void RendererMaterial::renderMaterial(Material * m) {
//qDebug() << "renderMaterial" << m;
last_thumb_material = m;
QOpenGLShaderProgram * prog = 0;
QOpenGLExtraFunctions * f = r->view;
fbo_mat_thumb.bind();
glEnableDepth();
glClearFramebuffer();
if (r->bindShader(Renderer::srGeometryPass, &prog)) {
r->setUniformMaps(prog);
r->setUniformCamera(prog, mat_camera, true, fbo_mat_thumb.size());
//qDebug() << mat_camera->viewMatrix();
r->textures_empty.bind(f, tarEmpty);
r->textures_maps .bind(f, tarMaps );
Object o;
o.material = m->_index;
mat_sphere->loadObject(f, o);
mat_sphere->draw(f, 1);
}
fbo_mat_thumb.bindColorTextures();
fbo_mat_thumb.bindDepthTexture(5);
fbo_mat_thumb.setWriteBuffer(5);
if (r->bindShader(Renderer::srLightingPass, &prog)) {
r->setUniformCamera(prog, mat_camera, true, fbo_mat_thumb.size());
r->setUniformViewCorners(prog, mat_camera, fbo_mat_thumb.size());
for (int i = 0; i < 5; ++i)
prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i);
prog->setUniformValue("tex_d", 5);
prog->setUniformValue("lights_count", 1);
QList<Light*> mat_l;
mat_l << mat_light;
r->reloadLightsParameters(mat_l);
r->reloadLightsPositions(mat_l, mat_camera);
glClearFramebuffer(r->view->backColor(), false);
r->renderQuad(prog, r->quad, mat_camera);
r->view->scene()->setLightsChanged();
}
fbo_mat_thumb.queryImage(5);
fbo_mat_thumb.release();
}
void RendererMaterial::procQueue() {
if (last_thumb_material) {
mat_thumbnails[last_thumb_material] = fbo_mat_thumb.getImage();
emit r->view->materialThumbnailCreated(last_thumb_material);
last_thumb_material = 0;
}
if (!mat_thumb_queue.isEmpty())
renderMaterial(mat_thumb_queue.dequeue());
}
QImage RendererMaterial::materialThumbnail(Material * m) {
return mat_thumbnails.value(m);
}
void RendererMaterial::recreateMaterialThumbnails(bool force_all) {
if (force_all) {
mat_thumb_queue.clear();
//qDebug() << "recreateMaterialThumbnails" << view->scene_->materials;
foreach (Material * m, r->view->scene_->materials)
mat_thumb_queue.enqueue(m);
} else {
foreach (Material * m, r->view->scene_->changed_materials)
if (!mat_thumb_queue.contains(m))
mat_thumb_queue.enqueue(m);
}
}

View File

@@ -0,0 +1,54 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RENDERER_MATERIAL_H
#define RENDERER_MATERIAL_H
#include "glframebuffer.h"
#include <QQueue>
class RendererMaterial {
friend class QGLView;
public:
RendererMaterial(Renderer * r_);
virtual ~RendererMaterial();
void init(int width, int height);
void resize(int width, int height);
QImage materialThumbnail(Material * m);
void recreateMaterialThumbnails(bool force_all = false);
void renderMaterial(Material * m);
void procQueue();
private:
Renderer * r;
Framebuffer fbo_mat_thumb;
Mesh * mat_sphere;
Camera * mat_camera;
Light * mat_light;
QMap<Material*, QImage> mat_thumbnails;
Material * last_thumb_material;
QQueue<Material*> mat_thumb_queue;
};
#endif // RENDERER_MATERIAL_H

View File

@@ -0,0 +1,136 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "renderer_service.h"
#include "renderer.h"
#include "qglview.h"
#include "glmesh.h"
#include <qad_types.h>
using namespace QGLEngineShaders;
RendererService::RendererService(Renderer * r_): r(r_) {
line_width = 1;
axis_camera = new Camera();
axis_camera->setAim(QVector3D());
axis_camera->setFOV(45.);
axis_mesh = Primitive::arrow(12);
axis_objects.resize(3);
const QVector3D _rot[3] = {QVector3D(0,1,0), QVector3D(-1,0,0), QVector3D(0,0,1)};
for (int i = 0; i < 3; ++i) {
axis_objects[i].color = QVector4D(0,0,0,1);
axis_objects[i].color[i] = 1.;
QMatrix4x4 m; m.rotate(90., _rot[i]);
m.transposed().copyDataTo(axis_objects[i].modelmatrix);
}
box_vp_scale = 1.;
box_mesh = Primitive::cube();
}
RendererService::~RendererService() {
delete box_mesh;
delete axis_camera;
delete axis_mesh;
}
void RendererService::init(int width, int height) {
axis_mesh->loadObjects(r->view, axis_objects);
resize(width, height);
}
void RendererService::resize(int width, int height) {
axis_viewport = preferredIconSize(10.);
line_width = lineThickness();
box_vp_scale = 30. * appScale() / qMax(qMin(width, height), 1);
//qDebug() << axis_viewport;
}
void RendererService::fillBoxObjects() {
box_objects.clear();
Object o;
QList<Light*> ll = r->view->scene()->lights_used;
QMatrix4x4 v_mat = r->view->camera()->viewMatrix() * r->view->camera()->offsetMatrix();
QMatrix4x4 lmat;
double vps = tan(r->view->camera()->FOV() / 2. * deg2rad) * box_vp_scale;
foreach (Light * l, ll) {
QVector4D lpos = QVector4D(l->worldPos(), 1.);
double dist = -(v_mat * lpos).z();
lmat.translate(lpos.toVector3D());
lmat.scale(dist * vps);
lmat.transposed().copyDataTo(o.modelmatrix);
box_objects << o;
}
}
void RendererService::setObjectsColor(QVector<Object> & ol, QColor col) {
QVector4D cv = QColor2QVector(col);
for (int i = 0; i < ol.size(); ++i)
ol[i].color = cv;
}
void RendererService::renderService() {
QOpenGLShaderProgram * prog = 0;
QOpenGLExtraFunctions * f = r->view;
if (r->bindShader(Renderer::srService, &prog)) {
f->glEnable(GL_MULTISAMPLE);
glEnableDepth();
f->glClear(GL_DEPTH_BUFFER_BIT);
glEnableDepth();
/// lights
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_CULL_FACE);
r->setUniformCamera(prog, r->view->camera());
fillBoxObjects();
setObjectsColor(box_objects, Qt::white);
glLineWidth(line_width*3);
box_mesh->loadObjects(f, box_objects);
box_mesh->draw(f, box_objects.size());
setObjectsColor(box_objects, Qt::black);
glLineWidth(line_width);
box_mesh->loadObjects(f, box_objects);
box_mesh->draw(f, box_objects.size());
glEnable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
/// axis
f->glViewport(0, 0, axis_viewport.width(), axis_viewport.height());
axis_camera->setPos(-r->view->camera()->direction() * 3.);
r->setUniformCamera(prog, axis_camera, true, axis_viewport);
//axis_mesh->loadObjects(f, axis_objects);
axis_mesh->draw(f, axis_objects.size());
f->glViewport(0, 0, r->view->width(), r->view->height());
f->glDisable(GL_MULTISAMPLE);
}
}

View File

@@ -0,0 +1,53 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RENDERER_SERVICE_H
#define RENDERER_SERVICE_H
#include "glframebuffer.h"
#include "glshaders_types.h"
#include <QQueue>
class RendererService {
friend class QGLView;
public:
RendererService(Renderer * r_);
virtual ~RendererService();
void init(int width, int height);
void resize(int width, int height);
void fillBoxObjects();
void setObjectsColor(QVector<QGLEngineShaders::Object> & ol, QColor col);
void renderService();
private:
Renderer * r;
Mesh * axis_mesh, * box_mesh;
QVector<QGLEngineShaders::Object> axis_objects, box_objects;
Camera * axis_camera;
QSize axis_viewport;
int line_width;
double box_vp_scale;
};
#endif // RENDERER_SERVICE_H

Some files were not shown because too many files have changed in this diff Show More