git-svn-id: svn://db.shs.com.ru/libs@586 a8b55f48-bf90-11e4-a774-851b48703e85
61
test/qglview/CMakeLists.txt
Normal file
@@ -0,0 +1,61 @@
|
||||
project(qglview)
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
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(QAD REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
include_directories(${QAD_INCLUDES})
|
||||
find_qt(${QtVersions} Core Gui OpenGL Xml)
|
||||
qt_sources(SRC)
|
||||
qt_wrap(${SRC} HDRS out_HDR CPPS out_CPP QMS out_QM)
|
||||
qt_add_library(${PROJECT_NAME} SHARED out_CPP)
|
||||
qt_target_link_libraries(${PROJECT_NAME} qad_utils qad_widgets ${OPENGL_LIBRARIES})
|
||||
message(STATUS "Building ${PROJECT_NAME}")
|
||||
if (LIBPROJECT)
|
||||
sdk_install("qad" "${PROJECT_NAME}" "${out_HDR}" "${out_QM}")
|
||||
else()
|
||||
if (LIB)
|
||||
if (WIN32)
|
||||
qt_install(FILES ${H} DESTINATION ${MINGW_INCLUDE}/qad)
|
||||
qt_install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_LIB})
|
||||
qt_install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_BIN})
|
||||
qt_install(TARGETS ${PROJECT_NAME} DESTINATION QtBin)
|
||||
else()
|
||||
qt_install(FILES ${H} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/qad)
|
||||
qt_install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
|
||||
endif()
|
||||
message(STATUS "Install ${PROJECT_NAME} to system \"${CMAKE_INSTALL_PREFIX}\"")
|
||||
else()
|
||||
qt_install(TARGETS ${PROJECT_NAME} DESTINATION bin)
|
||||
message(STATUS "Install ${PROJECT_NAME} to local \"bin\"")
|
||||
endif()
|
||||
endif()
|
||||
foreach(_v ${_QT_VERSIONS_})
|
||||
set(MULTILIB_qglview_SUFFIX_Qt${_v} ${_v})
|
||||
set(MULTILIB_qglview_SUFFIX_Qt${_v} ${_v} PARENT_SCOPE)
|
||||
endforeach()
|
||||
list(APPEND QT_MULTILIB_LIST qglview)
|
||||
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 ${PROJECT_NAME})
|
||||
260
test/qglview/glcamera.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
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;
|
||||
buildTransform();
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
104
test/qglview/glcamera.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
class Camera;
|
||||
|
||||
//extern QMatrix4x4 globCameraMatrix;
|
||||
//extern Camera * currentCamera;
|
||||
|
||||
class Camera: public GLObjectBase
|
||||
{
|
||||
friend class QGLView;
|
||||
friend class GLParticlesSystem;
|
||||
friend QDataStream & operator <<(QDataStream & s, const GLObjectBase * p);
|
||||
friend QDataStream & operator >>(QDataStream & s, GLObjectBase *& 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);
|
||||
|
||||
QMatrix4x4 offsetMatrix() const;
|
||||
|
||||
private:
|
||||
QVector3D aim_, 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
|
||||
145
test/qglview/glframebuffer.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
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 "glframebuffer.h"
|
||||
|
||||
|
||||
GLFramebuffer::GLFramebuffer(int colorAttachments_, bool withDepth, GLenum colorFormat_, GLenum target__) {
|
||||
is_depth = withDepth;
|
||||
color_format = colorFormat_;
|
||||
target_ = target__;
|
||||
colors.fill(0, colorAttachments_);
|
||||
fbo = drbo = 0;
|
||||
tex_d = 0;
|
||||
wid = hei = 0;
|
||||
is_changed = false;
|
||||
}
|
||||
|
||||
|
||||
GLFramebuffer::~GLFramebuffer() {
|
||||
deleteGLFramebuffer(fbo);
|
||||
deleteGLRenderbuffer(drbo);
|
||||
for (int i = 0; i < colors.size(); ++i)
|
||||
deleteGLTexture(colors[i]);
|
||||
deleteGLTexture(tex_d);
|
||||
}
|
||||
|
||||
|
||||
void GLFramebuffer::resize(int width, int height, bool force) {
|
||||
if ((wid == width) && (hei == height) && !force) return;
|
||||
initializeOpenGLFunctions();
|
||||
wid = width;
|
||||
hei = height;
|
||||
deleteGLFramebuffer(fbo);
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
for (int i = 0; i < colors.size(); ++i) {
|
||||
deleteGLTexture(colors[i]);
|
||||
createGLTexture(colors[i], width, height, color_format, target_);
|
||||
glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, 4);
|
||||
glTexParameteri(target_, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, target_, colors[i], 0);
|
||||
}
|
||||
if (is_depth) {
|
||||
deleteGLTexture(tex_d);
|
||||
deleteGLRenderbuffer(drbo);
|
||||
glGenRenderbuffers(1, &drbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, drbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, drbo);
|
||||
createGLTexture(tex_d, width, height, GL_DEPTH_COMPONENT);
|
||||
glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(target_, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target_, tex_d, 0);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
is_changed = false;
|
||||
}
|
||||
|
||||
|
||||
QImage GLFramebuffer::grab() const {
|
||||
//glReadPixels(0, 0, wid, hei, GL_RGBA, );
|
||||
//QImage ret();
|
||||
return QImage();
|
||||
}
|
||||
|
||||
|
||||
void GLFramebuffer::bind() {
|
||||
if (is_changed) resize(wid, hei);
|
||||
if (fbo == 0) return;
|
||||
initializeOpenGLFunctions();
|
||||
//glFlush();
|
||||
glGetIntegerv(GL_VIEWPORT, prev_view);
|
||||
//glClearError();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
//qDebug() << QString::number(glGetError(), 16);
|
||||
QVector<GLenum> buffers;
|
||||
for (int i = 0; i < colors.size(); ++i)
|
||||
buffers << GL_COLOR_ATTACHMENT0 + i;
|
||||
glDrawBuffers(buffers.size(), buffers.constData());
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
//glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glViewport(0, 0, wid, hei);
|
||||
}
|
||||
|
||||
|
||||
void GLFramebuffer::release() {
|
||||
is_changed = false;
|
||||
if (fbo == 0) return;
|
||||
//glFlush();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glViewport(prev_view[0], prev_view[1], prev_view[2], prev_view[3]);
|
||||
}
|
||||
|
||||
|
||||
void GLFramebuffer::setWriteBuffer(int index) {
|
||||
//QVector<GLenum> buffers; buffers << GL_COLOR_ATTACHMENT0 + index;
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0 + index);
|
||||
//glDrawBuffers(buffers.size(), buffers.constData());
|
||||
}
|
||||
|
||||
|
||||
void GLFramebuffer::setWriteBuffers(int * indeces, int count) {
|
||||
QVector<GLenum> buffers;
|
||||
for (int i = 0; i < count; ++i)
|
||||
buffers << GL_COLOR_ATTACHMENT0 + indeces[i];
|
||||
glDrawBuffers(buffers.size(), buffers.constData());
|
||||
}
|
||||
|
||||
|
||||
void GLFramebuffer::bindColorTextures() {
|
||||
for (int i = colors.size() - 1; i >= 0; --i) {
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, colors[i]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLFramebuffer::bindDepthTexture(int channel) {
|
||||
glActiveTexture(GL_TEXTURE0 + channel);
|
||||
glBindTexture(GL_TEXTURE_2D, tex_d);
|
||||
}
|
||||
66
test/qglview/glframebuffer.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
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 "gltypes.h"
|
||||
#include <QOpenGLExtraFunctions>
|
||||
|
||||
|
||||
class GLFramebuffer : protected QOpenGLExtraFunctions
|
||||
{
|
||||
public:
|
||||
GLFramebuffer(int colorAttachments = 1, bool withDepth = true, GLenum colorFormat = GL_RGBA8, GLenum target = GL_TEXTURE_2D);
|
||||
virtual ~GLFramebuffer();
|
||||
|
||||
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);}
|
||||
QImage grab() const;
|
||||
|
||||
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 setColorFormat(GLenum format) {color_format = format; is_changed = true;}
|
||||
|
||||
void copyDepthFrom(GLuint tex) {;}
|
||||
void bindColorTextures();
|
||||
void bindDepthTexture(int channel);
|
||||
|
||||
private:
|
||||
void deleteGLRenderbuffer(GLuint & drbo) {if (drbo != 0) glDeleteRenderbuffers(1, &drbo); drbo = 0;}
|
||||
void deleteGLFramebuffer(GLuint & fbo) {if (fbo != 0) glDeleteFramebuffers(1, &fbo); fbo = 0;}
|
||||
|
||||
bool is_depth, is_changed;
|
||||
QVector<GLuint> colors;
|
||||
GLenum color_format, target_;
|
||||
GLuint fbo, drbo, tex_d;
|
||||
GLint prev_view[4], wid, hei;
|
||||
|
||||
};
|
||||
|
||||
#endif // GLFRAMEBUFFER_H
|
||||
266
test/qglview/glmaterial.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
QStringList GLTextureManagerBase::search_pathes(".");
|
||||
|
||||
|
||||
bool GLCubeTexture::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 GLCubeTexture::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 GLCubeTexture::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 GLCubeTexture::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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString GLTextureManagerBase::findFile(const QString & path) {
|
||||
return ::findFile(path, search_pathes);
|
||||
}
|
||||
|
||||
|
||||
GLuint GLTextureManagerBase::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;
|
||||
///tid = currentQGLView->bindTexture(image, GL_TEXTURE_2D/*, GL_RGBA, __GLContext__::MipmapBindOption*/);
|
||||
//GLuint tid = 0;
|
||||
GLuint _tid = tid;
|
||||
createGLTexture(_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);
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
GLuint GLTextureManagerBase::loadTexture(const QImage & im, bool ownership, bool bump) {
|
||||
if (im.isNull()) return 0;
|
||||
QImage image(im);
|
||||
if (bump) convertToNormal(image);
|
||||
GLuint tid = 0;
|
||||
createGLTexture(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;
|
||||
if (ownership) tex_ids[bump ? 1 : 0].insert(QString(), tid);
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
void GLTextureManagerBase::reloadTexture(GLuint tid, const QString & path) {
|
||||
QString p = findFile(path);
|
||||
if (p.isEmpty() || (tid == 0)) return;
|
||||
QImage image(p);
|
||||
createGLTexture(tid, image);
|
||||
if (tid == 0) {
|
||||
qDebug() << "[TextureManager] Can`t load" << p;
|
||||
return;
|
||||
}
|
||||
qDebug() << "[TextureManager] Reloaded" << p << "as" << tid;
|
||||
}
|
||||
|
||||
|
||||
void GLTextureManagerBase::reloadTexture(GLuint tid, const QImage & im) {
|
||||
if (im.isNull() || (tid == 0)) return;
|
||||
QImage image(im);
|
||||
createGLTexture(tid, image);
|
||||
qDebug() << "[TextureManager] Reloaded" << tid;
|
||||
}
|
||||
|
||||
|
||||
Vector3d colorVector(QRgb c) {
|
||||
return Vector3d(((uchar*)(&c))[0] / 255., ((uchar*)(&c))[1] / 255., ((uchar*)(&c))[2] / 255.);
|
||||
}
|
||||
|
||||
|
||||
void GLTextureManagerBase::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 bump";
|
||||
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;
|
||||
Vector3d 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.y = piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f);
|
||||
res.x = 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.y = piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f);
|
||||
res.x = piClamp(0.5f + (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f);
|
||||
res.z = 1.;
|
||||
dd[a] = res.z * 255; ++a;
|
||||
dd[a] = res.x * 255; ++a;
|
||||
dd[a] = res.y * 255; ++a;
|
||||
dd[a] = 255; ++a;
|
||||
}
|
||||
}
|
||||
im = dim;
|
||||
//im.save("_bump.png");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Material::Material(): map_reflection(512) {
|
||||
color_diffuse = color_specular = Qt::white;
|
||||
color_self_illumination = Qt::black;
|
||||
glass = false;
|
||||
transparency = reflectivity = 0.f;
|
||||
map_specularity.color_amount = 0.5f;
|
||||
map_specular.color_amount = 1.f;
|
||||
iof = 1.f;
|
||||
dispersion = 0.05f;
|
||||
}
|
||||
|
||||
|
||||
void Material::apply(QOpenGLShaderProgram * prog) {
|
||||
if (prog) {
|
||||
setUniformMaterial(prog, *this);
|
||||
} else {
|
||||
GLfloat mat_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
GLfloat mat_specular[4] = {0.9f, 0.9f, 0.9f, 1.0f};
|
||||
GLfloat mat_emission[4] = {0.f, 0.f, 0.f, 1.0f};
|
||||
mat_diffuse[0] = map_diffuse.color_amount * color_diffuse.redF();
|
||||
mat_diffuse[1] = map_diffuse.color_amount * color_diffuse.greenF();
|
||||
mat_diffuse[2] = map_diffuse.color_amount * color_diffuse.blueF();
|
||||
mat_diffuse[3] = map_diffuse.color_amount * color_diffuse.alphaF() * (1.f - transparency);
|
||||
mat_specular[0] = map_specular.color_amount * color_specular.redF();
|
||||
mat_specular[1] = map_specular.color_amount * color_specular.greenF();
|
||||
mat_specular[2] = map_specular.color_amount * color_specular.blueF();
|
||||
mat_emission[0] = map_self_illumination.color_amount * color_self_illumination.redF();
|
||||
mat_emission[1] = map_self_illumination.color_amount * color_self_illumination.greenF();
|
||||
mat_emission[2] = map_self_illumination.color_amount * color_self_illumination.blueF();
|
||||
glColor4f(mat_diffuse[0], mat_diffuse[1], mat_diffuse[2], mat_diffuse[3]);
|
||||
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
|
||||
//qDebug() << (map_specularity.color_amount)*128.;
|
||||
glMaterialf(GL_FRONT, GL_SHININESS, (map_specularity.color_amount)*128.f);
|
||||
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_diffuse);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Material::loadTextures(GLTextureManagerBase * tm) {
|
||||
//qDebug() << "load textures";
|
||||
if (!tm) return;
|
||||
if (!map_diffuse.bitmap_path.isEmpty()) map_diffuse.bitmap_id = tm->loadTexture(map_diffuse.bitmap_path);
|
||||
if (!map_normal.bitmap_path.isEmpty()) map_normal.bitmap_id = tm->loadTexture(map_normal.bitmap_path, true, true);
|
||||
if (!map_relief.bitmap_path.isEmpty()) map_relief.bitmap_id = tm->loadTexture(map_relief.bitmap_path);
|
||||
if (!map_specularity.bitmap_path.isEmpty()) map_specularity.bitmap_id = tm->loadTexture(map_specularity.bitmap_path);
|
||||
if (!map_specular.bitmap_path.isEmpty()) map_specular.bitmap_id = tm->loadTexture(map_specular.bitmap_path);
|
||||
if (!map_self_illumination.bitmap_path.isEmpty()) map_self_illumination.bitmap_id = tm->loadTexture(map_self_illumination.bitmap_path);
|
||||
//if (!map_diffuse_2.bitmap_path.isEmpty()) map_diffuse_2.bitmap_id = tm->loadTexture(map_diffuse_2.bitmap_path);
|
||||
map_reflection.load();
|
||||
}
|
||||
188
test/qglview/glmaterial.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
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 "gltypes.h"
|
||||
#include "chunkstream.h"
|
||||
|
||||
class GLTexture {
|
||||
public:
|
||||
GLTexture(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 GLCubeTexture {
|
||||
public:
|
||||
GLCubeTexture(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 GLTextureManager;
|
||||
|
||||
class GLTextureManagerBase {
|
||||
public:
|
||||
GLTextureManagerBase() {}
|
||||
virtual ~GLTextureManagerBase() {}
|
||||
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);
|
||||
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];}
|
||||
virtual void addTexture(const QString & path) = 0;
|
||||
virtual void addAnimation(const QString & dir, const QString & name) = 0;
|
||||
virtual bool loadTextures() = 0;
|
||||
|
||||
protected:
|
||||
static void convertToNormal(QImage & im);
|
||||
static QStringList search_pathes;
|
||||
QMap<QString, GLuint> tex_ids[2];
|
||||
|
||||
};
|
||||
|
||||
struct Map {
|
||||
Map() {bitmap_id = 0; color_amount = 1.f; color_offset = 0.f; animation_frame_rate = -1.f;}
|
||||
QString bitmap_path;
|
||||
GLuint bitmap_id;
|
||||
QPointF bitmap_offset;
|
||||
float color_amount;
|
||||
float color_offset;
|
||||
QString animation;
|
||||
float animation_frame_rate;
|
||||
};
|
||||
|
||||
struct Material {
|
||||
Material();
|
||||
void apply(QOpenGLShaderProgram * prog);
|
||||
void loadTextures(GLTextureManagerBase * tm);
|
||||
QString name;
|
||||
QColor color_diffuse;
|
||||
QColor color_specular;
|
||||
QColor color_self_illumination;
|
||||
bool glass;
|
||||
float transparency;
|
||||
float reflectivity;
|
||||
float iof;
|
||||
float dispersion;
|
||||
Map map_diffuse;
|
||||
Map map_normal;
|
||||
Map map_relief;
|
||||
Map map_self_illumination;
|
||||
Map map_specularity;
|
||||
Map map_specular;
|
||||
/*Map map_diffuse_2;
|
||||
Map map_diffuse_3;
|
||||
Map map_diffuse_4;*/
|
||||
GLCubeTexture map_reflection;
|
||||
};
|
||||
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const Map & m) {
|
||||
ChunkStream cs;
|
||||
cs << cs.chunk(1, m.bitmap_path) << cs.chunk(2, m.color_amount) << cs.chunk(3, m.color_offset) << cs.chunk(4, m.animation) << cs.chunk(5, m.animation_frame_rate);
|
||||
s << cs.data(); return s;
|
||||
}
|
||||
inline QDataStream & operator >>(QDataStream & s, Map & m) {
|
||||
ChunkStream cs(s);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: m.bitmap_path = cs.getData<QString>(); break;
|
||||
case 2: m.color_amount = cs.getData<float>(); break;
|
||||
case 3: m.color_offset = cs.getData<float>(); break;
|
||||
case 4: m.animation = cs.getData<QString>(); break;
|
||||
case 5: m.animation_frame_rate = cs.getData<float>(); break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const Material & m) {
|
||||
ChunkStream cs;
|
||||
cs << cs.chunk(1, m.name) << cs.chunk(2, m.color_diffuse) << cs.chunk(3, m.color_specular) << cs.chunk(4, m.color_self_illumination)
|
||||
<< cs.chunk(5, m.transparency) << cs.chunk(6, m.reflectivity) << cs.chunk(7, m.glass) << cs.chunk(8, m.map_diffuse) << cs.chunk(9, m.map_normal)
|
||||
<< cs.chunk(10, m.map_relief) << cs.chunk(11, m.map_specular) << cs.chunk(12, m.map_specularity) << cs.chunk(13, m.map_self_illumination);
|
||||
s << qCompress(cs.data()); return s;
|
||||
}
|
||||
inline QDataStream & operator >>(QDataStream & s, Material & m) {
|
||||
QByteArray ba;
|
||||
s >> ba;
|
||||
ba = qUncompress(ba);
|
||||
ChunkStream cs(ba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: m.name = cs.getData<QString>(); break;
|
||||
case 2: m.color_diffuse = cs.getData<QColor>(); break;
|
||||
case 3: m.color_specular = cs.getData<QColor>(); break;
|
||||
case 4: m.color_self_illumination = cs.getData<QColor>(); break;
|
||||
case 5: m.transparency = cs.getData<float>(); break;
|
||||
case 6: m.reflectivity = cs.getData<float>(); break;
|
||||
case 7: m.glass = cs.getData<bool>(); break;
|
||||
case 8: m.map_diffuse = cs.getData<Map>(); break;
|
||||
case 9: m.map_normal = cs.getData<Map>(); break;
|
||||
case 10: m.map_relief = cs.getData<Map>(); break;
|
||||
case 11: m.map_specular = cs.getData<Map>(); break;
|
||||
case 12: m.map_specularity = cs.getData<Map>(); break;
|
||||
case 13: m.map_self_illumination = cs.getData<Map>(); break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // GLMATERIAL_H
|
||||
593
test/qglview/globject.cpp
Normal file
@@ -0,0 +1,593 @@
|
||||
/*
|
||||
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 "qglview.h"
|
||||
|
||||
|
||||
GLObjectBase::GLObjectBase() {
|
||||
type_ = glMesh;
|
||||
render_mode = View;
|
||||
pass_ = Solid;
|
||||
geom_prim = Triangles;
|
||||
scale_ = QVector3D(1., 1., 1.);
|
||||
parent_ = nullptr;
|
||||
is_root = is_init = is_tex_loaded = selected_ = false;
|
||||
visible_ = accept_fog = accept_light = cast_shadow = rec_shadow = select_ = true;
|
||||
line_width = -1.;
|
||||
blend_src = GL_SRC_ALPHA;
|
||||
blend_dest = GL_ONE_MINUS_SRC_ALPHA;
|
||||
type_ = glMesh;
|
||||
raw_matrix = false;
|
||||
mat_.setToIdentity();
|
||||
view_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase::~GLObjectBase() {
|
||||
//qDebug() << "del" << name() << view_;
|
||||
if (parent_) parent_->children_.removeAll(this);
|
||||
if (view_) ((QGLView*)view_)->objectDeleted(this);
|
||||
foreach (GLObjectBase * c, children_) {
|
||||
c->parent_ = nullptr;
|
||||
delete c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * GLObjectBase::clone(bool withChildren) {
|
||||
GLObjectBase * o = new GLObjectBase();
|
||||
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->material_ = material_;
|
||||
o->pos_h = pos_h;
|
||||
o->points = points;
|
||||
o->puvws = puvws;
|
||||
o->faces = faces;
|
||||
o->uvws = uvws;
|
||||
o->norms = norms;
|
||||
o->normals = normals;
|
||||
o->vbo.vertices_ = vbo.vertices_;
|
||||
o->vbo.normals_ = vbo.normals_;
|
||||
o->vbo.texcoords_ = vbo.texcoords_;
|
||||
o->vbo.colors_ = vbo.colors_;
|
||||
o->view_ = nullptr;
|
||||
o->children_.clear();
|
||||
if (withChildren) {
|
||||
for (int i = 0; i < children_.size(); ++i)
|
||||
o->addChild(children_[i]->clone(withChildren));
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::init() {
|
||||
calculateBoundingBox();
|
||||
vbo.init();
|
||||
vbo.rebuffer();
|
||||
//material_.reflection.create();
|
||||
//qDebug() << "init" << vbo.buffer_;
|
||||
is_init = true;
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::draw(QOpenGLShaderProgram * prog, bool simplest) {
|
||||
vbo.draw(geom_prim, prog, simplest);
|
||||
/*if (!d_vertices.isEmpty()) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glVertexPointer(3, GL_FLOAT, 0, d_vertices.constData());
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, d_uvs.constData());
|
||||
//glColorPointer(4, GL_FLOAT, 0, d_colors.constData());
|
||||
glNormalPointer(GL_FLOAT, 0, d_normals.constData());
|
||||
glDrawArrays(geom_prim, 0, d_vertices.size() / 3);*/
|
||||
/*if (pass_ == Reflection) {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
||||
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
||||
}*/
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::setView(QGLView * v) {
|
||||
view_ = v;
|
||||
foreach (GLObjectBase * c, children_)
|
||||
c->setView(v);
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::addChild(GLObjectBase * o) {
|
||||
if (o == this) return;
|
||||
if (o->parent_)
|
||||
o->parent_->children_.removeAll(o);
|
||||
children_ << o;
|
||||
o->parent_ = this;
|
||||
o->setView((QGLView*)view_);
|
||||
o->buildTransform();
|
||||
if (view_) {
|
||||
view_->collectLights();
|
||||
QList<GLObjectBase*> cl = o->children(true);
|
||||
cl << o;
|
||||
foreach (GLObjectBase * i, cl) {
|
||||
emit ((QGLView*)view_)->objectAdded(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::removeChild(GLObjectBase * o) {
|
||||
if (o == this) return;
|
||||
children_.removeAll(o);
|
||||
o->parent_ = nullptr;
|
||||
o->buildTransform();
|
||||
if (view_ != nullptr) view_->collectLights();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::removeChild(int index) {
|
||||
children_[index]->parent_ = nullptr;
|
||||
children_[index]->buildTransform();
|
||||
children_.removeAt(index);
|
||||
if (view_ != nullptr) view_->collectLights();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::clearChildren(bool deleteAll) {
|
||||
foreach (GLObjectBase * i, children_) {
|
||||
i->view_ = nullptr;
|
||||
i->parent_ = nullptr;
|
||||
i->clearChildren(deleteAll);
|
||||
if (deleteAll) {
|
||||
delete i;
|
||||
} else {
|
||||
i->buildTransform();
|
||||
}
|
||||
}
|
||||
children_.clear();
|
||||
if (view_) view_->collectLights();
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * GLObjectBase::child(int index) {
|
||||
if (index < 0 || index >= children_.size()) return nullptr;
|
||||
return children_[index];
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * GLObjectBase::child(const QString & name) {
|
||||
foreach (GLObjectBase * i, children_)
|
||||
if (i->name_ == name) return i;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
const GLObjectBase * GLObjectBase::child(int index) const {
|
||||
if (index < 0 || index >= children_.size()) return nullptr;
|
||||
return children_[index];
|
||||
}
|
||||
|
||||
|
||||
const GLObjectBase * GLObjectBase::child(const QString & name) const {
|
||||
foreach (GLObjectBase * i, children_)
|
||||
if (i->name_ == name) return i;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
QList<GLObjectBase * > GLObjectBase::children(bool all_) {
|
||||
if (!all_) return children_;
|
||||
QList<GLObjectBase * > cl;
|
||||
addChildren(cl, this);
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::rotateX(GLfloat a) {
|
||||
raw_matrix = false;
|
||||
angles_.setX(angles_.x() + a);
|
||||
buildTransform();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::rotateY(GLfloat a) {
|
||||
raw_matrix = false;
|
||||
angles_.setY(angles_.y() + a);
|
||||
buildTransform();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::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 GLObjectBase::setRotationX(GLfloat a) {
|
||||
raw_matrix = false;
|
||||
angles_.setX(a);
|
||||
buildTransform();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::setRotationY(GLfloat a) {
|
||||
raw_matrix = false;
|
||||
angles_.setY(a);
|
||||
buildTransform();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::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 GLObjectBase::setRotation(const QVector3D & a) {
|
||||
raw_matrix = false;
|
||||
angles_= a;
|
||||
buildTransform();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::resetRotation() {
|
||||
raw_matrix = false;
|
||||
angles_ = QVector3D(0., 0., 0.);
|
||||
buildTransform();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::addChildren(QList<GLObjectBase * > & list, GLObjectBase * where) {
|
||||
foreach (GLObjectBase * i, where->children_) {
|
||||
list << i;
|
||||
addChildren(list, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::loadTextures(bool with_children) {
|
||||
material_.loadTextures(view_->textureManager());
|
||||
if (with_children)
|
||||
foreach (GLObjectBase * i, children_) i->loadTextures();
|
||||
is_tex_loaded = true;
|
||||
checkPass();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::calculateBoundingBox() {
|
||||
bound = vbo.boundingBox();
|
||||
QVector<QVector3D> c = bound.corners(), tc;
|
||||
//QMatrix4x4 mat = itransform_.inverted();
|
||||
//qDebug() << itransform_ << mat_ << mat;
|
||||
foreach (QVector3D p, c)
|
||||
tc << (itransform_ * QVector4D(p, 1)).toVector3D();
|
||||
bound = Box3D(tc);
|
||||
foreach (GLObjectBase * i, children_) {
|
||||
i->calculateBoundingBox();
|
||||
bound |= i->boundingBox();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::setProperty(const QString & pn, const QVariant & v) {
|
||||
meta[pn] = v;
|
||||
}
|
||||
|
||||
|
||||
QVariant GLObjectBase::property(const QString & pn, bool * exists) const {
|
||||
if (exists) *exists = meta.contains(pn);
|
||||
return meta.value(pn);
|
||||
}
|
||||
|
||||
|
||||
bool GLObjectBase::hasProperty(const QString & pn) const {
|
||||
return meta.contains(pn);
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::removeProperty(const QString & pn) {
|
||||
meta.remove(pn);
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::setTransform(const QMatrix4x4 & t) {
|
||||
raw_matrix = true;
|
||||
mat_ = t;
|
||||
pos_ = mat_.column(3).toVector3D();
|
||||
mat_.setColumn(3, QVector4D(0., 0., 0., 1.));
|
||||
buildTransform();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::select() {
|
||||
//qDebug() << "select" << name() << view_;
|
||||
selected_ = true;
|
||||
if (view_)
|
||||
((QGLView*)view_)->selectObject(this);
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::setMaterial(const Material & m, bool with_children) {
|
||||
material_ = m;
|
||||
if (with_children)
|
||||
foreach (GLObjectBase * i, children_) i->setMaterial(m, true);
|
||||
checkPass();
|
||||
is_tex_loaded = false;
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::buildTransform() {
|
||||
itransform_.setToIdentity();
|
||||
GLObjectBase * 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 (GLObjectBase * i, children_)
|
||||
i->buildTransform();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::initInternal() {
|
||||
init();
|
||||
loadTextures();
|
||||
foreach (GLObjectBase * i, children_) i->initInternal();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::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 GLObjectBase::checkPass() {
|
||||
if (float(material_.color_diffuse.alphaF()) * (1.f - material_.transparency) < 1.f) pass_ = Transparent;
|
||||
else pass_ = Solid;
|
||||
}
|
||||
|
||||
|
||||
QMatrix4x4 GLObjectBase::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;
|
||||
}
|
||||
|
||||
|
||||
void GLObjectBase::render(int * id, QMap<int, GLObjectBase * > * ids, int sh_id_loc) {
|
||||
if (!visible_) return;
|
||||
//glPushMatrix();
|
||||
///qglMultMatrix TODO
|
||||
material_.apply(nullptr);
|
||||
if (id != nullptr) {
|
||||
++(*id);
|
||||
ids->insert(*id, this);
|
||||
//glVertexAttrib1f(sh_id_loc, (*id) / 255.f);
|
||||
//qDebug() << "assign to" << sh_id_loc << (*id) / 255.f;
|
||||
}
|
||||
draw(nullptr);
|
||||
foreach (GLObjectBase * i, children_)
|
||||
i->render(id, ids, sh_id_loc);
|
||||
//glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Light::Light(): GLObjectBase(), 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): GLObjectBase(), 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.);
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * Light::clone(bool withChildren) {
|
||||
Light * o = new Light(*this);
|
||||
//GLObjectBase::clone(withChildren);
|
||||
o->is_init = false;
|
||||
o->name_ = name_ + "_copy";
|
||||
o->view_ = 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;
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
void Light::draw(QOpenGLShaderProgram * prog, bool simplest) {
|
||||
bool l = glIsEnabled(GL_LIGHTING);
|
||||
glDisable(GL_LIGHTING);
|
||||
glPointSize(8.);
|
||||
glColor3f(0., 0., 0.);
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3f(0., 0., 0.);
|
||||
glEnd();
|
||||
float s = 10;
|
||||
if (light_type != Omni) {
|
||||
glBegin(GL_LINES);
|
||||
QVector4D dir = QVector4D(direction);
|
||||
if (raw_matrix)
|
||||
dir = transform().inverted() * dir;
|
||||
glVertex3f(0., 0., 0.);
|
||||
glVertex3f(dir.x() * s, dir.y() * s, dir.z() * s);
|
||||
glEnd();
|
||||
}
|
||||
if (l) glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
|
||||
QDataStream & operator <<(QDataStream & s, const GLObjectBase * p) {
|
||||
ChunkStream cs;
|
||||
//qDebug() << "place" << p->name() << "...";
|
||||
cs << cs.chunk(1, int(p->type_)) << cs.chunk(2, p->accept_light) << cs.chunk(3, p->accept_fog) << cs.chunk(4, p->visible_)
|
||||
<< cs.chunk(5, p->cast_shadow) << cs.chunk(6, p->rec_shadow) << cs.chunk(7, p->raw_matrix) << cs.chunk(8, p->line_width)
|
||||
<< cs.chunk(9, int(p->render_mode)) << cs.chunk(10, p->material_) << cs.chunk(11, p->pos_) << cs.chunk(12, p->angles_)
|
||||
<< cs.chunk(13, p->scale_) << cs.chunk(14, p->mat_) << cs.chunk(15, p->vbo) << cs.chunk(16, p->children_.size())
|
||||
<< cs.chunk(17, p->name_) << cs.chunk(18, p->meta);
|
||||
//qDebug() << "place self done";
|
||||
if (p->type_ == GLObjectBase::glLight) {
|
||||
//qDebug() << "place light ...";
|
||||
const Light * l = (const Light*)p;
|
||||
cs << cs.chunk(100, l->direction) << cs.chunk(101, l->angle_start) << cs.chunk(102, l->angle_end) << cs.chunk(103, l->intensity)
|
||||
<< cs.chunk(104, l->decay_const) << cs.chunk(105, l->decay_linear) << cs.chunk(106, l->decay_quadratic)
|
||||
<< cs.chunk(107, l->decay_start) << cs.chunk(108, l->decay_end) << cs.chunk(109, int(l->light_type));
|
||||
}
|
||||
if (p->type_ == GLObjectBase::glCamera) {
|
||||
//qDebug() << "place camera ...";
|
||||
const Camera * c = (const Camera*)p;
|
||||
cs << cs.chunk(200, c->aim_) << cs.chunk(201, c->fov_) << cs.chunk(202, c->depth_start) << cs.chunk(203, c->depth_end)
|
||||
<< cs.chunk(204, c->angle_limit_lower_xy) << cs.chunk(205, c->angle_limit_upper_xy)
|
||||
<< cs.chunk(206, c->mirror_x) << cs.chunk(207, c->mirror_y);
|
||||
}
|
||||
//qDebug() << "place" << p->name() << cs.data().size() << s.device()->size();
|
||||
s << cs.data();
|
||||
foreach (const GLObjectBase * c, p->children_)
|
||||
s << c;
|
||||
return s;
|
||||
}
|
||||
QDataStream & operator >>(QDataStream & s, GLObjectBase *& p) {
|
||||
ChunkStream cs(s);
|
||||
p = nullptr;
|
||||
int ccnt = 0;
|
||||
Light * l = nullptr;
|
||||
Camera * c = nullptr;
|
||||
//qDebug() << "read obj ...";
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1:
|
||||
{
|
||||
GLObjectBase::Type type = (GLObjectBase::Type)cs.getData<int>();
|
||||
switch (type) {
|
||||
case GLObjectBase::glMesh: p = new GLObjectBase(); break;
|
||||
case GLObjectBase::glLight: p = new Light(); l = (Light*)p; break;
|
||||
case GLObjectBase::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 = (GLObjectBase::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>(); 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<GLVBO>(); 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 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;
|
||||
}
|
||||
}
|
||||
//qDebug() << p->name() << ccnt;
|
||||
for (int i = 0; i < ccnt; ++i) {
|
||||
GLObjectBase * c = nullptr;
|
||||
s >> c;
|
||||
if (!c) continue;
|
||||
c->parent_ = p;
|
||||
p->children_ << c;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
268
test/qglview/globject.h
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
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 "glvbo.h"
|
||||
#include "glframebuffer.h"
|
||||
#include "glmaterial.h"
|
||||
|
||||
class Camera;
|
||||
class QGLView;
|
||||
|
||||
class GLObjectBase
|
||||
{
|
||||
friend class QGLView;
|
||||
friend class GLRendererBase;
|
||||
friend QDataStream & operator <<(QDataStream & s, const GLObjectBase * p);
|
||||
friend QDataStream & operator >>(QDataStream & s, GLObjectBase *& p);
|
||||
friend GLObjectBase * loadFromQGLFile(const QString & filepath);
|
||||
public:
|
||||
enum Type {glMesh, glLight, glCamera, glParticlesSystem};
|
||||
enum Pass {Solid, Transparent, Reflection, User};
|
||||
enum GeomPrimitives {Triangles = GL_TRIANGLES, Quads = GL_QUADS};
|
||||
enum RenderMode {View = 0, Point = GL_POINT, Line = GL_LINE, Fill = GL_FILL};
|
||||
|
||||
explicit GLObjectBase();
|
||||
virtual ~GLObjectBase();
|
||||
|
||||
virtual GLObjectBase * clone(bool withChildren = true);
|
||||
|
||||
QString name() const {return name_;}
|
||||
void setName(const QString & name) {name_ = name;}
|
||||
//virtual GLuint hList() {return list;}
|
||||
virtual void init();
|
||||
virtual void draw(QOpenGLShaderProgram * prog, bool simplest = false);
|
||||
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;}
|
||||
|
||||
GLObjectBase * parent() {return parent_;}
|
||||
void setParent(GLObjectBase * o) {parent_ = o;}
|
||||
bool hasParent() const {return parent_ != nullptr;}
|
||||
bool hasChildren() const {return children_.size() != 0;}
|
||||
void setView(QGLView * v);
|
||||
|
||||
void addChild(GLObjectBase * o);
|
||||
void removeChild(GLObjectBase * o);
|
||||
void removeChild(int index);
|
||||
void clearChildren(bool deleteAll = false);
|
||||
int childCount() const {return children_.size();}
|
||||
GLObjectBase * child(int index);
|
||||
GLObjectBase * child(const QString & name);
|
||||
const GLObjectBase * child(int index) const;
|
||||
const GLObjectBase * child(const QString & name) const;
|
||||
QList<GLObjectBase * > children(bool all_ = false);
|
||||
|
||||
bool isVisible() const {return visible_;}
|
||||
bool isHidden() const {return !visible_;}
|
||||
void setVisible(bool v) {visible_ = v;}
|
||||
void setHidden(bool v) {visible_ = !v;}
|
||||
void show() {visible_ = true;}
|
||||
void hide() {visible_ = 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() const {return selected_;}
|
||||
void setSelected(bool yes) {selected_ = yes;}
|
||||
void select();
|
||||
void deselect() {selected_ = false;}
|
||||
|
||||
bool isSelectable() const {return select_;}
|
||||
void setSelectable(bool yes) {select_ = yes;}
|
||||
/*
|
||||
bool isWriteDepth() const {return write_depth_;}
|
||||
void setWriteDepth(bool yes) {write_depth_ = yes;}*/
|
||||
|
||||
QColor color() const {return material_.color_diffuse;}
|
||||
void setColor(const QColor & c) {material_.color_diffuse = c; checkPass();}
|
||||
|
||||
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(const Material & m, bool with_children = false);
|
||||
Material & material() {return material_;}
|
||||
|
||||
const Box3D & boundingBox(bool withChildren = true) const {return bound;}
|
||||
GLVBO & VBO() {return vbo;}
|
||||
|
||||
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<Vector3d> points, puvws;
|
||||
QVector<Vector3i> faces, uvws, norms;
|
||||
QVector<Vector3d> normals;
|
||||
|
||||
//QVector<GLfloat> d_vertices, d_normals, d_uvs;
|
||||
|
||||
protected:
|
||||
void addChildren(QList<GLObjectBase * > & list, GLObjectBase * where);
|
||||
void loadTextures(bool with_children = false);
|
||||
//void deleteTextures() {foreach (GLuint i, textures) currentQGLView->deleteTexture(i); textures.clear();}
|
||||
void buildTransform();
|
||||
void initInternal();
|
||||
void render(int * id = nullptr, QMap<int, GLObjectBase * > * ids = nullptr, int sh_id_loc = 0);
|
||||
void checkPass();
|
||||
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;
|
||||
Type type_;
|
||||
GeomPrimitives geom_prim;
|
||||
RenderMode render_mode;
|
||||
Material material_;
|
||||
Box3D bound;
|
||||
QVector3D pos_, angles_, scale_;
|
||||
QList<GLObjectBase * > children_;
|
||||
QList<GLuint> textures;
|
||||
QMatrix4x4 itransform_, mat_;
|
||||
//QColor color_;
|
||||
QString name_;
|
||||
GLenum blend_src, blend_dest;
|
||||
GLObjectBase * parent_;
|
||||
QGLViewBase * view_;
|
||||
GLVBO vbo;
|
||||
QVariantMap meta;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator <(const GLObjectBase & f, const GLObjectBase & s) {return f.pos_h.z() < s.pos_h.z();}
|
||||
|
||||
class Light: public GLObjectBase {
|
||||
friend class QGLView;
|
||||
friend class GLRendererBase;
|
||||
public:
|
||||
enum Type {Omni, Directional, Cone};
|
||||
|
||||
Light();
|
||||
Light(const QVector3D & p, const QColor & c = Qt::white, float i = 1.);
|
||||
virtual GLObjectBase * clone(bool withChildren = true);
|
||||
virtual void init() {shadow_map.resize(512, 512); is_init = true;}
|
||||
virtual void draw(QOpenGLShaderProgram * prog, bool simplest = false);
|
||||
|
||||
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;
|
||||
GLFramebuffer shadow_map;
|
||||
QMatrix4x4 shadow_matrix;
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline T globject_cast(GLObjectBase * object) {return reinterpret_cast<T>(object);}
|
||||
|
||||
template <class T>
|
||||
inline T globject_cast(const GLObjectBase * object) {return reinterpret_cast<T>(object);}
|
||||
|
||||
|
||||
QDataStream & operator <<(QDataStream & s, const GLObjectBase * p);
|
||||
QDataStream & operator >>(QDataStream & s, GLObjectBase *& p);
|
||||
|
||||
#endif // GLOBJECT_H
|
||||
151
test/qglview/globject_editor.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
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 "globject_editor.h"
|
||||
#include "ui_globject_editor.h"
|
||||
|
||||
|
||||
GLObjectEditor::GLObjectEditor(QWidget * parent): QWidget(parent) {
|
||||
ui = new Ui::GLObjectEditor();
|
||||
ui->setupUi(this);
|
||||
active = true;
|
||||
object = 0;
|
||||
rmodes << GLObjectBase::View << GLObjectBase::Point << GLObjectBase::Line << GLObjectBase::Fill;
|
||||
ui->groupLight->setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
void GLObjectEditor::changeEvent(QEvent * e) {
|
||||
return;
|
||||
QWidget::changeEvent(e);
|
||||
switch (e->type()) {
|
||||
case QEvent::LanguageChange:
|
||||
ui->retranslateUi(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLObjectEditor::setObject(GLObjectBase * o) {
|
||||
object = o;
|
||||
if (object == 0) {
|
||||
ui->groupLight->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
ui->buttonDiscardRawMatrix->setEnabled(o->isRawMatrix());
|
||||
active = false;
|
||||
ui->spinPosX->setValue(object->posX());
|
||||
ui->spinPosY->setValue(object->posY());
|
||||
ui->spinPosZ->setValue(object->posZ());
|
||||
ui->spinRotationX->setValue(object->rotationX());
|
||||
ui->spinRotationY->setValue(object->rotationY());
|
||||
ui->spinRotationZ->setValue(object->rotationZ());
|
||||
ui->spinScaleX->setValue(object->scaleX());
|
||||
ui->spinScaleY->setValue(object->scaleY());
|
||||
ui->spinScaleZ->setValue(object->scaleZ());
|
||||
ui->spinLineWidth->setValue(object->lineWidth());
|
||||
ui->checkVisible->setChecked(object->isVisible());
|
||||
ui->checkAcceptLight->setChecked(object->isAcceptLight());
|
||||
ui->checkAcceptFog->setChecked(object->isAcceptFog());
|
||||
ui->checkCastShadows->setChecked(object->isCastShadows());
|
||||
ui->checkReceiveShadows->setChecked(object->isReceiveShadows());
|
||||
ui->comboRenderMode->setCurrentIndex(rmodes.indexOf(object->renderMode()));
|
||||
ui->groupLight->setEnabled(object->type() == GLObjectBase::glLight);
|
||||
if (object->type() == GLObjectBase::glLight) {
|
||||
Light * l = globject_cast<Light * >(object);
|
||||
//bool is_dir = l->light_type == Light::Directional, is_cone = l->light_type == Light::Cone;
|
||||
ui->buttonLightColor->setColor(l->color());
|
||||
ui->comboLightType->setCurrentIndex(l->light_type);
|
||||
ui->spinLightIntensity->setValue(l->intensity);
|
||||
ui->spinLightDecayConst->setValue(l->decay_const);
|
||||
ui->spinLightDecayLinear->setValue(l->decay_linear);
|
||||
ui->spinLightDecayQuadratic->setValue(l->decay_quadratic);
|
||||
ui->spinLightAngleStart->setValue(l->angle_start);
|
||||
ui->spinLightAngleEnd->setValue(l->angle_end);
|
||||
ui->spinLightDirectionX->setValue(l->direction.x());
|
||||
ui->spinLightDirectionY->setValue(l->direction.y());
|
||||
ui->spinLightDirectionZ->setValue(l->direction.z());
|
||||
}
|
||||
active = true;
|
||||
}
|
||||
|
||||
|
||||
void GLObjectEditor::objectChanged() {
|
||||
if (!active || object == 0) return;
|
||||
if (!object->isRawMatrix()) {
|
||||
object->setPosX(ui->spinPosX->value());
|
||||
object->setPosY(ui->spinPosY->value());
|
||||
object->setPosZ(ui->spinPosZ->value());
|
||||
object->setRotationX(ui->spinRotationX->value());
|
||||
object->setRotationY(ui->spinRotationY->value());
|
||||
object->setRotationZ(ui->spinRotationZ->value());
|
||||
object->setScaleX(ui->spinScaleX->value());
|
||||
object->setScaleY(ui->spinScaleY->value());
|
||||
object->setScaleZ(ui->spinScaleZ->value());
|
||||
}
|
||||
object->setLineWidth(ui->spinLineWidth->value());
|
||||
object->setVisible(ui->checkVisible->isChecked());
|
||||
object->setAcceptLight(ui->checkAcceptLight->isChecked());
|
||||
object->setAcceptFog(ui->checkAcceptFog->isChecked());
|
||||
object->setCastShadows(ui->checkCastShadows->isChecked());
|
||||
object->setReceiveShadows(ui->checkReceiveShadows->isChecked());
|
||||
object->setRenderMode((GLObjectBase::RenderMode)rmodes[ui->comboRenderMode->currentIndex()]);
|
||||
if (object->type() == GLObjectBase::glLight) {
|
||||
Light * l = globject_cast<Light * >(object);
|
||||
//bool is_dir = l->light_type == Light::Directional, is_cone = l->light_type == Light::Cone;
|
||||
l->setColor(ui->buttonLightColor->color());
|
||||
l->light_type = (Light::Type)ui->comboLightType->currentIndex();
|
||||
l->intensity = ui->spinLightIntensity->value();
|
||||
l->decay_const = ui->spinLightDecayConst->value();
|
||||
l->decay_linear = ui->spinLightDecayLinear->value();
|
||||
l->decay_quadratic = ui->spinLightDecayQuadratic->value();
|
||||
l->angle_start = ui->spinLightAngleStart->value();
|
||||
l->angle_end = ui->spinLightAngleEnd->value();
|
||||
l->direction = QVector3D(ui->spinLightDirectionX->value(), ui->spinLightDirectionY->value(), ui->spinLightDirectionZ->value()).normalized();
|
||||
}
|
||||
emit changed();
|
||||
}
|
||||
|
||||
|
||||
void GLObjectEditor::on_spinLightAngleStart_valueChanged(double v) {
|
||||
if (ui->spinLightAngleEnd->value() < v)
|
||||
ui->spinLightAngleEnd->setValue(v);
|
||||
}
|
||||
|
||||
|
||||
void GLObjectEditor::on_spinLightAngleEnd_valueChanged(double v) {
|
||||
if (ui->spinLightAngleStart->value() > v)
|
||||
ui->spinLightAngleStart->setValue(v);
|
||||
}
|
||||
|
||||
|
||||
void GLObjectEditor::on_buttonDiscardRawMatrix_clicked() {
|
||||
if (!active || !object) return;
|
||||
object->setPosX(ui->spinPosX->value());
|
||||
object->setPosY(ui->spinPosY->value());
|
||||
object->setPosZ(ui->spinPosZ->value());
|
||||
object->setRotationX(ui->spinRotationX->value());
|
||||
object->setRotationY(ui->spinRotationY->value());
|
||||
object->setRotationZ(ui->spinRotationZ->value());
|
||||
object->setScaleX(ui->spinScaleX->value());
|
||||
object->setScaleY(ui->spinScaleY->value());
|
||||
object->setScaleZ(ui->spinScaleZ->value());
|
||||
ui->buttonDiscardRawMatrix->setEnabled(false);
|
||||
}
|
||||
55
test/qglview/globject_editor.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 GLOBJECT_EDITOR_H
|
||||
#define GLOBJECT_EDITOR_H
|
||||
|
||||
#include "globject.h"
|
||||
|
||||
namespace Ui {
|
||||
class GLObjectEditor;
|
||||
};
|
||||
|
||||
class GLObjectEditor: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GLObjectEditor(QWidget * parent = 0);
|
||||
|
||||
void setObject(GLObjectBase * o);
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent * e);
|
||||
|
||||
Ui::GLObjectEditor * ui;
|
||||
bool active;
|
||||
GLObjectBase * object;
|
||||
QList<GLenum> rmodes;
|
||||
|
||||
private slots:
|
||||
void objectChanged();
|
||||
void on_spinLightAngleStart_valueChanged(double v);
|
||||
void on_spinLightAngleEnd_valueChanged(double v);
|
||||
void on_buttonDiscardRawMatrix_clicked();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
};
|
||||
|
||||
#endif // GLOBJECT_EDITOR_H
|
||||
1087
test/qglview/globject_editor.ui
Normal file
@@ -0,0 +1,1087 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GLObjectEditor</class>
|
||||
<widget class="QWidget" name="GLObjectEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>329</width>
|
||||
<height>707</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Position X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinPosX">
|
||||
<property name="minimum">
|
||||
<double>-99999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Position Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinPosY">
|
||||
<property name="minimum">
|
||||
<double>-99999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Position Z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinPosZ">
|
||||
<property name="minimum">
|
||||
<double>-99999.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Rotation X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Rotation Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Rotation Z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="SpinSlider" name="spinRotationX">
|
||||
<property name="minimum">
|
||||
<double>-180.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>180.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="SpinSlider" name="spinRotationY">
|
||||
<property name="minimum">
|
||||
<double>-180.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>180.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="SpinSlider" name="spinRotationZ">
|
||||
<property name="minimum">
|
||||
<double>-180.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>180.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Scale X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Scale Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Scale Z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinScaleX">
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-99999.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="8" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinScaleY">
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-99999.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="9" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinScaleZ">
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-99999.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="10" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Render mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QComboBox" name="comboRenderMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>View</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Point</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Line</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fill</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="checkVisible">
|
||||
<property name="text">
|
||||
<string>Visible</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QCheckBox" name="checkAcceptLight">
|
||||
<property name="text">
|
||||
<string>Accept light</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QCheckBox" name="checkAcceptFog">
|
||||
<property name="text">
|
||||
<string>Accept fog</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Line width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinLineWidth">
|
||||
<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="14" column="1">
|
||||
<widget class="QCheckBox" name="checkCastShadows">
|
||||
<property name="text">
|
||||
<string>Cast shadows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="checkReceiveShadows">
|
||||
<property name="text">
|
||||
<string>Receive shadows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupLight">
|
||||
<property name="title">
|
||||
<string>Light</string>
|
||||
</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>
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="ColorButton" name="buttonLightColor"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboLightType">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Omni</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Directional</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Cone</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Intensity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="SpinSlider" name="spinLightIntensity">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>128.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</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="3" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Decay const</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SpinSlider" name="spinLightDecayConst">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>64.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</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="4" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Decay linear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="SpinSlider" name="spinLightDecayLinear">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>64.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</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="5" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Decay quadratic</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="SpinSlider" name="spinLightDecayQuadratic">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>64.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</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="6" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Angle Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="SpinSlider" name="spinLightAngleStart">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>180.000000000000000</double>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<double>30.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>Angle End</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="SpinSlider" name="spinLightAngleEnd">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>180.000000000000000</double>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<double>30.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Direcion X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="SpinSlider" name="spinLightDirectionX">
|
||||
<property name="minimum">
|
||||
<double>-1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</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>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Direcion Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>Direcion Z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="SpinSlider" name="spinLightDirectionY">
|
||||
<property name="minimum">
|
||||
<double>-1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</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>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="SpinSlider" name="spinLightDirectionZ">
|
||||
<property name="minimum">
|
||||
<double>-1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</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>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="buttonDiscardRawMatrix">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Discard raw transform</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>spinPosX</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>312</x>
|
||||
<y>9</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>5</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinPosY</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>307</x>
|
||||
<y>40</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>320</x>
|
||||
<y>36</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinPosZ</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>317</x>
|
||||
<y>73</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>61</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinRotationX</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>97</x>
|
||||
<y>78</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>82</x>
|
||||
<y>73</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinRotationY</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>317</x>
|
||||
<y>123</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>320</x>
|
||||
<y>96</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinRotationZ</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>292</x>
|
||||
<y>128</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>125</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinScaleX</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>295</x>
|
||||
<y>156</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>150</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinScaleY</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>273</x>
|
||||
<y>177</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>175</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinScaleZ</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>297</x>
|
||||
<y>202</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>200</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>checkVisible</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>185</x>
|
||||
<y>268</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>76</x>
|
||||
<y>242</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>checkAcceptLight</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>104</x>
|
||||
<y>277</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>61</x>
|
||||
<y>261</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>checkAcceptFog</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>210</x>
|
||||
<y>314</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>79</x>
|
||||
<y>288</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>checkCastShadows</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>208</x>
|
||||
<y>337</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>55</x>
|
||||
<y>310</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>checkReceiveShadows</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>212</x>
|
||||
<y>360</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>78</x>
|
||||
<y>334</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLineWidth</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>303</x>
|
||||
<y>366</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>359</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>comboRenderMode</sender>
|
||||
<signal>currentIndexChanged(int)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>299</x>
|
||||
<y>228</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>228</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonLightColor</sender>
|
||||
<signal>colorChanged(QColor)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>270</x>
|
||||
<y>423</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>320</x>
|
||||
<y>393</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>comboLightType</sender>
|
||||
<signal>currentIndexChanged(int)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>292</x>
|
||||
<y>447</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>320</x>
|
||||
<y>429</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightIntensity</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>255</x>
|
||||
<y>469</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>318</x>
|
||||
<y>463</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightDecayConst</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>303</x>
|
||||
<y>492</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>320</x>
|
||||
<y>489</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightDecayLinear</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>289</x>
|
||||
<y>511</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>318</x>
|
||||
<y>517</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightDecayQuadratic</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>299</x>
|
||||
<y>535</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>325</x>
|
||||
<y>543</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightAngleStart</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>295</x>
|
||||
<y>559</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>321</x>
|
||||
<y>569</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightAngleEnd</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>301</x>
|
||||
<y>585</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>320</x>
|
||||
<y>595</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightDirectionX</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>302</x>
|
||||
<y>612</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>332</x>
|
||||
<y>607</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightDirectionY</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>313</x>
|
||||
<y>636</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>330</x>
|
||||
<y>633</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinLightDirectionZ</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>GLObjectEditor</receiver>
|
||||
<slot>objectChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>313</x>
|
||||
<y>654</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>326</x>
|
||||
<y>659</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>objectChanged()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
215
test/qglview/glparticles_system.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
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 "glparticles_system.h"
|
||||
|
||||
|
||||
GLParticlesSystem::GLParticlesSystem(const QVector3D & pos): GLObjectBase() {
|
||||
pass_ = GLObjectBase::Transparent;
|
||||
freq = 40.f;
|
||||
birthRate_ = 10.f;
|
||||
lifeDuration_ = 2.f;
|
||||
fade_time = 0.5f;
|
||||
size_ = 1.f;
|
||||
additionalSpeed = 0.f;
|
||||
initialSpeed_ = 1.f;
|
||||
need_birth = -1.f;
|
||||
tex_rect.setRect(0., 0., 1., 1.);
|
||||
tex_scale = QSizeF();
|
||||
emitterPosition_ = pos;
|
||||
emitterDirection_.setZ(1.);
|
||||
speedDirection_.setZ(1.);
|
||||
speedDecay_ = initialAngle_ = enlargeSpeed_ = enlargeSpeedJitter_ = baseAngle_ = 0.f;
|
||||
lifeDurationJitter_ = speedJitter_ = speedDirectionJitter_ = sizeJitter_ = angleJitter_ = 0.f;
|
||||
active_ = birthEnabled_ = true;
|
||||
is_diffuse_anim = add_vert_face = false;
|
||||
emitterType_ = Cone;
|
||||
tick_life = 1.f / freq;
|
||||
tick_birth = birthRate_ / freq;
|
||||
}
|
||||
|
||||
|
||||
void GLParticlesSystem::update() {
|
||||
//qDebug() << "update" << need_birth << tick_birth;
|
||||
if (!active_) return;
|
||||
//QMutexLocker locker(&mutex);
|
||||
Particle cp(lifeDuration_);
|
||||
if (birthEnabled_) need_birth += tick_birth;
|
||||
qDebug() << "update" << particles.size();
|
||||
if (need_birth >= 1.f) {
|
||||
cp.pos = emitterPosition_;
|
||||
//qDebug() << "speed" << cp.speed;
|
||||
cp.speedDecay = 1.f + speedDecay_;
|
||||
for (int i = 0; i < floor(need_birth); ++i) {
|
||||
cp.lifeDuration = lifeDuration_ + urand(lifeDurationJitter_);
|
||||
switch (emitterType_) {
|
||||
case Omni:
|
||||
cp.speed = QVector3D(urand(), urand(), urand()).normalized() * initialSpeed_ * (1.f + urand(speedJitter_));
|
||||
break;
|
||||
case Cone: case Box:
|
||||
cp.speed = emitterDirection_ * initialSpeed_ * (1.f + urand(speedJitter_));
|
||||
cp.speed += orthToVector(cp.speed, speedDirectionJitter_);
|
||||
break;
|
||||
}
|
||||
if (emitterType_ == Box)
|
||||
cp.pos = emitterRect_.randomPoint();
|
||||
//qDebug() << "before" << cp.speed.length();
|
||||
lengthenVector(cp.speed, additionalSpeed);
|
||||
//qDebug() << "after" << cp.speed.length();
|
||||
cp.size = size_ + urand(sizeJitter_);
|
||||
cp.angle = initialAngle_ + urand(angleJitter_);
|
||||
cp.enlargeSpeed = (enlargeSpeed_ + urand(enlargeSpeedJitter_)) * tick_life;
|
||||
/*if (is_diffuse_anim) {
|
||||
if (material_.diffuse.animation_frame_rate < 0 && animation->bitmaps.size() > 0)
|
||||
cp.animationFrameRate = animation->bitmaps.size() / cp.lifeDuration;
|
||||
else
|
||||
cp.animationFrameRate = material_.diffuse.animation_frame_rate;
|
||||
}*/
|
||||
if (tex_scale.isEmpty()) cp.tex_rect.setSize(tex_rect.size());
|
||||
else cp.tex_rect.setSize(tex_rect.size() * tex_scale);
|
||||
cp.tex_rect.moveTopLeft(tex_rect.topLeft() + QPointF(uprand(tex_rect.width() - cp.tex_rect.width()), uprand(tex_rect.height() - cp.tex_rect.height())));
|
||||
//cp.tex_rect = tex_rect;
|
||||
particles.push_back(cp);
|
||||
}
|
||||
need_birth -= floor(need_birth);
|
||||
}
|
||||
for (int i = 0; i < particles.size(); ++i) {
|
||||
Particle & c(particles[i]);
|
||||
foreach (const QVector3D & f, forces)
|
||||
c.speed += f;
|
||||
c.lifeCurrent += tick_life;
|
||||
//qDebug() << "life" << c.lifeCurrent << c.lifeDuration;
|
||||
if (c.lifeCurrent > c.lifeDuration) {
|
||||
//qDebug() << "remove" << i;
|
||||
particles.remove(i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
c.pos += c.speed * tick_life;
|
||||
c.speed /= c.speedDecay;
|
||||
c.size += c.enlargeSpeed;
|
||||
//if (c.lifeCurrent > 1.) c.angle += urand(5.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLParticlesSystem::draw(QOpenGLShaderProgram * prog, bool) {
|
||||
if (particles.isEmpty()) return;
|
||||
if (view_ == nullptr) return;
|
||||
pass_ = GLObjectBase::Transparent;
|
||||
Camera * camera(view_->camera());
|
||||
QVector3D apos = camera->pos(), dir = camera->direction();
|
||||
//qDebug() << dir;
|
||||
//qDebug() << camera.angles();
|
||||
//qDebug() << camera.angle_xy;
|
||||
GLfloat cxyc, czs, czc;
|
||||
GLfloat dx, dy, cdx, cdy, cdz, a, tr_r = material_.color_diffuse.redF(),
|
||||
tr_g = material_.color_diffuse.greenF(),
|
||||
tr_b = material_.color_diffuse.blueF(),
|
||||
tr_a = material_.color_diffuse.alphaF() * (1.f - material_.transparency);
|
||||
//cxys = sin(camera.angle_xy * deg2rad);
|
||||
cxyc = cosf(camera->angles_.y() * deg2rad);
|
||||
czs = sinf(camera->angles_.z() * deg2rad);
|
||||
czc = cosf(camera->angles_.z() * deg2rad);
|
||||
|
||||
dx = -czc;
|
||||
dy = czs;
|
||||
vertices.clear();
|
||||
texcoords.clear();
|
||||
colors.clear();
|
||||
for (int i = 0; i < particles.size(); ++i)
|
||||
//particles[i].pos_h.setZ((particles[i].pos - apos).lengthSquared());
|
||||
particles[i].pos_h.setZ(particles[i].pos.distanceToPlane(apos, dir));
|
||||
qSort(particles.begin(), particles.end());
|
||||
glBegin(GL_POINTS);
|
||||
foreach (const Particle & i, particles) {
|
||||
//glVertex3f(i.pos.x(), i.pos.y(), i.pos.z());
|
||||
a = (i.lifeDuration - i.lifeCurrent) / fade_time;
|
||||
if (a > 1.f) a = 1.f;
|
||||
a *= tr_a;
|
||||
cdx = dx * i.size;
|
||||
cdy = dy * i.size;
|
||||
cdz = i.size;
|
||||
vertices << i.pos.x() - cdx << i.pos.y() - cdy << i.pos.z() - cdz;
|
||||
vertices << i.pos.x() - cdx << i.pos.y() - cdy << i.pos.z() + cdz;
|
||||
vertices << i.pos.x() + cdx << i.pos.y() + cdy << i.pos.z() + cdz;
|
||||
vertices << i.pos.x() + cdx << i.pos.y() + cdy << i.pos.z() - cdz;
|
||||
cdx = i.size;
|
||||
cdy = i.size;
|
||||
texcoords << i.tex_rect.right() << i.tex_rect.top();
|
||||
texcoords << i.tex_rect.right() << i.tex_rect.bottom();
|
||||
texcoords << i.tex_rect.left() << i.tex_rect.bottom();
|
||||
texcoords << i.tex_rect.left() << i.tex_rect.top();
|
||||
colors << tr_r << tr_g << tr_b << a;
|
||||
colors << tr_r << tr_g << tr_b << a;
|
||||
colors << tr_r << tr_g << tr_b << a;
|
||||
colors << tr_r << tr_g << tr_b << a;
|
||||
if (add_vert_face) {
|
||||
if (cxyc > 0.f) {
|
||||
vertices << i.pos.x() - cdx << i.pos.y() - cdy << i.pos.z();
|
||||
vertices << i.pos.x() + cdx << i.pos.y() - cdy << i.pos.z();
|
||||
vertices << i.pos.x() + cdx << i.pos.y() + cdy << i.pos.z();
|
||||
vertices << i.pos.x() - cdx << i.pos.y() + cdy << i.pos.z();
|
||||
} else {
|
||||
vertices << i.pos.x() - cdx << i.pos.y() - cdy << i.pos.z();
|
||||
vertices << i.pos.x() - cdx << i.pos.y() + cdy << i.pos.z();
|
||||
vertices << i.pos.x() + cdx << i.pos.y() + cdy << i.pos.z();
|
||||
vertices << i.pos.x() + cdx << i.pos.y() - cdy << i.pos.z();
|
||||
}
|
||||
texcoords << i.tex_rect.right() << i.tex_rect.top();
|
||||
texcoords << i.tex_rect.right() << i.tex_rect.bottom();
|
||||
texcoords << i.tex_rect.left() << i.tex_rect.bottom();
|
||||
texcoords << i.tex_rect.left() << i.tex_rect.top();
|
||||
colors << tr_r << tr_g << tr_b << a;
|
||||
colors << tr_r << tr_g << tr_b << a;
|
||||
colors << tr_r << tr_g << tr_b << a;
|
||||
colors << tr_r << tr_g << tr_b << a;
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
//bool cae = glIsEnabled(GL_COLOR_ARRAY), nae = glIsEnabled(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
//glNormal3f(vn.x(), vn.y(), vn.z());
|
||||
glNormal3f(0., 0., 1.);
|
||||
glDepthMask(false);
|
||||
glEnable(GL_COLOR_ARRAY);
|
||||
glDisable(GL_NORMAL_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, texcoords.constData());
|
||||
glColorPointer(4, GL_FLOAT, 0, colors.constData());
|
||||
//glEnable(GL_ALPHA_TEST);
|
||||
//glAlphaFunc();
|
||||
glDrawArrays(GL_QUADS, 0, vertices.size() / 3);
|
||||
glDepthMask(true);
|
||||
//glDisable(GL_ALPHA_TEST);
|
||||
//if (!cae) glDisable(GL_COLOR_ARRAY);
|
||||
//if (nae) glEnable(GL_NORMAL_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLParticlesSystem::Particle::Particle(float life_dur) {
|
||||
size = 1.;
|
||||
angle = lifeCurrent = 0.;
|
||||
speedDecay = 0.;
|
||||
lifeDuration = life_dur;
|
||||
tex_rect = QRectF(0, 0, 1, 1);
|
||||
}
|
||||
153
test/qglview/glparticles_system.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
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 GLPARTICLES_SYSTEM_H
|
||||
#define GLPARTICLES_SYSTEM_H
|
||||
|
||||
#include <QMutex>
|
||||
#include "gltexture_manager.h"
|
||||
#include "globject.h"
|
||||
#include "glcamera.h"
|
||||
|
||||
class GLParticlesSystem: public QObject, public GLObjectBase, protected QOpenGLFunctions
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float birthRate READ birthRate WRITE setBirthRate)
|
||||
Q_PROPERTY(float lifeDuration READ lifeDuration WRITE setLifeDuration)
|
||||
Q_PROPERTY(float size READ size WRITE setSize)
|
||||
Q_PROPERTY(float enlargeSpeed READ enlargeSpeed WRITE setEnlargeSpeed)
|
||||
Q_PROPERTY(float initialAngle READ initialAngle WRITE setInitialAngle)
|
||||
Q_PROPERTY(float initialSpeed READ initialSpeed WRITE setInitialSpeed)
|
||||
Q_PROPERTY(float speedDecay READ speedDecay WRITE setSpeedDecay)
|
||||
Q_PROPERTY(float baseAngle READ baseAngle WRITE setBaseAngle)
|
||||
Q_PROPERTY(QVector3D speedDirection READ speedDirection WRITE setSpeedDirection)
|
||||
Q_PROPERTY(QVector3D emitterPosition READ emitterPosition WRITE setEmitterPosition)
|
||||
Q_PROPERTY(QVector3D emitterDirection READ emitterDirection WRITE setEmitterDirection)
|
||||
Q_PROPERTY(float lifeDurationJitter READ lifeDurationJitter WRITE setLifeDurationJitter)
|
||||
Q_PROPERTY(float speedJitter READ speedJitter WRITE setSpeedJitter)
|
||||
Q_PROPERTY(float speedDirectionJitter READ speedDirectionJitter WRITE setSpeedDirectionJitter)
|
||||
Q_PROPERTY(float sizeJitter READ sizeJitter WRITE setSizeJitter)
|
||||
Q_PROPERTY(float enlargeSpeedJitter READ enlargeSpeedJitter WRITE setEnlargeSpeedJitter)
|
||||
Q_PROPERTY(float angleJitter READ angleJitter WRITE setAngleJitter)
|
||||
Q_PROPERTY(bool active READ isActive WRITE setActive)
|
||||
Q_PROPERTY(bool birthEnabled READ isBirthEnabled WRITE setBirthEnabled)
|
||||
Q_PROPERTY(float fadeTime READ fadeTime WRITE setFadeTime)
|
||||
public:
|
||||
GLParticlesSystem(const QVector3D & pos = QVector3D());
|
||||
~GLParticlesSystem() {;}
|
||||
|
||||
enum Type {Cone, Omni, Box};
|
||||
|
||||
struct Particle {
|
||||
Particle(float life_dur = 40.);
|
||||
QVector3D pos;
|
||||
QVector3D pos_h;
|
||||
QVector3D speed;
|
||||
QRectF tex_rect;
|
||||
float speedDecay;
|
||||
float size;
|
||||
float angle;
|
||||
float enlargeSpeed;
|
||||
float lifeDuration;
|
||||
float lifeCurrent;
|
||||
float animationFrameRate;
|
||||
};
|
||||
|
||||
void update();
|
||||
void draw(QOpenGLShaderProgram * prog, bool);
|
||||
|
||||
float birthRate() const {return birthRate_;}
|
||||
float lifeDuration() const {return lifeDuration_;}
|
||||
float size() const {return size_;}
|
||||
float enlargeSpeed() const {return enlargeSpeed_;}
|
||||
float initialAngle() const {return initialAngle_;}
|
||||
float initialSpeed() const {return initialSpeed_;}
|
||||
float speedDecay() const {return speedDecay_;}
|
||||
float baseAngle() const {return baseAngle_;}
|
||||
QVector3D speedDirection() const {return speedDirection_;}
|
||||
QVector3D emitterPosition() const {return emitterPosition_;}
|
||||
QVector3D emitterDirection() const {return emitterDirection_;}
|
||||
Box3D emitterRect() const {return emitterRect_;}
|
||||
float lifeDurationJitter() const {return lifeDurationJitter_;}
|
||||
float speedJitter() const {return speedJitter_;}
|
||||
float speedDirectionJitter() const {return speedDirectionJitter_;}
|
||||
float sizeJitter() const {return sizeJitter_;}
|
||||
float enlargeSpeedJitter() const {return enlargeSpeedJitter_;}
|
||||
float angleJitter() const {return angleJitter_;}
|
||||
bool isActive() const {return active_;}
|
||||
bool isBirthEnabled() const {return birthEnabled_;}
|
||||
GLParticlesSystem::Type emitterType() const {return emitterType_;}
|
||||
float fadeTime() const {return fade_time;}
|
||||
bool isAddVerticalFaceEnabled() const {return add_vert_face;}
|
||||
|
||||
void setBirthRate(const float & arg) {birthRate_ = arg; tick_birth = birthRate_ / freq;}
|
||||
void setLifeDuration(const float & arg) {lifeDuration_ = arg;}
|
||||
void setSize(const float & arg) {size_ = arg;}
|
||||
void setEnlargeSpeed(const float & arg) {enlargeSpeed_ = arg;}
|
||||
void setInitialAngle(const float & arg) {initialAngle_ = arg;}
|
||||
void setInitialSpeed(const float & arg) {initialSpeed_ = arg;}
|
||||
void setBaseAngle(const float & arg) {baseAngle_ = arg;}
|
||||
void setSpeedDecay(const float & arg) {speedDecay_ = arg;}
|
||||
void setSpeedDirection(const QVector3D & arg) {speedDirection_ = arg;}
|
||||
void setEmitterPosition(const QVector3D & arg) {emitterPosition_ = arg;}
|
||||
void setEmitterDirection(const QVector3D & arg) {emitterDirection_ = arg.normalized();}
|
||||
void setEmitterRect(const Box3D & arg) {emitterRect_ = arg;}
|
||||
void setLifeDurationJitter(const float & arg) {lifeDurationJitter_ = arg;}
|
||||
void setSpeedJitter(const float & arg) {speedJitter_ = arg;}
|
||||
void setSpeedDirectionJitter(const float & arg) {speedDirectionJitter_ = arg;}
|
||||
void setSizeJitter(const float & arg) {sizeJitter_ = arg;}
|
||||
void setEnlargeSpeedJitter(const float & arg) {enlargeSpeedJitter_ = arg;}
|
||||
void setActive(const bool & arg) {active_ = arg;}
|
||||
void setAngleJitter(const float & arg) {angleJitter_ = arg;}
|
||||
void setBirthEnabled(const bool & arg) {birthEnabled_ = arg;}
|
||||
void setEmitterType(const GLParticlesSystem::Type & arg) {emitterType_ = arg;}
|
||||
void setFadeTime(const float & arg) {fade_time = arg;}
|
||||
void setAddVerticalFaceEnabled(const bool & arg) {add_vert_face = arg;}
|
||||
void setTextureRect(const QRectF & arg) {tex_rect = arg;}
|
||||
void setTextureScale(const float & x, const float & y) {tex_scale = QSizeF(x, y);}
|
||||
void setTextureScale(const QSizeF & arg) {tex_scale = arg;}
|
||||
|
||||
void addForce(const QVector3D & f) {forces << f;}
|
||||
void birthParticles(int count) {need_birth += count;}
|
||||
|
||||
float frequency() const {return freq;}
|
||||
void setFrequency(const float & f) {freq = f;}
|
||||
|
||||
float additionalSpeed;
|
||||
|
||||
private:
|
||||
QVector3D speedDirection_, emitterPosition_, emitterDirection_;
|
||||
QRectF tex_rect;
|
||||
QSizeF tex_scale;
|
||||
Box3D emitterRect_;
|
||||
QMutex mutex;
|
||||
GLParticlesSystem::Type emitterType_;
|
||||
GLTextureManager::Animation * animation;
|
||||
QVector<GLfloat> vertices, texcoords, colors;
|
||||
QVector<Particle> particles;
|
||||
QVector<QVector3D> forces;
|
||||
float birthRate_, initialSpeed_, speedDecay_, lifeDuration_, size_, freq, need_birth, tick_birth, tick_life, fade_time;
|
||||
float lifeDurationJitter_, speedJitter_, speedDirectionJitter_, sizeJitter_, angleJitter_, initialAngle_;
|
||||
float enlargeSpeed_, enlargeSpeedJitter_, baseAngle_;
|
||||
bool active_, birthEnabled_, is_diffuse_anim, add_vert_face;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator <(const GLParticlesSystem::Particle & f, const GLParticlesSystem::Particle & s) {return f.pos_h.z() > s.pos_h.z();}
|
||||
|
||||
#endif // GLPARTICLES_SYSTEM_H
|
||||
220
test/qglview/glprimitives.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
|
||||
void GLPrimitivePoint::draw(QOpenGLShaderProgram * prog, bool simplest) {
|
||||
glPointSize(sz);
|
||||
glColor3f(material_.color_diffuse.redF(), material_.color_diffuse.greenF(), material_.color_diffuse.blueF());
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3d(0., 0., 0.);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLPrimitiveLine::draw(QOpenGLShaderProgram * prog, bool simplest) {
|
||||
glColor3f(material_.color_diffuse.redF(), material_.color_diffuse.greenF(), material_.color_diffuse.blueF());
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(p0.x(), p0.y(), p0.z());
|
||||
glVertex3f(p1.x(), p1.y(), p1.z());
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLPrimitiveCube::GLPrimitiveCube(float width, float length, float height, QVector3D pos): GLObjectBase() {
|
||||
geom_prim = Quads;
|
||||
w = width;
|
||||
l = length;
|
||||
h = height;
|
||||
moveTo(pos);
|
||||
//init();
|
||||
}
|
||||
|
||||
|
||||
void GLPrimitiveCube::init() {
|
||||
float hw = w / 2.f, hl = l / 2.f, hh = h / 2.f;
|
||||
//list = glGenLists(1);
|
||||
//glNewList(list, GL_COMPILE);
|
||||
//glColor4d(material_.color_diffuse.redF(), material_.color_diffuse.greenF(), material_.color_diffuse.blueF(), material_.color_diffuse.alphaF());
|
||||
vbo.init();
|
||||
QVector<GLfloat> & d_vertices(vbo.vertices()), & d_normals(vbo.normals()), & d_uvs(vbo.texcoords());
|
||||
d_vertices.clear();
|
||||
d_normals.clear();
|
||||
d_uvs.clear();
|
||||
for (int i = 0; i < 4; ++i)
|
||||
d_normals << 0. << -1. << 0.;
|
||||
d_vertices << -hw << -hl << -hh;
|
||||
d_vertices << hw << -hl << -hh;
|
||||
d_vertices << hw << -hl << hh;
|
||||
d_vertices << -hw << -hl << hh;
|
||||
d_uvs << 0. << 0. << 1. << 0. << 1. << 1. << 0. << 1.;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
d_normals << 0. << 1. << 0.;
|
||||
d_vertices << -hw << hl << -hh;
|
||||
d_vertices << -hw << hl << hh;
|
||||
d_vertices << hw << hl << hh;
|
||||
d_vertices << hw << hl << -hh;
|
||||
d_uvs << 0. << 0. << 1. << 0. << 1. << 1. << 0. << 1.;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
d_normals << -1. << 0. << 0.;
|
||||
d_vertices << -hw << -hl << -hh;
|
||||
d_vertices << -hw << -hl << hh;
|
||||
d_vertices << -hw << hl << hh;
|
||||
d_vertices << -hw << hl << -hh;
|
||||
d_uvs << 0. << 0. << 1. << 0. << 1. << 1. << 0. << 1.;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
d_normals << 1. << 0. << 0.;
|
||||
d_vertices << hw << -hl << -hh;
|
||||
d_vertices << hw << hl << -hh;
|
||||
d_vertices << hw << hl << hh;
|
||||
d_vertices << hw << -hl << hh;
|
||||
d_uvs << 0. << 0. << 1. << 0. << 1. << 1. << 0. << 1.;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
d_normals << 0. << 0. << -1.;
|
||||
d_vertices << -hw << -hl << -hh;
|
||||
d_vertices << -hw << hl << -hh;
|
||||
d_vertices << hw << hl << -hh;
|
||||
d_vertices << hw << -hl << -hh;
|
||||
d_uvs << 0. << 0. << 1. << 0. << 1. << 1. << 0. << 1.;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
d_normals << 0. << 0. << 1.;
|
||||
d_vertices << -hw << -hl << hh;
|
||||
d_vertices << hw << -hl << hh;
|
||||
d_vertices << hw << hl << hh;
|
||||
d_vertices << -hw << hl << hh;
|
||||
d_uvs << 0. << 0. << 1. << 0. << 1. << 1. << 0. << 1.;
|
||||
is_init = true;
|
||||
vbo.rebuffer();
|
||||
}
|
||||
|
||||
|
||||
GLPrimitiveEllipsoid::GLPrimitiveEllipsoid(float width, float length, float height, int seg_wl, int seg_h, QVector3D pos) {
|
||||
geom_prim = GLObjectBase::Triangles;
|
||||
w = width;
|
||||
l = length;
|
||||
h = height;
|
||||
swl = seg_wl;
|
||||
sh = seg_h;
|
||||
moveTo(pos);
|
||||
//init();
|
||||
}
|
||||
|
||||
|
||||
void GLPrimitiveEllipsoid::putTriangle(const QVector3D & v0, const QVector3D & v1, const QVector3D & v2) {
|
||||
vbo.vertices() << v0.x() << v0.y() << v0.z() << v1.x() << v1.y() << v1.z() << v2.x() << v2.y() << v2.z();
|
||||
QVector3D n = QVector3D::normal(v1 - v0, v2 - v0);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
vbo.normals() << n.x() << n.y() << n.z();
|
||||
return;
|
||||
QVector3D s(w, l, h);
|
||||
n = (v0 * s).normalized(); vbo.normals() << n.x() << n.y() << n.z();
|
||||
n = (v1 * s).normalized(); vbo.normals() << n.x() << n.y() << n.z();
|
||||
n = (v2 * s).normalized(); vbo.normals() << n.x() << n.y() << n.z();
|
||||
}
|
||||
|
||||
|
||||
void GLPrimitiveEllipsoid::init() {
|
||||
QVector<QVector3D> points;
|
||||
vbo.clear();
|
||||
vbo.init();
|
||||
int ret = 0;
|
||||
int hseg = sh + 1, wlseg = swl + 1;
|
||||
float crw, crl, a, ch, twl;
|
||||
QVector3D cp(0., 0., -h / 2.f);
|
||||
points << cp;
|
||||
for (int i = 1; i < hseg; i++) {
|
||||
ch = -cosf((float)i / hseg * float(M_PI));
|
||||
cp.setZ(ch * h / 2.f);
|
||||
twl = sqrtf(1.f - ch * ch) / 2.f;
|
||||
crw = twl * w;
|
||||
crl = twl * l;
|
||||
for (int j = 0; j < wlseg * 2; j++) {
|
||||
a = (float)j / wlseg * float(M_PI);
|
||||
cp.setY(crw * sinf(a));
|
||||
cp.setX(crl * cosf(a));
|
||||
points << cp;
|
||||
ret = points.size() - 1;
|
||||
if (i == 1)
|
||||
if (j > 0) putTriangle(points[0], points[ret], points[ret - 1]);
|
||||
if (j > 0) {
|
||||
if (i > 1) {
|
||||
putTriangle(points[ret - wlseg * 2 - 1], points[ret], points[ret - 1]);
|
||||
putTriangle(points[ret - wlseg * 2], points[ret], points[ret - wlseg * 2 - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == 1) putTriangle(points[0], points[ret - wlseg * 2 + 1], points[ret]);
|
||||
else {
|
||||
putTriangle(points[ret - wlseg * 2 + 1], points[ret], points[ret - wlseg * 2]);
|
||||
putTriangle(points[ret - wlseg * 2 + 1], points[ret - wlseg * 2], points[ret - wlseg * 4 + 1]);
|
||||
}
|
||||
}
|
||||
points << QVector3D(0., 0., h / 2.f);
|
||||
ret = points.size() - 1;
|
||||
putTriangle(points[ret - 1], points[ret - wlseg * 2], points[ret]);
|
||||
for (int j = 1; j < wlseg * 2; j++)
|
||||
if (j > 0) putTriangle(points[ret - wlseg * 2 + j - 1], points[ret - wlseg * 2 + j], points[ret]);
|
||||
is_init = true;
|
||||
vbo.rebuffer();
|
||||
}
|
||||
|
||||
|
||||
void GLPrimitiveAxis::draw(QOpenGLShaderProgram * prog, bool simplest) {
|
||||
float bs = 1.f;
|
||||
float as = 0.1f;
|
||||
float aw = 0.07f;
|
||||
float cr_x = 0.8f, cg_y = 0.75f, cb_z = 0.8f;
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(cr_x, 0, 0);
|
||||
glVertex3f(-bs, 0, 0);
|
||||
glVertex3f(bs, 0, 0);
|
||||
glVertex3f(bs, 0, 0);
|
||||
glVertex3f(bs-as, aw, 0);
|
||||
glVertex3f(bs, 0, 0);
|
||||
glVertex3f(bs-as, -aw, 0);
|
||||
glVertex3f(bs, 0, 0);
|
||||
glVertex3f(bs-as, 0, aw);
|
||||
glVertex3f(bs, 0, 0);
|
||||
glVertex3f(bs-as, 0, -aw);
|
||||
glColor3f(0, cg_y, 0);
|
||||
glVertex3f(0, -bs, 0);
|
||||
glVertex3f(0, bs, 0);
|
||||
glVertex3f(0, bs, 0);
|
||||
glVertex3f(0, bs-as, aw);
|
||||
glVertex3f(0, bs, 0);
|
||||
glVertex3f(0, bs-as, -aw);
|
||||
glVertex3f(0, bs, 0);
|
||||
glVertex3f(aw, bs-as, 0);
|
||||
glVertex3f(0, bs, 0);
|
||||
glVertex3f(-aw, bs-as, 0);
|
||||
glColor3f(0, 0, cb_z);
|
||||
glVertex3f(0, 0, -bs);
|
||||
glVertex3f(0, 0, bs);
|
||||
glVertex3f(0, 0, bs);
|
||||
glVertex3f(aw, 0, bs-as);
|
||||
glVertex3f(0, 0, bs);
|
||||
glVertex3f(-aw, 0, bs-as);
|
||||
glVertex3f(0, 0, bs);
|
||||
glVertex3f(0, aw, bs-as);
|
||||
glVertex3f(0, 0, bs);
|
||||
glVertex3f(0, -aw, bs-as);
|
||||
glEnd();
|
||||
}
|
||||
85
test/qglview/glprimitives.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
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 "globject.h"
|
||||
|
||||
|
||||
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 GLPrimitiveCube: public GLObjectBase
|
||||
{
|
||||
public:
|
||||
GLPrimitiveCube(float width = 1., float length = 1., float height = 1., QVector3D pos = QVector3D());
|
||||
virtual void init();
|
||||
private:
|
||||
float w, l, h;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
321
test/qglview/glrendererbase.cpp
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
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(GLObjectBase & o, GLRendererBase::RenderingParameters & rp, bool first_object) {
|
||||
if (first_object) {
|
||||
view.glReleaseTextures();
|
||||
return;
|
||||
}
|
||||
setupShadersTextures(o, rp);
|
||||
Material & mat(o.material_);
|
||||
if (rp.light) {
|
||||
if (o.accept_light) {if (!rp.prev_light) {glSetLightEnabled(true); rp.prev_light = true;}}
|
||||
else {if (rp.prev_light) {glSetLightEnabled(false); rp.prev_light = false;}}
|
||||
}
|
||||
if (rp.fog) {
|
||||
if (o.accept_fog) {if (!rp.prev_fog) {glSetFogEnabled(true); rp.prev_fog = true;}}
|
||||
else {if (rp.prev_fog) {glSetFogEnabled(false); rp.prev_fog = false;}}
|
||||
}
|
||||
if (rp.textures) {
|
||||
BIND_TEXTURE(0, map_diffuse)
|
||||
BIND_TEXTURE(1, map_normal)
|
||||
BIND_TEXTURE(2, map_relief)
|
||||
BIND_TEXTURE(3, map_self_illumination)
|
||||
BIND_TEXTURE(4, map_specularity)
|
||||
BIND_TEXTURE(5, map_specular)
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
glSetLightEnabled(rpl.prev_light);
|
||||
glSetFogEnabled(rpl.prev_fog);
|
||||
glSetCapEnabled(GL_TEXTURE_2D, rpl.textures);
|
||||
glSetCapEnabled(GL_BLEND, pass == GLObjectBase::Transparent);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_TEXTURE_CUBE_MAP);
|
||||
glPushMatrix();
|
||||
renderSingleObject(view.objects_, rpl);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void GLRendererBase::renderSingleObject(GLObjectBase & 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 != GLObjectBase::View ? o.render_mode : (view.rmode != GLObjectBase::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 (GLObjectBase * 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 = GLObjectBase::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(GLObjectBase & 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 != GLObjectBase::View ? o.render_mode : (view.rmode != GLObjectBase::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 (GLObjectBase * 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());
|
||||
}
|
||||
80
test/qglview/glrendererbase.h
Normal 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(GLObjectBase & object, GLRendererBase::RenderingParameters & rp, bool first_object = false);
|
||||
virtual void setupShadersTextures(GLObjectBase & 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(GLObjectBase & o, RenderingParameters & rpl);
|
||||
void renderShadow(Light * l, QOpenGLShaderProgram * prog = 0, QMatrix4x4 mat = QMatrix4x4());
|
||||
void renderSingleShadow(GLObjectBase & o, RenderingParameters & rpl);
|
||||
|
||||
QGLView & view;
|
||||
QImage white_image, violent_image;
|
||||
GLuint white_image_id, violent_image_id;
|
||||
|
||||
};
|
||||
|
||||
#endif // GLRENDERERBASE_H
|
||||
253
test/qglview/glshaders.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
const char qgl_vertex_head[] =
|
||||
"in vec3 _qgl_Vertex;\n"
|
||||
"in vec3 qgl_Normal;\n"
|
||||
"in vec3 qgl_Tangent;\n"
|
||||
"in vec3 qgl_Bitangent;\n"
|
||||
"in vec2 qgl_Texture;\n"
|
||||
"in vec4 qgl_Color;\n"
|
||||
"out vec2 qgl_FragTexture;\n"
|
||||
"out vec4 qgl_FragColor;\n"
|
||||
"vec4 qgl_Vertex = vec4(_qgl_Vertex, 1.);\n"
|
||||
"vec4 qgl_ftransform() {return qgl_ModelViewProjectionMatrix * qgl_Vertex;}\n";
|
||||
|
||||
const char qgl_fragment_head[] =
|
||||
"in vec2 qgl_FragTexture;\n"
|
||||
"in vec4 qgl_FragColor;\n"
|
||||
"out vec4 qgl_FragData[gl_MaxDrawBuffers];\n";
|
||||
|
||||
const char qgl_uniform[] =
|
||||
"uniform mat4 qgl_ModelViewMatrix;\n"
|
||||
"uniform mat4 qgl_ProjectionMatrix;\n"
|
||||
"uniform mat4 qgl_ModelViewProjectionMatrix;\n"
|
||||
"uniform mat3 qgl_NormalMatrix;\n"
|
||||
"uniform mat4 qgl_ModelViewMatrixInverse;\n"
|
||||
"uniform mat4 qgl_ProjectionMatrixInverse;\n"
|
||||
"uniform mat4 qgl_ModelViewProjectionMatrixInverse;\n"
|
||||
"uniform mat4 qgl_ModelViewMatrixTranspose;\n"
|
||||
"uniform mat4 qgl_ProjectionMatrixTranspose;\n"
|
||||
"uniform mat4 qgl_ModelViewProjectionMatrixTranspose;\n"
|
||||
"uniform mat4 qgl_ModelViewMatrixInverseTranspose;\n"
|
||||
"uniform mat4 qgl_ProjectionMatrixInverseTranspose;\n"
|
||||
"uniform mat4 qgl_ModelViewProjectionMatrixInverseTranspose;\n";
|
||||
|
||||
const char qgl_structs[] =
|
||||
"const int qgl_MaxLights = 8;\n"
|
||||
"struct QGLLight {\n"
|
||||
" vec4 color;\n"
|
||||
" vec4 position;\n"
|
||||
" vec4 direction;\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 QGLMap {\n"
|
||||
" float offset;\n"
|
||||
" float amount;\n"
|
||||
" sampler2D map;\n"
|
||||
"};\n"
|
||||
"struct QGLMaterial {\n"
|
||||
" float transparency;\n"
|
||||
" float reflectivity;\n"
|
||||
" float iof;\n"
|
||||
" float dispersion;\n"
|
||||
" vec4 color_diffuse;\n"
|
||||
" vec4 color_specular;\n"
|
||||
" vec4 color_self_illumination;\n"
|
||||
" QGLMap map_diffuse;\n"
|
||||
" QGLMap map_normal;\n"
|
||||
" QGLMap map_relief;\n"
|
||||
" QGLMap map_self_illumination;\n"
|
||||
" QGLMap map_specularity;\n"
|
||||
" QGLMap map_specular;\n"
|
||||
"};\n"
|
||||
"uniform QGLLight qgl_AmbientLight;\n"
|
||||
"uniform QGLLight qgl_Light[qgl_MaxLights];\n"
|
||||
"uniform QGLMaterial qgl_Material;\n";
|
||||
|
||||
|
||||
QString loadShaderFile(QOpenGLShaderProgram * prog, QOpenGLShader::ShaderType type, const QString & file) {
|
||||
QFile f(file);
|
||||
if (!f.open(QIODevice::ReadOnly)) return "";
|
||||
QString all = QString::fromUtf8(f.readAll());
|
||||
int i = all.indexOf("#version");
|
||||
QString version = all.mid(i + 8, all.indexOf("\n", i) - i - 8).trimmed();
|
||||
if (version.toInt() >= 150) {
|
||||
int ip = all.indexOf("\n", i);
|
||||
if (ip < 0) return all;
|
||||
if (type == QOpenGLShader::Vertex) {
|
||||
all.insert(ip + 1, qgl_vertex_head);
|
||||
}
|
||||
if (type == QOpenGLShader::Fragment) {
|
||||
all.insert(ip + 1, qgl_fragment_head);
|
||||
}
|
||||
all.insert(ip + 1, qgl_structs);
|
||||
all.insert(ip + 1, qgl_uniform);
|
||||
}
|
||||
prog->addShaderFromSourceCode(type, all);
|
||||
// qDebug() << "********" << all;
|
||||
return all;
|
||||
}
|
||||
|
||||
|
||||
bool loadShaders(QOpenGLShaderProgram * prog, const QString & name, const QString & dir) {
|
||||
prog->removeAllShaders();
|
||||
QDir d(dir);
|
||||
QFileInfoList sl;
|
||||
//qDebug() << "[QGLView] Shader \"" + name + "\" load shaders from" << d.absolutePath();
|
||||
sl = d.entryInfoList(QStringList(name + ".geom"), QDir::Files | QDir::NoDotAndDotDot);
|
||||
foreach (const QFileInfo & i, sl) {
|
||||
//qDebug() << "[QGLView] Shader \"" + name + "\" add geometry shader:" << i.fileName();
|
||||
loadShaderFile(prog, QOpenGLShader::Geometry, i.absoluteFilePath());
|
||||
}
|
||||
sl = d.entryInfoList(QStringList(name + ".vert"), QDir::Files | QDir::NoDotAndDotDot);
|
||||
foreach (const QFileInfo & i, sl) {
|
||||
//qDebug() << "[QGLView] Shader \"" + name + "\" add vertex shader:" << i.fileName();
|
||||
loadShaderFile(prog, QOpenGLShader::Vertex, i.absoluteFilePath());
|
||||
}
|
||||
sl = d.entryInfoList(QStringList(name + ".frag"), QDir::Files | QDir::NoDotAndDotDot);
|
||||
foreach (const QFileInfo & i, sl) {
|
||||
//qDebug() << "[QGLView] Shader \"" + name + "\" add fragment shader:" << i.fileName();
|
||||
loadShaderFile(prog, QOpenGLShader::Fragment, i.absoluteFilePath());
|
||||
}
|
||||
if (!prog->link()) {
|
||||
qDebug() << "[QGLView] Shader \"" + name + "\" link error: " + prog->log();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void 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 setUniformMap(QOpenGLShaderProgram * prog, QString map_name, const Map & map, int channel, int def_channel) {
|
||||
if (!prog) return;
|
||||
if (!prog->isLinked()) return;
|
||||
prog->setUniformValue(("qgl_Material." + map_name + ".offset").toLatin1().constData(), map.color_offset);
|
||||
prog->setUniformValue(("qgl_Material." + map_name + ".amount").toLatin1().constData(), map.color_amount);
|
||||
prog->setUniformValue(("qgl_Material." + map_name + ".map").toLatin1().constData(), map.bitmap_id > 0 ? channel : def_channel);
|
||||
}
|
||||
|
||||
|
||||
void setUniformMaterial(QOpenGLShaderProgram * prog, const Material & mat) {
|
||||
if (!prog) return;
|
||||
if (!prog->isLinked()) return;
|
||||
QOpenGLFunctions *glFuncs = QOpenGLContext::currentContext()->functions();
|
||||
GLfloat mat_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
mat_diffuse[0] = mat.color_diffuse.redF();
|
||||
mat_diffuse[1] = mat.color_diffuse.greenF();
|
||||
mat_diffuse[2] = mat.color_diffuse.blueF();
|
||||
mat_diffuse[3] = mat.color_diffuse.alphaF() * (1.f - mat.transparency);
|
||||
glFuncs->glVertexAttrib4f(prog->attributeLocation("qgl_Color"), mat_diffuse[0], mat_diffuse[1], mat_diffuse[2], mat_diffuse[3]);
|
||||
prog->setUniformValue("qgl_Material.transparency", mat.transparency);
|
||||
prog->setUniformValue("qgl_Material.reflectivity", mat.reflectivity);
|
||||
prog->setUniformValue("qgl_Material.iof", mat.iof);
|
||||
prog->setUniformValue("qgl_Material.dispersion", mat.dispersion);
|
||||
prog->setUniformValue("qgl_Material.color_diffuse", mat.color_diffuse);
|
||||
prog->setUniformValue("qgl_Material.color_self_illumination", mat.color_self_illumination);
|
||||
prog->setUniformValue("qgl_Material.color_specular", mat.color_specular);
|
||||
setUniformMap(prog, "map_diffuse", mat.map_diffuse, 0, 6);
|
||||
setUniformMap(prog, "map_normal", mat.map_normal, 1, 7);
|
||||
setUniformMap(prog, "map_relief", mat.map_relief, 2, 6);
|
||||
setUniformMap(prog, "map_self_illumination", mat.map_self_illumination, 3, 6);
|
||||
setUniformMap(prog, "map_specularity", mat.map_specularity, 4, 6);
|
||||
setUniformMap(prog, "map_specular", mat.map_specular, 5, 6);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void 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 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);//, dir0(light->dir0), dir1(light->dir1);
|
||||
pos = m * pos;
|
||||
dir = (mat * dir).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;
|
||||
}
|
||||
35
test/qglview/glshaders.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
class Map;
|
||||
class Material;
|
||||
class Light;
|
||||
|
||||
QString loadShaderFile(QOpenGLShaderProgram * prog, QOpenGLShader::ShaderType type, const QString & file);
|
||||
bool loadShaders(QOpenGLShaderProgram * prog, const QString & name, const QString & dir = QString());
|
||||
void setUniformMatrices(QOpenGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj = QMatrix4x4(), QMatrix4x4 prevview = QMatrix4x4());
|
||||
void setUniformMap(QOpenGLShaderProgram * prog, const Map & map, int channel, int def_channel);
|
||||
void setUniformMaterial(QOpenGLShaderProgram * prog, const Material & mat);
|
||||
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
|
||||
67
test/qglview/gltexture_manager.cpp
Normal 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 "gltexture_manager.h"
|
||||
|
||||
|
||||
bool GLTextureManager::loadTextures() {
|
||||
//glGenTextures();
|
||||
QFileInfoList fil;
|
||||
Animation anim;
|
||||
for (int i = 0; i < anim_pathes.size(); ++i) {
|
||||
anim.path = anim_pathes[i].second;
|
||||
anim.bitmaps.clear();
|
||||
fil = QDir(anim_pathes[i].first).entryInfoList(QDir::Files, QDir::Name);
|
||||
foreach (const QFileInfo & fi, fil) {
|
||||
if (fi.baseName().indexOf(anim_pathes[i].second) < 0) continue;
|
||||
anim.bitmaps << loadTexture(fi.filePath(), false);
|
||||
}
|
||||
qDebug() << "[TextureManager] Loaded" << anim.bitmaps.size() << "frames";
|
||||
anim_ids << QPair<QString, Animation>(anim_pathes[i].second, anim);
|
||||
}
|
||||
anim_pathes.clear();
|
||||
foreach (const QString & i, tex_pathes)
|
||||
loadTexture(i, true);
|
||||
tex_pathes.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void GLTextureManager::deleteTextures() {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
QList<GLuint> texs = tex_ids[i].values();
|
||||
qDebug() << "[TextureManager] Delete" << texs.size() << "textures";
|
||||
if (!texs.isEmpty()) glDeleteTextures(texs.size(), &texs[0]);
|
||||
tex_ids[i].clear();
|
||||
}
|
||||
qDebug() << "[TextureManager] Delete" << anim_ids.size() << "animations";
|
||||
for (int i = 0; i < anim_ids.size(); ++i)
|
||||
glDeleteTextures(anim_ids[i].second.bitmaps.size(), anim_ids[i].second.bitmaps.data());
|
||||
anim_ids.clear();
|
||||
}
|
||||
|
||||
|
||||
void GLTextureManager::deleteTexture(const QString & name) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (tex_ids[i].contains(name)) {
|
||||
GLuint id = tex_ids[i][name];
|
||||
glDeleteTextures(1, &id);
|
||||
tex_ids[i].remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
test/qglview/gltexture_manager.h
Normal 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 GLTEXTUREMANAGER_H
|
||||
#define GLTEXTUREMANAGER_H
|
||||
|
||||
#include "glmaterial.h"
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
class GLTextureManager: public GLTextureManagerBase
|
||||
{
|
||||
public:
|
||||
GLTextureManager() {;}
|
||||
~GLTextureManager() {deleteTextures();}
|
||||
|
||||
struct Animation {
|
||||
QString path;
|
||||
QVector<GLuint> bitmaps;
|
||||
GLuint bitmapID(const int frame) {if (frame < 0 || frame >= bitmaps.size()) return 0; return bitmaps[frame];}
|
||||
};
|
||||
|
||||
void addTexture(const QString & path) {tex_pathes << path;}
|
||||
void addAnimation(const QString & dir, const QString & name) {anim_pathes << QPair<QString, QString>(dir, name);}
|
||||
bool loadTextures();
|
||||
void deleteTextures();
|
||||
void deleteTexture(const QString & name);
|
||||
Animation * findAnimation(const QString & name) {for (int i = 0; i < anim_ids.size(); ++i) if (anim_ids[i].first == name) return &(anim_ids[i].second); return 0;}
|
||||
|
||||
QVector<QPair<QString, Animation> > anim_ids;
|
||||
|
||||
private:
|
||||
QStringList tex_pathes;
|
||||
QList<QPair<QString, QString> > anim_pathes;
|
||||
|
||||
};
|
||||
|
||||
#endif // GLTEXTUREMANAGER_H
|
||||
379
test/qglview/gltypes.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
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 <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);
|
||||
int loc = prog ? prog->attributeLocation("qgl_Color") : 0,
|
||||
locv = prog ? prog->attributeLocation("qgl_Vertex") : 0,
|
||||
loct = prog ? prog->attributeLocation("qgl_Texture") : 0,
|
||||
locc = prog ? prog->attributeLocation("view_corner") : 0;
|
||||
glBegin(GL_QUADS);
|
||||
QOpenGLFunctions *glFuncs = QOpenGLContext::currentContext()->functions();
|
||||
if (prog) {
|
||||
glFuncs->glVertexAttrib3f(loc, 1.f, 1.f, 1.f);
|
||||
}
|
||||
glColor3f(1.f, 1.f, 1.f);
|
||||
if (prog) {
|
||||
if (corner_dirs)
|
||||
prog->setAttributeValue(locc, corner_dirs[0]);
|
||||
glFuncs->glVertexAttrib2f(loct, 0.f, 0.f);
|
||||
glFuncs->glVertexAttrib2f(locv, x, y);
|
||||
}
|
||||
glTexCoord2f(0.f, 0.f);
|
||||
glVertex2f(x, y);
|
||||
if (prog) {
|
||||
if (corner_dirs)
|
||||
prog->setAttributeValue(locc, corner_dirs[1]);
|
||||
glFuncs->glVertexAttrib2f(loct, 1.f, 0.f);
|
||||
glFuncs->glVertexAttrib2f(locv, x + w, y);
|
||||
}
|
||||
glTexCoord2f(1.f, 0.f);
|
||||
glVertex2f(x + w, y);
|
||||
if (prog) {
|
||||
if (corner_dirs)
|
||||
prog->setAttributeValue(locc, corner_dirs[2]);
|
||||
glFuncs->glVertexAttrib2f(loct, 1.f, 1.f);
|
||||
glFuncs->glVertexAttrib2f(locv, x + w, y + h);
|
||||
}
|
||||
glTexCoord2f(1.f, 1.f);
|
||||
glVertex2f(x + w, y + h);
|
||||
if (prog) {
|
||||
if (corner_dirs)
|
||||
prog->setAttributeValue(locc, corner_dirs[3]);
|
||||
glFuncs->glVertexAttrib2f(loct, 0.f, 1.f);
|
||||
glFuncs->glVertexAttrib2f(locv, x, y + h);
|
||||
}
|
||||
glTexCoord2f(0.f, 1.f);
|
||||
glVertex2f(x, 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(GLuint & tex, int width, int height, const GLenum & format, const GLenum & target) {
|
||||
glClearError();
|
||||
if (tex == 0) {
|
||||
glGenTextures(1, &tex);
|
||||
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)
|
||||
glTexImage2D(target, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr);
|
||||
else {
|
||||
int t = GL_UNSIGNED_BYTE;
|
||||
int f = GL_RGBA;
|
||||
if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGBA32F || format == GL_RGBA16F)
|
||||
t = GL_FLOAT;
|
||||
if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGB8 || format == GL_RGB)
|
||||
f = GL_RGB;
|
||||
glTexImage2D(target, 0, format, width, height, 0, f, t, nullptr);
|
||||
//glGenerateMipmap(target);
|
||||
//qDebug() << "glTexImage2D" << width << height << QString::number(t, 16);
|
||||
}
|
||||
//qDebug() << QString::number(glGetError(), 16);
|
||||
}
|
||||
|
||||
|
||||
void createGLTexture(GLuint & tex, const QImage & image, const GLenum & format, const GLenum & target) {
|
||||
if (tex == 0) {
|
||||
glGenTextures(1, &tex);
|
||||
}
|
||||
glBindTexture(target, tex);
|
||||
QImage im = image.mirrored(false, true);///__GLWidget__::convertToGLFormat(image);
|
||||
//const QImage & cim(im);
|
||||
//glClearError();
|
||||
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_3D) {
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
|
||||
}
|
||||
glTexImage2D(target, 0, format, im.width(), im.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, im.bits());
|
||||
//qDebug() << tex << im.width() << im.height() << im.bits() << glGetError();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
ret(0, 0) = t / aspect;
|
||||
ret(1, 1) = t;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Vector3d::Vector3d(const QString & str) {
|
||||
QString s = str.trimmed();
|
||||
int i = s.indexOf("\t");
|
||||
x = s.left(i).toFloat(); s = s.right(s.length() - i - 1); i = s.indexOf("\t");
|
||||
y = s.left(i).toFloat(); s = s.right(s.length() - i - 1);
|
||||
z = s.toFloat();
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QGLViewBase::QGLViewBase() {
|
||||
camera_ = new Camera();
|
||||
textures_manager = new GLTextureManager();
|
||||
}
|
||||
|
||||
|
||||
QGLViewBase::~QGLViewBase() {
|
||||
delete textures_manager;
|
||||
}
|
||||
|
||||
|
||||
Camera * QGLViewBase::camera() {
|
||||
return camera_;
|
||||
}
|
||||
|
||||
|
||||
const Camera * QGLViewBase::camera() const {
|
||||
return camera_;
|
||||
}
|
||||
|
||||
|
||||
void QGLViewBase::setCamera(Camera * camera) {
|
||||
camera_ = camera;
|
||||
}
|
||||
|
||||
|
||||
GLTextureManagerBase * QGLViewBase::textureManager() {
|
||||
return textures_manager;
|
||||
}
|
||||
|
||||
|
||||
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 (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;
|
||||
}
|
||||
348
test/qglview/gltypes.h
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
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 <QOpenGLFunctions>
|
||||
#include <QOpenGLWidget>
|
||||
#include <QOpenGLShader>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#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);}
|
||||
#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));}
|
||||
|
||||
//extern __GLWidget__ * currentQGLView;
|
||||
|
||||
inline void qglColor(const QColor & c) {glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());}
|
||||
void qglMultMatrix(const QMatrix4x4 & m);
|
||||
void glEnableDepth();
|
||||
void glDisableDepth();
|
||||
inline void glResetAllTransforms() {glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}
|
||||
inline void glClearError() {int c = 100; while (glGetError() != GL_NO_ERROR && --c > 0) glGetError();}
|
||||
inline void glClearAccumulation(const QColor & color = Qt::black) {glClearAccum(color.redF(), color.greenF(), color.blueF(), color.alphaF()); glClear(GL_ACCUM_BUFFER_BIT);}
|
||||
void glClearFramebuffer(const QColor & color = Qt::black, bool depth = true);
|
||||
inline void glSetCapEnabled(GLenum cap, bool on = true) {if (on) glEnable(cap); else glDisable(cap);}
|
||||
inline void glSetLightEnabled(bool on) {if (on) glEnable(GL_LIGHTING); else glDisable(GL_LIGHTING);}
|
||||
inline void glSetFogEnabled(bool on) {if (on) glEnable(GL_FOG); else glDisable(GL_FOG);}
|
||||
inline void glSetPolygonMode(GLenum mode) {glPolygonMode(GL_FRONT_AND_BACK, mode);}
|
||||
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);
|
||||
QMatrix4x4 getGLMatrix(GLenum matrix);
|
||||
void setGLMatrix(QMatrix4x4 matrix);
|
||||
inline void deleteGLTexture(GLuint & tex) {if (tex != 0) glDeleteTextures(1, &tex); tex = 0;}
|
||||
//# define QGLCI if (!QOpenGLContext::currentContext()) return; QOpenGLFunctions gf(QOpenGLContext::currentContext());
|
||||
//# define QGLC gf.
|
||||
//inline void glActiveTextureChannel(int channel) {QGLCI gf.glActiveTexture(GL_TEXTURE0 + channel);}
|
||||
//inline void glDisableTextures(int channels = 8) {QGLCI for (int i = channels - 1; i >= 0; --i) {glActiveTextureChannel(i); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_CUBE_MAP);}}
|
||||
//inline void glReleaseTextures(int channels = 8) {QGLCI for (int i = channels - 1; i >= 0; --i) {glActiveTextureChannel(i); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0);}}
|
||||
//inline void glReleaseFramebuffer() {QGLCI gf.glBindFramebuffer(GL_FRAMEBUFFER, 0);}
|
||||
//inline void glReleaseShaders() {QGLCI gf.glUseProgram(0);}
|
||||
//inline void deleteGLFramebuffer(GLuint & fbo) {QGLCI if (fbo != 0) gf.glDeleteFramebuffers(1, &fbo); fbo = 0;}
|
||||
//inline void deleteGLRenderbuffer(GLuint & drbo) {QGLCI if (drbo != 0) gf.glDeleteRenderbuffers(1, &drbo); drbo = 0;}
|
||||
//inline void deleteGLBuffer(GLuint & bo) {QGLCI if (bo != 0) gf.glDeleteBuffers(1, &bo); bo = 0;}
|
||||
//inline void deleteGLVertexArray(GLuint & va) {QGLCI if (va != 0) gf.glDeleteVertexArrays(1, &va); va = 0;}
|
||||
void createGLTexture(GLuint & tex, int width, int height, const GLenum & format = GL_RGBA8, const GLenum & target = GL_TEXTURE_2D);
|
||||
void createGLTexture(GLuint & tex, const QImage & image, const GLenum & format = GL_RGBA8, const GLenum & target = GL_TEXTURE_2D);
|
||||
inline void qglTranslate(const QVector3D & v) {glTranslatef(v.x(), v.y(), v.z());}
|
||||
inline void qglScale(const QVector3D & v) {glScalef(v.x(), v.y(), v.z());}
|
||||
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);}
|
||||
//const double deg2rad = atan(1.) / 45.;
|
||||
//const double rad2deg = 45. / atan(1.);
|
||||
|
||||
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;}
|
||||
|
||||
struct Vector3d;
|
||||
|
||||
GLfloat dot(const Vector3d & v0, const Vector3d & v1);
|
||||
|
||||
struct Vector3d {
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
GLfloat z;
|
||||
Vector3d(GLfloat x_ = 0., GLfloat y_ = 0., GLfloat z_ = 0.) {x = x_; y = y_; z = z_;}
|
||||
Vector3d(const QVector3D & v) {x = v.x(); y = v.y(); z = v.z();}
|
||||
Vector3d(const QString & str);
|
||||
inline void clear() {x = y = z = 0.;}
|
||||
inline GLfloat length() const {return sqrtf(x*x + y*y + z*z);}
|
||||
inline GLfloat lengthSquared() const {return x*x + y*y + z*z;}
|
||||
Vector3d & normalize() {
|
||||
GLfloat l = length();
|
||||
if (l == 0.f) return *this;
|
||||
x /= l; y /= l; z /= l;
|
||||
return *this;
|
||||
}
|
||||
Vector3d normalized() {return Vector3d(*this).normalize();}
|
||||
Vector3d projectTo(Vector3d dir) {dir.normalize(); return dir * dot(dir, *this);}
|
||||
Vector3d operator *(const GLfloat v) {return Vector3d(x*v, y*v, z*v);}
|
||||
Vector3d operator /(const GLfloat v) {return Vector3d(x/v, y/v, z/v);}
|
||||
Vector3d operator +(const GLfloat v) {return Vector3d(x+v, y+v, z+v);}
|
||||
Vector3d operator -(const GLfloat v) {return Vector3d(x-v, y-v, z-v);}
|
||||
Vector3d operator +(const Vector3d & v) {return Vector3d(x + v.x, y + v.y, z + v.z);}
|
||||
Vector3d operator -(const Vector3d & v) {return Vector3d(x - v.x, y - v.y, z - v.z);}
|
||||
Vector3d operator -() {return Vector3d(-x, -y, -z);}
|
||||
Vector3d & operator *=(const GLfloat & v) {x *= v; y *= v; z *= v; return *this;}
|
||||
Vector3d & operator /=(const GLfloat & v) {x /= v; y /= v; z /= v; return *this;}
|
||||
Vector3d & operator +=(const GLfloat & v) {x += v; y += v; z += v; return *this;}
|
||||
Vector3d & operator -=(const GLfloat & v) {x -= v; y -= v; z -= v; return *this;}
|
||||
Vector3d & operator +=(const Vector3d & v) {x += v.x; y += v.y; z += v.z; return *this;}
|
||||
Vector3d & operator -=(const Vector3d & v) {x -= v.x; y -= v.y; z -= v.z; return *this;}
|
||||
bool operator ==(const Vector3d & v) {return x == v.x && y == v.y && z == v.z;}
|
||||
QVector3D toQVector3D() const {return QVector3D(x, y, z);}
|
||||
};
|
||||
|
||||
inline Vector3d operator *(const Vector3d & v0, const Vector3d & v1) {
|
||||
return Vector3d(v0.y * v1.z - v1.y * v0.z, v1.x * v0.z - v0.x * v1.z, v0.x * v1.y - v1.x * v0.y);
|
||||
}
|
||||
inline GLfloat dot(const Vector3d & v0, const Vector3d & v1) {return v0.x*v1.x + v0.y*v1.y + v0.z*v1.z;}
|
||||
|
||||
struct Vector2d {
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
Vector2d(GLfloat x_ = 0., GLfloat y_ = 0.) {x = x_; y = y_;}
|
||||
Vector2d(const Vector3d & v3) {x = v3.x; y = v3.y;}
|
||||
Vector2d operator *(const GLfloat v) {return Vector2d(x*v, y*v);}
|
||||
Vector2d operator /(const GLfloat v) {return Vector2d(x/v, y/v);}
|
||||
Vector2d operator +(const GLfloat v) {return Vector2d(x+v, y+v);}
|
||||
Vector2d operator -(const GLfloat v) {return Vector2d(x-v, y-v);}
|
||||
Vector2d operator +(const Vector3d & v) {return Vector3d(x + v.x, y + v.y);}
|
||||
Vector2d operator -(const Vector3d & v) {return Vector3d(x - v.x, y - v.y);}
|
||||
Vector2d operator +(const Vector2d & v) {return Vector2d(x + v.x, y + v.y);}
|
||||
Vector2d operator -(const Vector2d & v) {return Vector2d(x - v.x, y - v.y);}
|
||||
Vector2d & operator *=(const GLfloat & v) {x *= v; y *= v; return *this;}
|
||||
Vector2d & operator /=(const GLfloat & v) {x /= v; y /= v; return *this;}
|
||||
Vector2d & operator +=(const GLfloat & v) {x += v; y += v; return *this;}
|
||||
Vector2d & operator -=(const GLfloat & v) {x -= v; y -= v; return *this;}
|
||||
Vector2d & operator +=(const Vector3d & v) {x += v.x; y += v.y;; return *this;}
|
||||
Vector2d & operator -=(const Vector3d & v) {x -= v.x; y -= v.y;; return *this;}
|
||||
};
|
||||
|
||||
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);}
|
||||
int p0;
|
||||
int p1;
|
||||
int 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;}
|
||||
QVector3D toQVector3D() const {return QVector3D(p0, p1, 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 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 * 1024 + v.p2 * 1024 * 1024;}
|
||||
inline QDebug operator <<(QDebug d, const Vector3d& v) {d.nospace() << "{" << v.x << ", " << v.y << ", " << v.z << "}"; return d.space();}
|
||||
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 Vector3d & v) {s << v.x << v.y << v.z; return s;}
|
||||
inline QDataStream & operator >>(QDataStream & s, Vector3d & v) {s >> v.x >> v.y >> v.z; return s;}
|
||||
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;}
|
||||
|
||||
QColor colorFromString(const QString & str);
|
||||
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;}
|
||||
|
||||
class GLObjectBase;
|
||||
class QGLView;
|
||||
class Light;
|
||||
class Camera;
|
||||
class GLTextureManagerBase;
|
||||
|
||||
class QGLViewBase
|
||||
{
|
||||
friend class GLObjectBase;
|
||||
public:
|
||||
QGLViewBase();
|
||||
virtual ~QGLViewBase();
|
||||
Camera * camera();
|
||||
const Camera * camera() const;
|
||||
void setCamera(Camera * camera);
|
||||
GLTextureManagerBase * textureManager();
|
||||
protected:
|
||||
virtual void collectLights() = 0;
|
||||
Camera * camera_;
|
||||
GLTextureManagerBase * textures_manager;
|
||||
};
|
||||
|
||||
#endif // GLTYPES_H
|
||||
317
test/qglview/glvbo.cpp
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
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 "glvbo.h"
|
||||
|
||||
|
||||
GLVBO::GLVBO(GLenum usage_) {
|
||||
buffer_ = 0;
|
||||
va_ = 0;
|
||||
usage = usage_;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
GLVBO::~GLVBO() {
|
||||
//destroy();
|
||||
}
|
||||
|
||||
|
||||
void GLVBO::init() {
|
||||
initializeOpenGLFunctions();
|
||||
if (!isInit()) {
|
||||
//glGenVertexArrays(1, &va_);
|
||||
glGenBuffers(1, &buffer_);
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
void GLVBO::destroy() {
|
||||
if (buffer_ != 0) glDeleteFramebuffers(1, &buffer_);
|
||||
buffer_ = 0;
|
||||
// if (va_ != 0) glDeleteVertexArrays(1, &va_);
|
||||
// va_ = 0;
|
||||
}
|
||||
|
||||
|
||||
void GLVBO::calculateBinormals() {
|
||||
tangents_.clear();
|
||||
bitangents_.clear();
|
||||
if (vertices_.isEmpty() || texcoords_.isEmpty()) return;
|
||||
int vcnt = vertices_.size() / 3;
|
||||
if (texcoords_.size() != vcnt * 2) return;
|
||||
int tcnt = vcnt / 3;
|
||||
//qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "...";
|
||||
for (int t = 0; t < tcnt; ++t) {
|
||||
int vi = t*9, ti = t*6;
|
||||
Vector3d v0(vertices_[vi + 0], vertices_[vi + 1], vertices_[vi + 2]);
|
||||
Vector3d v1(vertices_[vi + 3], vertices_[vi + 4], vertices_[vi + 5]);
|
||||
Vector3d v2(vertices_[vi + 6], vertices_[vi + 7], vertices_[vi + 8]);
|
||||
Vector2d t0(texcoords_[ti + 0], texcoords_[ti + 1]);
|
||||
Vector2d t1(texcoords_[ti + 2], texcoords_[ti + 3]);
|
||||
Vector2d t2(texcoords_[ti + 4], texcoords_[ti + 5]);
|
||||
Vector3d dv1 = v1 - v0, dv2 = v2 - v0;
|
||||
Vector2d dt1 = t1 - t0, dt2 = t2 - t0;
|
||||
Vector3d tan;
|
||||
Vector3d bitan;
|
||||
tan = (dv1 * dt2.y - dv2 * dt1.y).normalize();
|
||||
bitan = (dv2 * dt1.x - dv1 * dt2.x).normalize();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
tangents_ << tan.x << tan.y << tan.z;
|
||||
bitangents_ << bitan.x << bitan.y << bitan.z;
|
||||
}
|
||||
//qDebug() << " t" << t << vi << ti << dv1.toQVector3D() << "...";
|
||||
}
|
||||
//qDebug() << "calculateBinormals" << vcnt << tcnt << tangents_.size();
|
||||
}
|
||||
|
||||
|
||||
bool GLVBO::rebuffer(bool clear_) {
|
||||
initializeOpenGLFunctions();
|
||||
QVector<GLfloat> data;
|
||||
//data.clear();
|
||||
calculateBinormals();
|
||||
data << vertices_;
|
||||
if (!normals_.isEmpty()) {
|
||||
data << normals_;
|
||||
has_normals = true;
|
||||
} else has_normals = false;
|
||||
if (!texcoords_.isEmpty()) {
|
||||
data << texcoords_;
|
||||
has_texcoords = true;
|
||||
} else has_texcoords = false;
|
||||
if (!colors_.isEmpty()) {
|
||||
data << colors_;
|
||||
has_colors = true;
|
||||
} else has_colors = false;
|
||||
if (!tangents_.isEmpty()) {
|
||||
data << tangents_ << bitangents_;
|
||||
has_binormals = true;
|
||||
} else has_binormals = false;
|
||||
//glBindVertexArray(va_);
|
||||
//qDebug() << "load buffer" << data.size() << buffer_;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer_);
|
||||
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(GLfloat), data.constData(), usage);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
//glBindVertexArray(0);
|
||||
vert_count = vertices_.size() / 3;
|
||||
changed = false;
|
||||
//qDebug() << "rebuff" << buffer_ << vert_count;
|
||||
if (clear_) clear();
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
|
||||
void GLVBO::draw(GLenum type, QOpenGLShaderProgram * prog, bool simplest) {
|
||||
if (buffer_ == 0 || vert_count == 0) return;
|
||||
if (changed) rebuffer();
|
||||
//qDebug() << "draw" << vert_count;
|
||||
void * offset = (void*)(vert_count * 3 * sizeof(GLfloat));
|
||||
//glBindVertexArray(va_);
|
||||
void * offsets[5] = {0, 0, 0, 0, 0};
|
||||
if (!simplest) {
|
||||
if (has_normals) {
|
||||
offsets[0] = offset;
|
||||
offset = (void*)(llong(offset) + vert_count * 3 * sizeof(GLfloat));
|
||||
}
|
||||
if (has_texcoords) {
|
||||
offsets[1] = offset;
|
||||
offset = (void*)(llong(offset) + vert_count * 2 * sizeof(GLfloat));
|
||||
}
|
||||
if (has_colors) {
|
||||
offsets[2] = offset;
|
||||
offset = (void*)(llong(offset) + vert_count * 4 * sizeof(GLfloat));
|
||||
}
|
||||
if (has_binormals) {
|
||||
offsets[3] = offset;
|
||||
offset = (void*)(llong(offset) + vert_count * 3 * sizeof(GLfloat));
|
||||
offsets[4] = offset;
|
||||
}
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer_);
|
||||
if (prog) {
|
||||
locs.clear();
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
int loc = prog->attributeLocation("_qgl_Vertex");
|
||||
glEnableVertexAttribArray(loc);
|
||||
glVertexAttribPointer(loc, 3, GL_FLOAT, 0, 0, 0);
|
||||
locs << loc;
|
||||
if (!simplest) {
|
||||
loc = prog->attributeLocation("qgl_Normal");
|
||||
if (has_normals) {
|
||||
glEnableVertexAttribArray(loc);
|
||||
glVertexAttribPointer(loc, 3, GL_FLOAT, 0, 0, offsets[0]);
|
||||
locs << loc;
|
||||
} else
|
||||
glDisableVertexAttribArray(loc);
|
||||
loc = prog->attributeLocation("qgl_Texture");
|
||||
if (has_texcoords) {
|
||||
glEnableVertexAttribArray(loc);
|
||||
glVertexAttribPointer(loc, 2, GL_FLOAT, 0, 0, offsets[1]);
|
||||
locs << loc;
|
||||
} else
|
||||
glDisableVertexAttribArray(loc);
|
||||
loc = prog->attributeLocation("qgl_Color");
|
||||
if (has_colors) {
|
||||
glEnableVertexAttribArray(loc);
|
||||
glVertexAttribPointer(loc, 4, GL_FLOAT, 0, 0, offsets[2]);
|
||||
locs << loc;
|
||||
} else
|
||||
glDisableVertexAttribArray(loc);
|
||||
loc = prog->attributeLocation("qgl_Tangent");
|
||||
int loc2 = prog->attributeLocation("qgl_Bitangent");
|
||||
if (has_binormals) {
|
||||
glEnableVertexAttribArray(loc);
|
||||
glEnableVertexAttribArray(loc2);
|
||||
glVertexAttribPointer(loc, 3, GL_FLOAT, 0, 0, offsets[3]);
|
||||
glVertexAttribPointer(loc2, 3, GL_FLOAT, 0, 0, offsets[4]);
|
||||
locs << loc << loc2;
|
||||
} else {
|
||||
glDisableVertexAttribArray(loc);
|
||||
glDisableVertexAttribArray(loc2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
if (!simplest) {
|
||||
if (has_normals) {
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glNormalPointer(GL_FLOAT, 0, offsets[0]);
|
||||
} else glDisableClientState(GL_NORMAL_ARRAY);
|
||||
if (has_texcoords) {
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, offsets[1]);
|
||||
} else glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
if (has_colors) {
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer(4, GL_FLOAT, 0, offsets[2]);
|
||||
} else glDisableClientState(GL_COLOR_ARRAY);
|
||||
}
|
||||
}
|
||||
//qDebug() << "draw" << vert_count << buffer_ << offsets[0] << offsets[1] << offsets[3];
|
||||
glDrawArrays(type, 0, vert_count);
|
||||
//qDebug() << "draw" << vert_count << buffer_ << "done";
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
foreach (int l, locs)
|
||||
glDisableVertexAttribArray(l);
|
||||
}
|
||||
|
||||
|
||||
void GLVBO::clear() {
|
||||
vertices_.clear();
|
||||
normals_.clear();
|
||||
texcoords_.clear();
|
||||
colors_.clear();
|
||||
}
|
||||
|
||||
|
||||
void GLVBO::translatePoints(const QVector3D & dp) {
|
||||
if (vertices_.isEmpty()) return;
|
||||
int vcnt = vertices_.size() / 3;
|
||||
for (int i = 0; i < vcnt; ++i) {
|
||||
int vi = i * 3;
|
||||
vertices_[vi + 0] += dp.x();
|
||||
vertices_[vi + 1] += dp.y();
|
||||
vertices_[vi + 2] += dp.z();
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
void GLVBO::scalePoints(const QVector3D & dp) {
|
||||
if (vertices_.isEmpty()) return;
|
||||
int vcnt = vertices_.size() / 3;
|
||||
for (int i = 0; i < vcnt; ++i) {
|
||||
int vi = i * 3;
|
||||
vertices_[vi + 0] *= dp.x();
|
||||
vertices_[vi + 1] *= dp.y();
|
||||
vertices_[vi + 2] *= dp.z();
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
bool GLVBO::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_ << colors_;
|
||||
ba = qCompress(ba);
|
||||
f.resize(0);
|
||||
f.write(ba);
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GLVBO::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_ >> colors_;
|
||||
changed = true;
|
||||
f.close();
|
||||
return !isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Box3D GLVBO::boundingBox() const {
|
||||
if (vertices_.size() < 3) return Box3D();
|
||||
int vcnt = vertices_.size() / 3;
|
||||
//qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "...";
|
||||
GLfloat mix, miy, miz, max, may, maz;
|
||||
Vector3d v0(vertices_[0], vertices_[1], vertices_[2]);
|
||||
mix = max = v0.x;
|
||||
miy = may = v0.y;
|
||||
miz = maz = v0.z;
|
||||
Box3D bound;
|
||||
for (int t = 1; t < vcnt; ++t) {
|
||||
int vi = t*3;
|
||||
Vector3d v(vertices_[vi + 0], vertices_[vi + 1], vertices_[vi + 2]);
|
||||
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;
|
||||
}
|
||||
98
test/qglview/glvbo.h
Normal 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 GLVBO_H
|
||||
#define GLVBO_H
|
||||
|
||||
#include "gltypes.h"
|
||||
#include "chunkstream.h"
|
||||
|
||||
class GLVBO : protected QOpenGLFunctions
|
||||
{
|
||||
friend class GLObjectBase;
|
||||
friend QDataStream & operator <<(QDataStream & s, const GLVBO & m);
|
||||
friend QDataStream & operator >>(QDataStream & s, GLVBO & m);
|
||||
public:
|
||||
GLVBO(GLenum usage = GL_DYNAMIC_DRAW);
|
||||
~GLVBO();
|
||||
|
||||
//GLVBO & operator =(const GLVBO & o) {return *this;}
|
||||
|
||||
void init();
|
||||
void destroy();
|
||||
bool rebuffer(bool clear_ = false);
|
||||
void draw(GLenum type, QOpenGLShaderProgram * prog, bool simplest = false);
|
||||
void clear();
|
||||
|
||||
GLuint buffer() const {return buffer_;}
|
||||
int verticesCount() const {return vertices_.size() / 3;}
|
||||
bool isInit() const {return buffer_ != 0;}
|
||||
bool isEmpty() const {return vertices_.size() < 3;}
|
||||
|
||||
QVector<GLfloat> & vertices() {changed = true; return vertices_;}
|
||||
QVector<GLfloat> & normals() {changed = true; return normals_;}
|
||||
QVector<GLfloat> & texcoords() {changed = true; return texcoords_;}
|
||||
QVector<GLfloat> & colors() {changed = true; return colors_;}
|
||||
|
||||
void translatePoints(const QVector3D & dp);
|
||||
void scalePoints(const QVector3D & dp);
|
||||
|
||||
bool saveToFile(const QString & filename);
|
||||
bool loadFromFile(const QString & filename);
|
||||
|
||||
Box3D boundingBox() const;
|
||||
|
||||
private:
|
||||
void calculateBinormals();
|
||||
|
||||
QVector<GLfloat> vertices_, normals_, texcoords_, colors_, tangents_, bitangents_;
|
||||
QVector<int> locs;
|
||||
GLenum usage;
|
||||
GLuint buffer_, va_;
|
||||
int vert_count;
|
||||
bool changed, has_normals, has_texcoords, has_colors, has_binormals;
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const GLVBO & m) {
|
||||
ChunkStream cs;
|
||||
//qDebug() << "place VBO" << m.vertices_.size() << m.normals_.size() << m.texcoords_.size() << m.colors_.size() << "...";
|
||||
cs << cs.chunk(1, m.vertices_) << cs.chunk(2, m.normals_) << cs.chunk(3, m.texcoords_) << cs.chunk(4, m.colors_) << cs.chunk(5, m.usage);
|
||||
//qDebug() << "place VBO done" << cs.data().size() << "...";
|
||||
s << qCompress(cs.data()); return s;
|
||||
}
|
||||
inline QDataStream & operator >>(QDataStream & s, GLVBO & m) {
|
||||
QByteArray ba;
|
||||
s >> ba;
|
||||
ba = qUncompress(ba);
|
||||
ChunkStream cs(ba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: m.vertices_ = cs.getData<QVector<GLfloat> >(); break;
|
||||
case 2: m.normals_ = cs.getData<QVector<GLfloat> >(); break;
|
||||
case 3: m.texcoords_ = cs.getData<QVector<GLfloat> >(); break;
|
||||
case 4: m.colors_ = cs.getData<QVector<GLfloat> >(); break;
|
||||
case 5: m.usage = cs.getData<GLenum>(); break;
|
||||
}
|
||||
}
|
||||
m.changed = true;
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // GLVBO_H
|
||||
268
test/qglview/glwidget.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
#include "glwidget.h"
|
||||
#include "renderer_simple.h"
|
||||
#include "renderer_deferred_shading.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();
|
||||
}
|
||||
|
||||
|
||||
void GLWidget::addObject(GLObjectBase * o) {
|
||||
view_->addObject(o);
|
||||
}
|
||||
|
||||
|
||||
QByteArray GLWidget::saveCamera() {
|
||||
ChunkStream cs;
|
||||
const Camera * c = view()->camera();
|
||||
cs.add(1, c->posX());
|
||||
cs.add(2, c->posY());
|
||||
cs.add(3, c->posZ());
|
||||
cs.add(4, c->aim().x());
|
||||
cs.add(5, c->aim().y());
|
||||
cs.add(6, c->aim().z());
|
||||
cs.add(7, c->angleZ());
|
||||
cs.add(8, c->angleXY());
|
||||
cs.add(9, c->angleRoll());
|
||||
cs.add(10, c->FOV());
|
||||
return cs.data();
|
||||
}
|
||||
|
||||
|
||||
void GLWidget::restoreCamera(const QByteArray &ba) {
|
||||
if (ba.isEmpty()) return;
|
||||
ChunkStream cs(ba);
|
||||
QVector3D pos, aim, ang;
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: pos.setX(cs.getData<float>()); break;
|
||||
case 2: pos.setY(cs.getData<float>()); break;
|
||||
case 3: pos.setZ(cs.getData<float>()); break;
|
||||
case 4: aim.setX(cs.getData<float>()); break;
|
||||
case 5: aim.setY(cs.getData<float>()); break;
|
||||
case 6: aim.setZ(cs.getData<float>()); break;
|
||||
case 7: ang.setZ(cs.getData<float>()); break;
|
||||
case 8: ang.setY(cs.getData<float>()); break;
|
||||
case 9: ang.setX(cs.getData<float>()); break;
|
||||
case 10: setFOV(cs.getData<float>()); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
view()->camera()->setPos(pos);
|
||||
view()->camera()->setAim(aim);
|
||||
view()->camera()->setAngles(ang);
|
||||
}
|
||||
|
||||
|
||||
void GLWidget::stop() {
|
||||
view_->stop();
|
||||
}
|
||||
|
||||
|
||||
void GLWidget::start(float freq, GLRendererBase * r) {
|
||||
if (r == nullptr) r = new RendererSimple(view_);
|
||||
GLRendererBase * pr = nullptr;
|
||||
view_->setRenderer(r, &pr);
|
||||
if (pr != nullptr && pr != r) delete pr;
|
||||
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!";
|
||||
}
|
||||
88
test/qglview/glwidget.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef GLWIDGET_H
|
||||
#define GLWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
class QGLView;
|
||||
class GLRendererBase;
|
||||
class GLObjectBase;
|
||||
|
||||
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;
|
||||
|
||||
void addObject(GLObjectBase * o);
|
||||
QByteArray saveCamera();
|
||||
void restoreCamera(const QByteArray & ba);
|
||||
|
||||
public slots:
|
||||
void stop();
|
||||
void start(float freq = 60.0, GLRendererBase * r = nullptr);
|
||||
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
|
||||
BIN
test/qglview/icons/alpha.png
Normal file
|
After Width: | Height: | Size: 158 B |
BIN
test/qglview/icons/application-exit.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
test/qglview/icons/configure.png
Normal file
|
After Width: | Height: | Size: 717 B |
BIN
test/qglview/icons/dialog-close.png
Normal file
|
After Width: | Height: | Size: 813 B |
BIN
test/qglview/icons/document-import.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
test/qglview/icons/document-new.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
test/qglview/icons/document-open.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
test/qglview/icons/document-save-.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
test/qglview/icons/document-save-all.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
test/qglview/icons/document-save.png
Normal file
|
After Width: | Height: | Size: 563 B |
BIN
test/qglview/icons/edit-clear-locationbar-rtl.png
Normal file
|
After Width: | Height: | Size: 644 B |
BIN
test/qglview/icons/edit-clear.png
Normal file
|
After Width: | Height: | Size: 802 B |
BIN
test/qglview/icons/edit-copy.png
Normal file
|
After Width: | Height: | Size: 485 B |
BIN
test/qglview/icons/edit-delete.png
Normal file
|
After Width: | Height: | Size: 640 B |
BIN
test/qglview/icons/edit-find.png
Normal file
|
After Width: | Height: | Size: 634 B |
BIN
test/qglview/icons/edit-guides.png
Normal file
|
After Width: | Height: | Size: 544 B |
BIN
test/qglview/icons/edit-paste.png
Normal file
|
After Width: | Height: | Size: 529 B |
BIN
test/qglview/icons/item-add.png
Normal file
|
After Width: | Height: | Size: 639 B |
BIN
test/qglview/icons/item.png
Normal file
|
After Width: | Height: | Size: 448 B |
BIN
test/qglview/icons/list-add.png
Normal file
|
After Width: | Height: | Size: 564 B |
BIN
test/qglview/icons/node-add.png
Normal file
|
After Width: | Height: | Size: 694 B |
BIN
test/qglview/icons/node.png
Normal file
|
After Width: | Height: | Size: 658 B |
BIN
test/qglview/icons/qglview.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
test/qglview/icons/qglview.xcf
Normal file
BIN
test/qglview/icons/type-camera.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
test/qglview/icons/type-geo.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
test/qglview/icons/type-light.png
Normal file
|
After Width: | Height: | Size: 971 B |
BIN
test/qglview/icons/view-grid.png
Normal file
|
After Width: | Height: | Size: 691 B |
BIN
test/qglview/icons/zoom-fit-best.png
Normal file
|
After Width: | Height: | Size: 539 B |
348
test/qglview/loader_3ds.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
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_3ds.h"
|
||||
|
||||
|
||||
void Loader3DS::init3DSMesh(GLObjectBase * o, const QVector<uint> & smooth) {
|
||||
QVector<GLfloat> & vertices(o->VBO().vertices()), & normals(o->VBO().normals()), & uvs(o->VBO().texcoords());
|
||||
QVector<Vector3d> & points(o->points), & puvws(o->puvws), fnormals;
|
||||
QVector<Vector3i> & faces(o->faces);
|
||||
Vector3d pos = Vector3d(o->pos());
|
||||
bool has_uv = !puvws.isEmpty();
|
||||
Vector3i cf;
|
||||
Vector3d v0, v1, v2, cn0, cn1, cn2;
|
||||
fnormals.resize(faces.size());
|
||||
for (int i = 0; i < points.size(); ++i)
|
||||
points[i] -= pos;
|
||||
for (int i = 0; i < fnormals.size(); ++i) {
|
||||
cf = faces[i];
|
||||
v0 = points[cf.p0];
|
||||
v1 = points[cf.p1];
|
||||
v2 = points[cf.p2];
|
||||
fnormals[i] = ((v1 - v0) * (v2 - v0)).normalized();
|
||||
}
|
||||
int fcnt = faces.size() * 3;
|
||||
vertices.resize(fcnt * 3);
|
||||
normals.resize(vertices.size());
|
||||
if (has_uv) uvs.resize(fcnt * 2);
|
||||
int ind = 0, induv = 0, ncnt0, ncnt1, ncnt2, csg;
|
||||
//qDebug() << faces.size();
|
||||
if (smooth.isEmpty()) {
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
cf = faces[i];
|
||||
cn0 = fnormals[i];
|
||||
v0 = points[cf.p0];
|
||||
v1 = points[cf.p1];
|
||||
v2 = points[cf.p2];
|
||||
vertices[ind] = v0.x; normals[ind] = cn0.x; ++ind;
|
||||
vertices[ind] = v0.y; normals[ind] = cn0.y; ++ind;
|
||||
vertices[ind] = v0.z; normals[ind] = cn0.z; ++ind;
|
||||
vertices[ind] = v1.x; normals[ind] = cn0.x; ++ind;
|
||||
vertices[ind] = v1.y; normals[ind] = cn0.y; ++ind;
|
||||
vertices[ind] = v1.z; normals[ind] = cn0.z; ++ind;
|
||||
vertices[ind] = v2.x; normals[ind] = cn0.x; ++ind;
|
||||
vertices[ind] = v2.y; normals[ind] = cn0.y; ++ind;
|
||||
vertices[ind] = v2.z; normals[ind] = cn0.z; ++ind;
|
||||
if (has_uv) {
|
||||
uvs[induv] = puvws[cf.p0].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p0].y; ++induv;
|
||||
uvs[induv] = puvws[cf.p1].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p1].y; ++induv;
|
||||
uvs[induv] = puvws[cf.p2].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p2].y; ++induv;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
cf = faces[i];
|
||||
csg = smooth[i];
|
||||
v0 = points[cf.p0];
|
||||
v1 = points[cf.p1];
|
||||
v2 = points[cf.p2];
|
||||
|
||||
cn0 = cn1 = cn2 = fnormals[i];
|
||||
ncnt0 = ncnt1 = ncnt2 = 1;
|
||||
for (int j = 0; j < faces.size(); ++j) {
|
||||
if (csg != smooth[j] || j == i) continue;
|
||||
if (faces[j].p0 == cf.p0 || faces[j].p1 == cf.p0 || faces[j].p2 == cf.p0 ||
|
||||
points[faces[j].p0] == v0 || points[faces[j].p1] == v0 || points[faces[j].p2] == v0) {
|
||||
cn0 += fnormals[j];
|
||||
++ncnt0;
|
||||
}
|
||||
if (faces[j].p0 == cf.p1 || faces[j].p1 == cf.p1 || faces[j].p2 == cf.p1 ||
|
||||
points[faces[j].p0] == v1 || points[faces[j].p1] == v1 || points[faces[j].p2] == v1) {
|
||||
cn1 += fnormals[j];
|
||||
++ncnt1;
|
||||
}
|
||||
if (faces[j].p0 == cf.p2 || faces[j].p1 == cf.p2 || faces[j].p2 == cf.p2 ||
|
||||
points[faces[j].p0] == v2 || points[faces[j].p1] == v2 || points[faces[j].p2] == v2) {
|
||||
cn2 += fnormals[j];
|
||||
++ncnt2;
|
||||
}
|
||||
}
|
||||
cn0 /= ncnt0;
|
||||
cn1 /= ncnt1;
|
||||
cn2 /= ncnt2;
|
||||
vertices[ind] = v0.x; normals[ind] = cn0.x; ++ind;
|
||||
vertices[ind] = v0.y; normals[ind] = cn0.y; ++ind;
|
||||
vertices[ind] = v0.z; normals[ind] = cn0.z; ++ind;
|
||||
vertices[ind] = v1.x; normals[ind] = cn1.x; ++ind;
|
||||
vertices[ind] = v1.y; normals[ind] = cn1.y; ++ind;
|
||||
vertices[ind] = v1.z; normals[ind] = cn1.z; ++ind;
|
||||
vertices[ind] = v2.x; normals[ind] = cn2.x; ++ind;
|
||||
vertices[ind] = v2.y; normals[ind] = cn2.y; ++ind;
|
||||
vertices[ind] = v2.z; normals[ind] = cn2.z; ++ind;
|
||||
if (has_uv) {
|
||||
uvs[induv] = puvws[cf.p0].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p0].y; ++induv;
|
||||
uvs[induv] = puvws[cf.p1].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p1].y; ++induv;
|
||||
uvs[induv] = puvws[cf.p2].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p2].y; ++induv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Material Loader3DS::materialByName(const QVector<Material> & materials, const QString & name) {
|
||||
foreach (const Material & m, materials)
|
||||
if (m.name == name)
|
||||
return m;
|
||||
return Material();
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * loadFrom3DSFile(const QString & filepath, float scale) {
|
||||
QFile f(filepath);
|
||||
if (!f.exists()) {
|
||||
qDebug() << "[Loader 3DS] Error: can`t open \"" + filepath + "\"";
|
||||
return nullptr;
|
||||
}
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QDataStream stream(&f);
|
||||
QVector<Material> materials;
|
||||
QVector<uint> smooth;
|
||||
QVector<ushort> face_mats;
|
||||
GLObjectBase * root = new GLObjectBase(), * co = nullptr;
|
||||
Material mat;
|
||||
Loader3DS::Chunk cc;
|
||||
Loader3DS::Face face;
|
||||
Vector3d pos;
|
||||
QString str;
|
||||
ushort cnt;
|
||||
QString name;
|
||||
QByteArray ba;
|
||||
int cur_map = 0;
|
||||
float fl, fl1, matrix[3][3];
|
||||
uint col;
|
||||
root->setName(QFileInfo(f).baseName());
|
||||
while (!stream.atEnd()) {
|
||||
stream.readRawData((char * )&cc, sizeof(cc));
|
||||
switch (cc.id) {
|
||||
case LOADER_3DS_CHUNK_MAIN: /*qDebug() << "main" << cc.size;*/ break;
|
||||
case LOADER_3DS_CHUNK_OBJECTS: /*qDebug() << " objects" << cc.size;*/ break;
|
||||
case LOADER_3DS_CHUNK_OBJECT:
|
||||
if (co != nullptr) {
|
||||
Loader3DS::init3DSMesh(co, smooth);
|
||||
root->addChild(co);
|
||||
}
|
||||
co = new GLObjectBase();
|
||||
co->setName(readCharsUntilNull(stream));
|
||||
smooth.clear();
|
||||
//qDebug() << " object" << co->name();
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_MESH: /*qDebug() << " mesh" << cc.size;*/ break;
|
||||
case LOADER_3DS_CHUNK_VERTLIST:
|
||||
stream.readRawData((char * )&cnt, sizeof(ushort));
|
||||
co->points.resize(cnt);
|
||||
//qDebug() << " vertices" << cnt;
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
stream.readRawData((char * )&co->points[i].x, sizeof(float));
|
||||
stream.readRawData((char * )&co->points[i].y, sizeof(float));
|
||||
stream.readRawData((char * )&co->points[i].z, sizeof(float));
|
||||
co->points[i] *= scale;
|
||||
}
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_FACELIST:
|
||||
stream.readRawData((char * )&cnt, sizeof(ushort));
|
||||
co->faces.resize(cnt);
|
||||
//qDebug() << " faces" << cnt;
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
stream.readRawData((char * )&face, sizeof(Loader3DS::Face));
|
||||
co->faces[i].p0 = face.v0;
|
||||
co->faces[i].p1 = face.v1;
|
||||
co->faces[i].p2 = face.v2;
|
||||
}
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_FACEMAT:
|
||||
name = readCharsUntilNull(stream);
|
||||
stream.readRawData((char * )&cnt, sizeof(ushort));
|
||||
face_mats.resize(cnt);
|
||||
for (int i = 0; i < cnt; ++i)
|
||||
stream.readRawData((char * )&(face_mats[i]), sizeof(ushort));
|
||||
//qDebug() << " facemat name" << name << cnt;
|
||||
co->material().name = name;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_MAPLIST:
|
||||
stream.readRawData((char * )&cnt, sizeof(ushort));
|
||||
co->puvws.resize(cnt);
|
||||
//qDebug() << " texcoords" << cnt;
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
stream.readRawData((char * )&co->puvws[i].x, sizeof(float));
|
||||
stream.readRawData((char * )&co->puvws[i].y, sizeof(float));
|
||||
}
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_SMOOTH:
|
||||
cnt = co->faces.size();
|
||||
smooth.resize(cnt);
|
||||
//qDebug() << " smooth" << cnt;
|
||||
for (int i = 0; i < cnt; ++i)
|
||||
stream.readRawData((char * )&smooth[i], sizeof(uint));
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_TRMATRIX:
|
||||
//qDebug() << co->name();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j)
|
||||
stream.readRawData((char * )&(matrix[i][j]), sizeof(float));
|
||||
//qDebug() << matrix[i][0] << matrix[i][1] << matrix[i][2];
|
||||
}
|
||||
stream.readRawData((char * )&pos, sizeof(Vector3d));
|
||||
pos *= scale;
|
||||
//qDebug() << "pos =" << pos;
|
||||
co->setPos(pos.toQVector3D());
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_LIGHT:
|
||||
//qDebug() << " light" << cc.size;
|
||||
str = co->name();
|
||||
delete co;
|
||||
co = new Light();
|
||||
co->setName(str);
|
||||
stream.readRawData((char * )&pos, sizeof(Vector3d));
|
||||
pos *= scale;
|
||||
co->setPos(pos.toQVector3D());
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_SPOTLIGHT:
|
||||
stream.readRawData((char * )&pos, sizeof(Vector3d));
|
||||
pos *= scale;
|
||||
globject_cast<Light * >(co)->light_type = Light::Cone;
|
||||
globject_cast<Light * >(co)->direction = (pos.toQVector3D() - co->pos()).normalized();
|
||||
stream.readRawData((char * )&fl1, sizeof(float));
|
||||
stream.readRawData((char * )&fl, sizeof(float));
|
||||
globject_cast<Light * >(co)->angle_start = fl1;
|
||||
globject_cast<Light * >(co)->angle_end = fl;
|
||||
//qDebug() << "spotlight" << globject_cast<Light * >(co)->direction << globject_cast<Light * >(co)->angle_spread;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_LIGHT_OFF:
|
||||
stream.skipRawData(cc.size - 6);
|
||||
co->hide();
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_ATTENUATION_ON:
|
||||
stream.skipRawData(cc.size - 6);
|
||||
fl = globject_cast<Light * >(co)->decay_end;
|
||||
//fl1 = globject_cast<Light * >(co)->decay_start;
|
||||
globject_cast<Light * >(co)->decay_quadratic = 4.f / fl;
|
||||
//qDebug() << "decay" << globject_cast<Light * >(co)->decay_quadratic;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_COLOR_F:
|
||||
stream.readRawData((char * )&pos, sizeof(Vector3d));
|
||||
co->setColor(QColor::fromRgbF(pos.x, pos.y, pos.z));
|
||||
//qDebug() << " color_f" << co->color();
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_COLOR_B:
|
||||
stream.readRawData((char * )&col, 3);
|
||||
co->setColor(QColor::fromRgb(((uchar * )&col)[0], ((uchar * )&col)[1], ((uchar * )&col)[2]));
|
||||
//qDebug() << " color_b" << co->color();
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_MULTIPLIER:
|
||||
stream.readRawData((char * )&fl, sizeof(float));
|
||||
globject_cast<Light * >(co)->intensity = fl;
|
||||
//qDebug() << " multiplier" << fl;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_RANGE_START:
|
||||
stream.readRawData((char * )&fl, sizeof(float));
|
||||
globject_cast<Light * >(co)->decay_start = fl;
|
||||
//qDebug() << " range start" << fl;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_RANGE_END:
|
||||
stream.readRawData((char * )&fl, sizeof(float));
|
||||
globject_cast<Light * >(co)->decay_end = fl;
|
||||
//qDebug() << " range end" << fl;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_MATERIAL:
|
||||
//stream.skipRawData(cc.size - 6);
|
||||
if (!mat.name.isEmpty())
|
||||
materials << mat;
|
||||
mat = Material();
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_MATERIAL_NAME:
|
||||
mat.name = readCharsUntilNull(stream);
|
||||
//qDebug() << "matname" << mat.name;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_AMBIENT_COLOR:
|
||||
stream.skipRawData(cc.size - 9);
|
||||
stream.readRawData((char * )&col, 3);
|
||||
mat.color_self_illumination = QColor::fromRgb(((uchar * )&col)[0], ((uchar * )&col)[1], ((uchar * )&col)[2]);
|
||||
//qDebug() << "mat diffuse" << mat.color_diffuse;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_DIFFUSE_COLOR:
|
||||
stream.skipRawData(cc.size - 9);
|
||||
stream.readRawData((char * )&col, 3);
|
||||
mat.color_diffuse = QColor::fromRgb(((uchar * )&col)[0], ((uchar * )&col)[1], ((uchar * )&col)[2]);
|
||||
//qDebug() << "mat diffuse" << mat.color_diffuse;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_SPECULAR_COLOR:
|
||||
stream.skipRawData(cc.size - 9);
|
||||
stream.readRawData((char * )&col, 3);
|
||||
mat.color_specular = QColor::fromRgb(((uchar * )&col)[0], ((uchar * )&col)[1], ((uchar * )&col)[2]);
|
||||
//qDebug() << "mat diffuse" << mat.color_diffuse;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_TEXTURE_MAP:
|
||||
cur_map = LOADER_3DS_CHUNK_TEXTURE_MAP;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_BUMP_MAP:
|
||||
cur_map = LOADER_3DS_CHUNK_BUMP_MAP;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_REFLECTION_MAP:
|
||||
cur_map = LOADER_3DS_CHUNK_REFLECTION_MAP;
|
||||
break;
|
||||
case LOADER_3DS_CHUNK_MAP_FILENAME:
|
||||
name = readCharsUntilNull(stream);
|
||||
//qDebug() << " mat map" << QString::number(cur_map, 16) << name;
|
||||
switch (cur_map) {
|
||||
case LOADER_3DS_CHUNK_TEXTURE_MAP: mat.map_diffuse.bitmap_path = name; break;
|
||||
case LOADER_3DS_CHUNK_BUMP_MAP: mat.map_normal.bitmap_path = name; break;
|
||||
}
|
||||
break;
|
||||
default: /*qDebug() << "???" << QString::number(cc.id, 16).rightJustified(4, '0') << cc.size;*/ stream.skipRawData(cc.size - 6);
|
||||
}
|
||||
}
|
||||
if (!mat.name.isEmpty())
|
||||
materials << mat;
|
||||
foreach (const Material & m, materials)
|
||||
qDebug() << m.name;
|
||||
if (co != nullptr) {
|
||||
Loader3DS::init3DSMesh(co, smooth);
|
||||
root->addChild(co);
|
||||
}
|
||||
for (int i = 0; i < root->childCount(); ++i)
|
||||
root->child(i)->material() = Loader3DS::materialByName(materials, root->child(i)->material().name);
|
||||
qDebug() << "[Loader 3DS] Loaded" << root->childCount() << "objects from" << filepath;
|
||||
return root;
|
||||
}
|
||||
77
test/qglview/loader_3ds.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
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_3DS_H
|
||||
#define LOADER_3DS_H
|
||||
|
||||
#include "gltexture_manager.h"
|
||||
#include "globject.h"
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
|
||||
#define LOADER_3DS_CHUNK_MAIN 0x4D4D // [-] сцена
|
||||
#define LOADER_3DS_CHUNK_COLOR_F 0x0010 // [+] цвет во float
|
||||
#define LOADER_3DS_CHUNK_COLOR_B 0x0011 // [+] цвет в byte
|
||||
#define LOADER_3DS_CHUNK_OBJECTS 0x3D3D // [-] всяческие объекты
|
||||
#define LOADER_3DS_CHUNK_OBJECT 0x4000 // [+] объект
|
||||
#define LOADER_3DS_CHUNK_MESH 0x4100 // [-] mesh-объект
|
||||
#define LOADER_3DS_CHUNK_VERTLIST 0x4110 // [+] список вершин
|
||||
#define LOADER_3DS_CHUNK_FACELIST 0x4120 // [+] список граней
|
||||
#define LOADER_3DS_CHUNK_FACEMAT 0x4130 // [+] материалы граней
|
||||
#define LOADER_3DS_CHUNK_MAPLIST 0x4140 // [+] текстурные координаты
|
||||
#define LOADER_3DS_CHUNK_SMOOTH 0x4150 // [+] группы сглаживания
|
||||
#define LOADER_3DS_CHUNK_TRMATRIX 0x4160 // [+] матрица перевода
|
||||
#define LOADER_3DS_CHUNK_LIGHT 0x4600 // [+] источник света
|
||||
#define LOADER_3DS_CHUNK_SPOTLIGHT 0x4610 // [+]
|
||||
#define LOADER_3DS_CHUNK_LIGHT_OFF 0x4620 // [+]
|
||||
#define LOADER_3DS_CHUNK_ATTENUATION_ON 0x4625 // [+]
|
||||
#define LOADER_3DS_CHUNK_RANGE_START 0x4659 // [+]
|
||||
#define LOADER_3DS_CHUNK_RANGE_END 0x465A // [+]
|
||||
#define LOADER_3DS_CHUNK_MULTIPLIER 0x465B // [+]
|
||||
#define LOADER_3DS_CHUNK_CAMERA 0x4700 // [+] объект-камера
|
||||
#define LOADER_3DS_CHUNK_MATERIAL 0xAFFF // [-] материал
|
||||
#define LOADER_3DS_CHUNK_MATERIAL_NAME 0xA000
|
||||
#define LOADER_3DS_CHUNK_AMBIENT_COLOR 0xA010
|
||||
#define LOADER_3DS_CHUNK_DIFFUSE_COLOR 0xA020
|
||||
#define LOADER_3DS_CHUNK_SPECULAR_COLOR 0xA030
|
||||
#define LOADER_3DS_CHUNK_TEXTURE_MAP 0xA200
|
||||
#define LOADER_3DS_CHUNK_BUMP_MAP 0xA230
|
||||
#define LOADER_3DS_CHUNK_REFLECTION_MAP 0xA220
|
||||
#define LOADER_3DS_CHUNK_MAP_FILENAME 0xA300
|
||||
#define LOADER_3DS_CHUNK_MAP_PARAMETERS 0xA351
|
||||
|
||||
namespace Loader3DS {
|
||||
#pragma pack(push, 1)
|
||||
struct Chunk {
|
||||
ushort id;
|
||||
uint size;
|
||||
};
|
||||
struct Face {
|
||||
ushort v0;
|
||||
ushort v1;
|
||||
ushort v2;
|
||||
ushort flags;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
void init3DSMesh(GLObjectBase * o, const QVector<uint> & smooth);
|
||||
Material materialByName(const QVector<Material> & materials, const QString & name);
|
||||
}
|
||||
|
||||
GLObjectBase * loadFrom3DSFile(const QString & filepath, float scale = 1.0);
|
||||
|
||||
#endif // LOADER_3DS_H
|
||||
386
test/qglview/loader_ase.cpp
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
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_ase.h"
|
||||
|
||||
|
||||
void LoaderASE::initASEMesh(GLObjectBase * o) {
|
||||
QVector<GLfloat> & vertices(o->VBO().vertices()), & normals(o->VBO().normals()), & uvs(o->VBO().texcoords());
|
||||
QVector<Vector3d> & points(o->points), & puvws(o->puvws), & fnormals(o->normals);
|
||||
QVector<Vector3i> & faces(o->faces);
|
||||
Vector3d pos = Vector3d(o->pos());
|
||||
bool has_uv = !puvws.isEmpty(), has_norms = !fnormals.isEmpty();
|
||||
Vector3i cf;
|
||||
Vector3d v0, v1, v2, cn0, cn1, cn2;
|
||||
int ni = 0;
|
||||
for (int i = 0; i < points.size(); ++i)
|
||||
points[i] -= pos;
|
||||
if (!has_norms) {
|
||||
fnormals.resize(faces.size() * 3);
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
cf = faces[i];
|
||||
v0 = points[cf.p0];
|
||||
v1 = points[cf.p1];
|
||||
v2 = points[cf.p2];
|
||||
cn0 = ((v1 - v0) * (v2 - v0)).normalized();
|
||||
fnormals[ni] = cn0; ++ni;
|
||||
fnormals[ni] = cn0; ++ni;
|
||||
fnormals[ni] = cn0; ++ni;
|
||||
}
|
||||
}
|
||||
int fcnt = faces.size() * 3;
|
||||
vertices.resize(fcnt * 3);
|
||||
normals.resize(vertices.size());
|
||||
if (has_uv) uvs.resize(fcnt * 2);
|
||||
int ind = 0, induv = 0;
|
||||
qDebug() << "init ase" << faces.size() << "faces";
|
||||
ni = 0;
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
cf = faces[i];
|
||||
v0 = points[cf.p0];
|
||||
v1 = points[cf.p1];
|
||||
v2 = points[cf.p2];
|
||||
cn0 = fnormals[ni]; ++ni;
|
||||
cn1 = fnormals[ni]; ++ni;
|
||||
cn2 = fnormals[ni]; ++ni;
|
||||
vertices[ind] = v0.x; normals[ind] = cn0.x; ++ind;
|
||||
vertices[ind] = v0.y; normals[ind] = cn0.y; ++ind;
|
||||
vertices[ind] = v0.z; normals[ind] = cn0.z; ++ind;
|
||||
vertices[ind] = v1.x; normals[ind] = cn1.x; ++ind;
|
||||
vertices[ind] = v1.y; normals[ind] = cn1.y; ++ind;
|
||||
vertices[ind] = v1.z; normals[ind] = cn1.z; ++ind;
|
||||
vertices[ind] = v2.x; normals[ind] = cn2.x; ++ind;
|
||||
vertices[ind] = v2.y; normals[ind] = cn2.y; ++ind;
|
||||
vertices[ind] = v2.z; normals[ind] = cn2.z; ++ind;
|
||||
if (has_uv) {
|
||||
uvs[induv] = puvws[cf.p0].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p0].y; ++induv;
|
||||
uvs[induv] = puvws[cf.p1].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p1].y; ++induv;
|
||||
uvs[induv] = puvws[cf.p2].x; ++induv;
|
||||
uvs[induv] = puvws[cf.p2].y; ++induv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * loadFromASEFile(const QString & filepath, float scale) {
|
||||
QFile f(filepath);
|
||||
if (!f.exists()) {
|
||||
qDebug() << "[Loader ASE] Error: can`t open" << filepath;
|
||||
return nullptr;
|
||||
}
|
||||
f.open(QIODevice::ReadOnly);
|
||||
//QVector<Material> materials;
|
||||
GLObjectBase * root = new GLObjectBase(), * co = nullptr;
|
||||
root->setName(QFileInfo(f).baseName());
|
||||
QTextStream stream(&f);
|
||||
QVector<Material> materials;
|
||||
QVector<Vector3d> points, puvws;
|
||||
QVector<Vector3i> faces, uvws;
|
||||
QVector<Vector3d> normals;
|
||||
Vector3d cv;
|
||||
int mst = -1;//, mat_ind;
|
||||
qint64 pst;
|
||||
QString line, cname;
|
||||
|
||||
|
||||
/// Parse materials
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MATERIAL_LIST {");
|
||||
}
|
||||
line = stream.readLine().trimmed();
|
||||
mst = line.indexOf("MATERIAL_COUNT");
|
||||
materials.resize(line.right(line.length() - mst - 14).toInt());
|
||||
//qDebug() << materials.size() << "materials";
|
||||
for (int i = 0; i < materials.size(); ++i) {
|
||||
materials[i].map_diffuse.bitmap_id = 0;
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MATERIAL " + QString::number(i) + " {");
|
||||
}
|
||||
/// Parse material i
|
||||
while (line != "}" && !stream.atEnd()) {
|
||||
line = stream.readLine().trimmed();
|
||||
if (line.left(17) == "*MATERIAL_DIFFUSE") {materials[i].color_diffuse = colorFromString(line.right(line.length() - 18)); continue;} //qDebug() << "diffuse " << i << " = " << colorFromString(line.right(line.length() - 18));
|
||||
if (line.left(18) == "*MATERIAL_SPECULAR") {materials[i].color_specular = colorFromString(line.right(line.length() - 19)); continue;} //qDebug() << "specular " << i << " = " << colorFromString(line.right(line.length() - 19));
|
||||
if (line.left(23) == "*MATERIAL_SHINESTRENGTH") {materials[i].map_specular.color_amount = line.right(line.length() - 24).toFloat(); continue;}
|
||||
if (line.left(15) == "*MATERIAL_SHINE") {materials[i].map_specularity.color_amount = 2.f / expf(line.right(line.length() - 16).toFloat()); continue;}
|
||||
if (line.left(22) == "*MATERIAL_TRANSPARENCY") {materials[i].transparency = line.right(line.length() - 23).toFloat(); continue;}
|
||||
if (line.left(12) == "*MAP_DIFFUSE") {
|
||||
line = stream.readLine().trimmed();
|
||||
while (line.left(11) != "*MAP_AMOUNT" && !stream.atEnd()) line = stream.readLine().trimmed();
|
||||
materials[i].map_normal.color_amount = line.right(line.length() - 12).toFloat();
|
||||
while (line.left(7) != "*BITMAP" && !stream.atEnd()) line = stream.readLine().trimmed();
|
||||
materials[i].map_diffuse.bitmap_path = line.mid(9, line.length() - 10);
|
||||
/*if (!materials[i].diffuse.bitmap_path.isEmpty()) {
|
||||
materials[i].diffuse.bitmap_id = currentQGLView->bindTexture(QImage(materials[i].diffuse.bitmap_path));
|
||||
parent->textures << materials[i].diffuse.bitmap_id;
|
||||
}
|
||||
qDebug() << materials[i].diffuse.bitmap_path << ", bind to" << materials[i].diffuse.bitmap_id;*/
|
||||
while (line != "}" && !stream.atEnd()) line = stream.readLine().trimmed();
|
||||
line = "";
|
||||
continue;
|
||||
}
|
||||
if (line.left(9) == "*MAP_BUMP") {
|
||||
line = stream.readLine().trimmed();
|
||||
while (line.left(11) != "*MAP_AMOUNT" && !stream.atEnd()) line = stream.readLine().trimmed();
|
||||
materials[i].map_normal.color_amount = line.right(line.length() - 12).toFloat();
|
||||
//qDebug() << "bump amount" << materials[i].bump.color_amount;
|
||||
while (line.left(7) != "*BITMAP" && !stream.atEnd()) line = stream.readLine().trimmed();
|
||||
materials[i].map_normal.bitmap_path = line.mid(9, line.length() - 10);
|
||||
/*if (!materials[i].bump.bitmap_path.isEmpty()) {
|
||||
materials[i].bump.bitmap_id = currentQGLView->bindTexture(QImage(materials[i].bump.bitmap_path));
|
||||
parent->textures << materials[i].bump.bitmap_id;
|
||||
}
|
||||
qDebug() << materials[i].bump.bitmap_path << ", bind to" << materials[i].bump.bitmap_id;*/
|
||||
while (line != "}" && !stream.atEnd()) line = stream.readLine().trimmed();
|
||||
line = "";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//bs << materials;
|
||||
/// Geometry objects
|
||||
int cotype = 0;
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
if (line.indexOf("GEOMOBJECT {") >= 0 || line.indexOf("LIGHTOBJECT {") >= 0) {
|
||||
if (line.indexOf("GEOMOBJECT {") >= 0) cotype = 0;
|
||||
if (line.indexOf("LIGHTOBJECT {") >= 0) cotype = 1;
|
||||
mst = -1;
|
||||
if (co != nullptr) {
|
||||
co->points = points;
|
||||
co->faces = faces;
|
||||
co->normals = normals;
|
||||
co->uvws = uvws;
|
||||
LoaderASE::initASEMesh(co);
|
||||
root->addChild(co);
|
||||
}
|
||||
co = new GLObjectBase();
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("NODE_NAME");
|
||||
}
|
||||
cname = line.right(line.length() - mst - 10);
|
||||
co->setName(cname.mid(1, cname.length() - 2));
|
||||
qDebug() << co->name();
|
||||
}
|
||||
mst = -1;
|
||||
switch (cotype) {
|
||||
case 0:
|
||||
//qDebug() << "object";
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH {");
|
||||
}
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_NUMVERTEX ");
|
||||
}
|
||||
points.resize(line.right(line.length() - mst - 15).toInt());
|
||||
//qDebug() << points.size() << "vertices";
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_NUMFACES ");
|
||||
}
|
||||
faces.resize(line.right(line.length() - mst - 14).toInt());
|
||||
normals.resize(faces.size() * 3);
|
||||
//qDebug() << faces.size() << "faces";
|
||||
//uvws.resize(faces.size());
|
||||
/// Points
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_VERTEX_LIST {");
|
||||
}
|
||||
for (int i = 0; i < points.size(); ++i) {
|
||||
line = stream.readLine().trimmed();
|
||||
mst = line.indexOf("MESH_VERTEX");
|
||||
points[i] = Vector3d(line.right(line.length() - mst - 17)) * scale;
|
||||
//qDebug() << points[i];
|
||||
}
|
||||
/// Faces
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_FACE_LIST {");
|
||||
}
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
line = stream.readLine().trimmed();
|
||||
mst = line.indexOf("MESH_FACE");
|
||||
line = line.right(line.length() - mst - 15);
|
||||
mst = line.indexOf("A:"); line = line.right(line.length() - mst - 2);
|
||||
mst = line.indexOf("B:");
|
||||
faces[i].p0 = line.left(mst).toInt(); line = line.right(line.length() - mst - 2);
|
||||
mst = line.indexOf("C:");
|
||||
faces[i].p1 = line.left(mst).toInt(); line = line.right(line.length() - mst - 2);
|
||||
mst = line.indexOf("AB");
|
||||
faces[i].p2 = line.left(mst).toInt();
|
||||
//qDebug() << faces[i];
|
||||
}
|
||||
/// Texture coordinates
|
||||
mst = -1;
|
||||
pst = stream.pos();
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_NUMTVERTEX ");
|
||||
}
|
||||
if (mst >= 0) {
|
||||
puvws.resize(line.right(line.length() - mst - 16).toInt());
|
||||
//qDebug() << puvws.size() << "tvertices";
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_TVERTLIST {");
|
||||
}
|
||||
for (int i = 0; i < puvws.size(); ++i) {
|
||||
line = stream.readLine().trimmed();
|
||||
mst = line.indexOf("MESH_TVERT"); line = line.right(line.length() - mst - 10);
|
||||
mst = line.indexOf("\t"); line = line.right(line.length() - mst - 1);
|
||||
puvws[i] = Vector3d(line);
|
||||
}
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_NUMTVFACES ");
|
||||
}
|
||||
uvws.resize(line.right(line.length() - mst - 16).toInt());
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_TFACELIST {");
|
||||
}
|
||||
for (int i = 0; i < uvws.size(); ++i) {
|
||||
line = stream.readLine().trimmed();
|
||||
mst = line.indexOf("MESH_TFACE"); line = line.right(line.length() - mst - 10);
|
||||
mst = line.indexOf("\t"); line = line.right(line.length() - mst - 1);
|
||||
uvws[i] = Vector3i(line);
|
||||
}
|
||||
} else {
|
||||
uvws.clear();
|
||||
uvws.resize(faces.size());
|
||||
stream.seek(pst);
|
||||
}
|
||||
if (puvws.size() <= 0) puvws.resize(1);
|
||||
/// Normals
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_NORMALS {");
|
||||
}
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
line = stream.readLine();
|
||||
line = stream.readLine().trimmed(); mst = line.indexOf(" ");
|
||||
line = line.right(line.length() - mst - 1); normals[i * 3] = Vector3d(line);
|
||||
line = stream.readLine().trimmed(); mst = line.indexOf(" ");
|
||||
line = line.right(line.length() - mst - 1); normals[i * 3 + 1] = Vector3d(line);
|
||||
line = stream.readLine().trimmed(); mst = line.indexOf(" ");
|
||||
line = line.right(line.length() - mst - 1); normals[i * 3 + 2] = Vector3d(line);
|
||||
//qDebug() << normals[i][0] << normals[i][1] << normals[i][2];
|
||||
}
|
||||
/// Material index
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MATERIAL_REF ");
|
||||
}
|
||||
//mat_ind = line.right(line.length() - mst - 13).toInt();
|
||||
//qDebug() << mat_ind.back();
|
||||
if (points.size() == 0 || faces.size() == 0) {
|
||||
mst = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/// Compiling into GLList
|
||||
/*glNewList(model, GL_COMPILE);
|
||||
if (mat_ind < 0 || mat_ind >= materials.size()) {
|
||||
mat_diffuse[0] = cfr;
|
||||
mat_diffuse[1] = cfg;
|
||||
mat_diffuse[2] = cfb;
|
||||
glColor3f(cfr, cfg, cfb);
|
||||
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_none);
|
||||
glMaterialf(GL_FRONT, GL_SHININESS, 0.);
|
||||
} else {
|
||||
materials[mat_ind].apply();
|
||||
//parent->material_ = materials[mat_ind];
|
||||
}
|
||||
glBegin(GL_TRIANGLES);
|
||||
if (normals_) {
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
glNormal3d(normals[i][0].x, normals[i][0].y, normals[i][0].z);
|
||||
glTexCoord3d(puvws[uvws[i].p0].x, puvws[uvws[i].p0].y, puvws[uvws[i].p0].z);
|
||||
cv = points[faces[i].p0] * scale; glVertex3d(cv.x, cv.y, cv.z);
|
||||
glNormal3d(normals[i][1].x, normals[i][1].y, normals[i][1].z);
|
||||
glTexCoord3d(puvws[uvws[i].p1].x, puvws[uvws[i].p1].y, puvws[uvws[i].p1].z);
|
||||
cv = points[faces[i].p1] * scale; glVertex3d(cv.x, cv.y, cv.z);
|
||||
glNormal3d(normals[i][2].x, normals[i][2].y, normals[i][2].z);
|
||||
glTexCoord3d(puvws[uvws[i].p2].x, puvws[uvws[i].p2].y, puvws[uvws[i].p2].z);
|
||||
cv = points[faces[i].p2] * scale; glVertex3d(cv.x, cv.y, cv.z);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
glTexCoord3d(puvws[uvws[i].p0].x, puvws[uvws[i].p0].y, puvws[uvws[i].p0].z);
|
||||
cv = points[faces[i].p0] * scale; glVertex3d(cv.x, cv.y, cv.z);
|
||||
glTexCoord3d(puvws[uvws[i].p1].x, puvws[uvws[i].p1].y, puvws[uvws[i].p1].z);
|
||||
cv = points[faces[i].p1] * scale; glVertex3d(cv.x, cv.y, cv.z);
|
||||
glTexCoord3d(puvws[uvws[i].p2].x, puvws[uvws[i].p2].y, puvws[uvws[i].p2].z);
|
||||
cv = points[faces[i].p2] * scale; glVertex3d(cv.x, cv.y, cv.z);
|
||||
}
|
||||
}
|
||||
glEnd();*/
|
||||
|
||||
///// Save binary
|
||||
//bs << mat_ind << points << faces << puvws << uvws << normals;
|
||||
break;
|
||||
case 1:
|
||||
qDebug() << "light";
|
||||
mst = -1;
|
||||
while (mst < 0 && !stream.atEnd()) {
|
||||
line = stream.readLine();
|
||||
mst = line.indexOf("MESH_NORMALS {");
|
||||
}
|
||||
break;
|
||||
}
|
||||
/// Continue
|
||||
mst = -1;
|
||||
}
|
||||
f.close();
|
||||
if (co != nullptr) {
|
||||
co->points = points;
|
||||
co->faces = faces;
|
||||
co->normals = normals;
|
||||
co->uvws = uvws;
|
||||
LoaderASE::initASEMesh(co);
|
||||
root->addChild(co);
|
||||
}
|
||||
/*parent->points = points;
|
||||
parent->puvws = puvws;
|
||||
parent->faces = faces;
|
||||
parent->uvws = uvws;
|
||||
parent->normals = normals;
|
||||
return model;*/
|
||||
return root;
|
||||
}
|
||||
33
test/qglview/loader_ase.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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_ASE_H
|
||||
#define LOADER_ASE_H
|
||||
|
||||
#include "globject.h"
|
||||
#include <QGLWidget>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace LoaderASE {
|
||||
void initASEMesh(GLObjectBase * o);
|
||||
}
|
||||
|
||||
GLObjectBase * loadFromASEFile(const QString & filepath, float scale = 1.0);
|
||||
|
||||
#endif // LOADER_ASE_H
|
||||
426
test/qglview/loader_dae.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
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_dae.h"
|
||||
#include <QDomDocument>
|
||||
#include <QUrl>
|
||||
|
||||
|
||||
Material LoaderDAE::materialByName(const QVector<Material> & materials, const QString & name) {
|
||||
foreach (const Material & m, materials) {
|
||||
//qDebug() << m.name << " ??? " << name;
|
||||
if (m.name == name)
|
||||
return m;
|
||||
}
|
||||
return Material();
|
||||
}
|
||||
|
||||
|
||||
QColor readXMLColor(QDomElement n) {
|
||||
QStringList sl(n.firstChildElement("color").firstChild().nodeValue().trimmed().split(" "));
|
||||
sl.removeAll("");
|
||||
sl.removeAll(" ");
|
||||
if (sl.size() >= 3)
|
||||
return QColor::fromRgbF(sl[0].toDouble(), sl[1].toDouble(), sl[2].toDouble(), sl.size() >= 4 ? sl[3].toDouble() : 1.);
|
||||
return QColor();
|
||||
}
|
||||
|
||||
|
||||
QVector4D readXMLVector(QDomElement n) {
|
||||
QStringList sl(n.firstChild().nodeValue().trimmed().split(" "));
|
||||
sl.removeAll("");
|
||||
sl.removeAll(" ");
|
||||
if (sl.size() == 3) return QVector4D(sl[0].toFloat(), sl[1].toFloat(), sl[2].toFloat(), 0.);
|
||||
if (sl.size() == 4) return QVector4D(sl[0].toFloat(), sl[1].toFloat(), sl[2].toFloat(), sl[3].toFloat());
|
||||
return QVector4D();
|
||||
}
|
||||
|
||||
|
||||
QMatrix4x4 readXMLMatrix(QDomElement n) {
|
||||
QStringList sl(n.firstChild().nodeValue().trimmed().split(" "));
|
||||
sl.removeAll("");
|
||||
sl.removeAll(" ");
|
||||
if (sl.size() != 16) return QMatrix4x4();
|
||||
QMatrix4x4 m;
|
||||
int ind = -1;
|
||||
for (int r = 0; r < 4; ++r)
|
||||
for (int c = 0; c < 4; ++c)
|
||||
m(r, c) = sl[++ind].toFloat();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
float readXMLFloat(QDomElement n) {
|
||||
return n.firstChildElement("float").firstChild().nodeValue().toFloat();
|
||||
}
|
||||
|
||||
|
||||
QString readXMLTexture(QDomElement n, QDomElement prof, QDomElement li) {
|
||||
QString tex = n.firstChildElement("texture").attribute("texture");
|
||||
if (tex.isEmpty()) return QString();
|
||||
QString tag;
|
||||
QDomNodeList elist = prof.elementsByTagName("newparam");
|
||||
if (elist.isEmpty()) {
|
||||
tag = tex;
|
||||
} else {
|
||||
bool found = false;
|
||||
int cnt = 0;
|
||||
while (!tex.isEmpty() && !found && cnt < 10) {
|
||||
found = false;
|
||||
cnt++;
|
||||
for (int i = 0; i < elist.count(); ++i) {
|
||||
QDomNode dn = elist.at(i);
|
||||
if (dn.attributes().namedItem("sid").nodeValue() == tex) {
|
||||
//qDebug() << "found!";
|
||||
if (dn.firstChild().nodeName() == "sampler2D") {
|
||||
tex = dn.firstChildElement("sampler2D").firstChildElement("source").firstChild().nodeValue();
|
||||
break;
|
||||
}
|
||||
if (dn.firstChild().nodeName() == "surface") {
|
||||
tag = dn.firstChildElement("surface").firstChildElement("init_from").firstChild().nodeValue();
|
||||
//qDebug() << tex << "->" << tag;
|
||||
tex.clear();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cnt == 10) return QString();
|
||||
}
|
||||
//qDebug() << tag;
|
||||
if (tag.isEmpty()) return QString();
|
||||
elist = li.elementsByTagName("image");
|
||||
for (int i = 0; i < elist.count(); ++i) {
|
||||
QDomElement dn = elist.at(i).toElement();
|
||||
if (dn.attribute("id") == tag) {
|
||||
tex = dn.firstChildElement("init_from").firstChild().nodeValue();
|
||||
tex.replace("\\", "/");
|
||||
if (tex.startsWith("file:") && tex.mid(5, 3) != "///") tex.insert(6, "/");
|
||||
//qDebug() << "found" << tex << QUrl(tex).toLocalFile();
|
||||
tex = QUrl(tex).toLocalFile();
|
||||
if (tex == "/") tex.clear();
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
QVector<Material> LoaderDAE::readMaterials(QDomElement le, QDomElement li, bool fbx) {
|
||||
QVector<Material> ret;
|
||||
QDomNodeList elist = le.elementsByTagName("effect");
|
||||
for (int i = 0; i < elist.count(); ++i) {
|
||||
QDomNode dn = elist.at(i);
|
||||
Material mat;
|
||||
mat.name = dn.attributes().namedItem("id").nodeValue();
|
||||
QDomElement prof = dn.firstChildElement("profile_COMMON");
|
||||
QDomNode pn = prof.firstChildElement("technique").firstChild();
|
||||
QColor col;
|
||||
QString text;
|
||||
|
||||
col = readXMLColor(pn.firstChildElement("emission"));
|
||||
if (col.isValid()) mat.color_self_illumination = col;
|
||||
col = readXMLColor(pn.firstChildElement("diffuse"));
|
||||
if (col.isValid()) mat.color_diffuse = col;
|
||||
col = readXMLColor(pn.firstChildElement("specular"));
|
||||
if (col.isValid()) mat.color_specular = col;
|
||||
mat.map_specularity.color_amount = 2.f / expf(readXMLFloat(pn.firstChildElement("shininess")));
|
||||
mat.transparency = readXMLFloat(pn.firstChildElement("transparency"));
|
||||
if (!fbx) mat.transparency = 1.f - mat.transparency;
|
||||
text = readXMLTexture(pn.firstChildElement("diffuse"), prof, li);
|
||||
if (!text.isEmpty()) mat.map_diffuse.bitmap_path = text;
|
||||
text = readXMLTexture(pn.firstChildElement("diffuse"), prof, li);
|
||||
if (!text.isEmpty()) mat.map_diffuse.bitmap_path = text;
|
||||
|
||||
pn = prof.firstChildElement("technique").firstChildElement("extra").firstChild();
|
||||
text = readXMLTexture(pn.firstChildElement("bump"), prof, li);
|
||||
if (!text.isEmpty()) mat.map_normal.bitmap_path = text;
|
||||
|
||||
ret << mat;
|
||||
qDebug() << "** Material" << mat.name;
|
||||
qDebug() << " emission" << mat.color_self_illumination;
|
||||
qDebug() << " diffuse" << mat.color_diffuse;
|
||||
qDebug() << " specular" << mat.color_specular;
|
||||
qDebug() << " transparency" << mat.transparency;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QMatrix4x4 readXMLTransformations(QDomElement n) {
|
||||
QMatrix4x4 tm;
|
||||
QDomNodeList trl = n.childNodes();
|
||||
for (int i = 0; i < trl.count(); ++i) {
|
||||
QDomElement dt = trl.at(i).toElement();
|
||||
}
|
||||
return tm;
|
||||
}
|
||||
|
||||
|
||||
void readScene(QDomElement n, QMatrix4x4 cm, QVector<QPair<QPair<QString, QString>, QMatrix4x4> > & ret, QString last_name = QString()) {
|
||||
QDomNodeList evsl = n.childNodes();
|
||||
if (n.hasAttribute("name")) last_name = n.attribute("name");
|
||||
for (int i = 0; i < evsl.count(); ++i) {
|
||||
QDomElement dt = evsl.at(i).toElement();
|
||||
QVector4D v;
|
||||
//qDebug() << dt.nodeName();
|
||||
if (dt.nodeName() == "translate") {
|
||||
v = readXMLVector(dt);
|
||||
cm.translate(v.toVector3D());
|
||||
continue;
|
||||
}
|
||||
if (dt.nodeName() == "rotate") {
|
||||
v = readXMLVector(dt);
|
||||
cm.rotate(v.w(), v.toVector3D());
|
||||
continue;
|
||||
}
|
||||
if (dt.nodeName() == "scale") {
|
||||
v = readXMLVector(dt);
|
||||
cm.scale(v.toVector3D());
|
||||
continue;
|
||||
}
|
||||
if (dt.nodeName() == "matrix") {
|
||||
QMatrix4x4 m = readXMLMatrix(dt);
|
||||
cm *= m;
|
||||
continue;
|
||||
}
|
||||
if (dt.nodeName() == "node") {
|
||||
readScene(dt, cm, ret, last_name);
|
||||
continue;
|
||||
}
|
||||
if (dt.nodeName() == "instance_geometry" || dt.nodeName() == "instance_light") {
|
||||
QString gid = dt.attribute("url");
|
||||
if (gid.startsWith("#")) gid.remove(0, 1);
|
||||
//qDebug() << "matrix" << gid << cm;
|
||||
ret << QPair<QPair<QString, QString>, QMatrix4x4>(QPair<QString, QString>(gid, last_name), cm);
|
||||
continue;
|
||||
}
|
||||
//qDebug() << name << m;
|
||||
}
|
||||
ret << QPair<QPair<QString, QString>, QMatrix4x4>(QPair<QString, QString>("", last_name), cm);
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * loadFromDAEFile(const QString & filepath, float scale) {
|
||||
QFile f(filepath);
|
||||
if (!f.exists()) {
|
||||
qDebug() << "[Loader DAE] Error: can`t open \"" + filepath + "\"";
|
||||
return nullptr;
|
||||
}
|
||||
QTime tm;
|
||||
tm.restart();
|
||||
QDomDocument dom(filepath);
|
||||
if (!dom.setContent(&f)) {
|
||||
qDebug() << "[Loader DAE] Error: can`t parse \"" + filepath + "\"";
|
||||
return nullptr;
|
||||
}
|
||||
//qDebug() << "parse" << tm.elapsed();
|
||||
tm.restart();
|
||||
QDomElement maine = dom.firstChildElement("COLLADA");
|
||||
bool fbx = maine.firstChildElement("asset").firstChildElement("contributor").firstChildElement("authoring_tool").firstChild().nodeValue().startsWith("FBX");
|
||||
QVector<Material> materials = LoaderDAE::readMaterials(maine.firstChildElement("library_effects"),
|
||||
maine.firstChildElement("library_images"), fbx);
|
||||
GLObjectBase * root = new GLObjectBase(), * co = nullptr;
|
||||
QMap<QString, QVector<GLObjectBase * > > objects;
|
||||
|
||||
QMap<QString, QString> mat_names;
|
||||
QDomElement mvse = maine.firstChildElement("library_visual_scenes").firstChildElement("visual_scene");
|
||||
QDomNodeList evsl = mvse.elementsByTagName("instance_material");
|
||||
QDomNodeList matl = maine.firstChildElement("library_materials").elementsByTagName("material");
|
||||
for (int i = 0; i < evsl.count(); ++i) {
|
||||
QDomElement dn = evsl.at(i).toElement();
|
||||
QString tn = dn.attribute("target");
|
||||
if (tn.startsWith("#")) tn.remove(0, 1);
|
||||
for (int j = 0; j < matl.count(); ++j) {
|
||||
QDomElement dm = matl.at(j).toElement();
|
||||
if (dm.attribute("id") == tn) {
|
||||
QString en = dm.firstChildElement("instance_effect").attribute("url");
|
||||
if (en.startsWith("#")) en.remove(0, 1);
|
||||
mat_names[dn.attribute("symbol")] = en;
|
||||
//qDebug() << dn.attribute("symbol") << "->" << en;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDomNodeList elist = maine.firstChildElement("library_geometries").elementsByTagName("geometry");
|
||||
for (int i = 0; i < elist.count(); ++i) {
|
||||
QDomNode dn = elist.at(i);
|
||||
QString name = dn.attributes().namedItem("name").nodeValue();
|
||||
QString gid = dn.attributes().namedItem("id").nodeValue();
|
||||
if (name.isEmpty()) continue;
|
||||
dn = dn.firstChildElement("mesh");
|
||||
QMap<QString, QString> source_names;
|
||||
QMap<QString, QVector<Vector3d> > source_data;
|
||||
QDomNodeList esrc = dn.toElement().elementsByTagName("source");
|
||||
for (int j = 0; j < esrc.count(); ++j) {
|
||||
QDomNode ds = esrc.at(j);
|
||||
QString id = ds.attributes().namedItem("id").nodeValue();
|
||||
QDomNodeList evert = dn.toElement().elementsByTagName("vertices");
|
||||
for (int k = 0; k < evert.count(); ++k) {
|
||||
QDomNode dv = evert.at(k);
|
||||
QString vid = dv.attributes().namedItem("id").nodeValue();
|
||||
if (dv.firstChildElement("input").attribute("source") == ("#" + id))
|
||||
source_names[vid] = id;
|
||||
//qDebug() << " found source sin" << vid;
|
||||
}
|
||||
QVector<Vector3d> & sd(source_data[id]);
|
||||
int stride = ds.firstChildElement("technique_common").firstChildElement("accessor").attribute("stride").toInt();
|
||||
QString astr = ds.firstChildElement("float_array").firstChild().nodeValue().trimmed();
|
||||
astr.replace("\n", " ");
|
||||
astr.remove("\r");
|
||||
QStringList sl = astr.split(" ");
|
||||
sl.removeAll("");
|
||||
sl.removeAll(" ");
|
||||
for (int c = 0; c < sl.size(); c += stride) {
|
||||
Vector3d v;
|
||||
if (stride >= 1) v.x = sl[c].toFloat();
|
||||
if (stride >= 2) v.y = sl[c + 1].toFloat();
|
||||
if (stride >= 3) v.z = sl[c + 2].toFloat();
|
||||
sd << v;
|
||||
}
|
||||
//qDebug() << " found source" << id << "stride =" << stride << ":" << sd;
|
||||
//qDebug() << " readed" << sd.size();
|
||||
}
|
||||
QDomNodeList etr = dn.toElement().elementsByTagName("triangles");
|
||||
//QMatrix4x4 m = matrices.value(gid);
|
||||
//qDebug() << "found geom" << name;
|
||||
QVector<GLObjectBase * > ol;
|
||||
for (int j = 0; j < etr.count(); ++j) {
|
||||
QDomElement ds = etr.at(j).toElement();
|
||||
QString matname = mat_names[ds.attribute("material")];
|
||||
QVector<int> p;
|
||||
QStringList psl = ds.firstChildElement("p").firstChild().nodeValue().trimmed().split(" ");
|
||||
foreach (const QString & s, psl)
|
||||
p << s.toInt();
|
||||
QDomNodeList einp = ds.elementsByTagName("input");
|
||||
int pbv = einp.count();//, tc = qMin(ds.attribute("count").toInt(), p.size() / pbv);
|
||||
co = new GLObjectBase();
|
||||
co->setName(name + "_" + QString::number(j));
|
||||
//co->setTransform(m);
|
||||
co->material() = LoaderDAE::materialByName(materials, matname);
|
||||
qDebug() << " tri" << co->material().name << matname;
|
||||
QVector<GLfloat> & vertices(co->VBO().vertices()), & normals(co->VBO().normals()), & uvs(co->VBO().texcoords());
|
||||
for (int k = 0; k < einp.count(); ++k) {
|
||||
QDomElement di = einp.at(k).toElement();
|
||||
QString src = di.attribute("source"), sem = di.attribute("semantic").toLower();
|
||||
int offset = di.attribute("offset").toInt();
|
||||
QVector<GLfloat> * curv = nullptr;
|
||||
int pccnt = 0;
|
||||
if (sem == "vertex") {curv = &vertices; pccnt = 3;}
|
||||
if (sem == "normal") {curv = &normals; pccnt = 3;}
|
||||
if (sem == "texcoord") {curv = &uvs; pccnt = 2;}
|
||||
if (curv == nullptr) continue;
|
||||
if (src.startsWith("#")) src.remove(0, 1);
|
||||
QVector<Vector3d> & data(source_data[source_names.value(src, src)]);
|
||||
for (int ii = offset; ii < p.size(); ii += pbv) {
|
||||
if ((p[ii] >= 0) && (p[ii] < data.size())) {
|
||||
Vector3d v = data[p[ii]];
|
||||
(*curv) << v.x << v.y;
|
||||
if (pccnt == 3) (*curv) << v.z;
|
||||
}
|
||||
}
|
||||
//qDebug() << " input" << sem << "from" << data.size() << "->" << (*curv) << pbv;
|
||||
}
|
||||
//qDebug() << "geom" << gid << co;
|
||||
ol << co;
|
||||
}
|
||||
objects[gid] = ol;
|
||||
}
|
||||
|
||||
elist = maine.firstChildElement("library_lights").elementsByTagName("light");
|
||||
for (int i = 0; i < elist.count(); ++i) {
|
||||
QDomElement dn = elist.at(i).toElement();
|
||||
QString name = dn.attributes().namedItem("name").nodeValue();
|
||||
QString gid = dn.attributes().namedItem("id").nodeValue();
|
||||
if (name.isEmpty() || name == "EnvironmentAmbientLight") continue;
|
||||
QDomElement dl = dn.firstChildElement("technique_common").firstChild().toElement();
|
||||
Light * lo = new Light();
|
||||
if (dl.nodeName() == "point") lo->light_type = Light::Omni;
|
||||
else if (dl.nodeName() == "spot") lo->light_type = Light::Cone;
|
||||
else {
|
||||
delete lo;
|
||||
continue;
|
||||
}
|
||||
lo->setColor(readXMLColor(dl));
|
||||
QDomNodeList ml = dn.elementsByTagName("multiplier");
|
||||
if (!ml.isEmpty()) lo->intensity = ml.at(0).firstChild().nodeValue().toFloat();
|
||||
ml = dn.elementsByTagName("intensity");
|
||||
if (!ml.isEmpty()) lo->intensity = ml.at(0).firstChild().nodeValue().toFloat();
|
||||
lo->setColor(lo->color() / lo->intensity);
|
||||
QString sv;
|
||||
sv = dl.firstChildElement("constant_attenuation").firstChild().nodeValue(); if (!sv.isEmpty()) lo->decay_const = sv.toFloat();
|
||||
sv = dl.firstChildElement("linear_attenuation").firstChild().nodeValue(); if (!sv.isEmpty()) lo->decay_linear = sv.toFloat();
|
||||
sv = dl.firstChildElement("quadratic_attenuation").firstChild().nodeValue(); if (!sv.isEmpty()) lo->decay_quadratic = sv.toFloat();
|
||||
///lo->setTransform(matrices.value(name));
|
||||
if (lo->light_type == Light::Cone) {
|
||||
ml = dn.elementsByTagName("decay_falloff"); if (!ml.isEmpty()) lo->angle_end = ml.at(0).firstChild().nodeValue().toFloat();
|
||||
ml = dn.elementsByTagName("hotspot_beam"); if (!ml.isEmpty()) lo->angle_start = ml.at(0).firstChild().nodeValue().toFloat();
|
||||
}
|
||||
QVector<GLObjectBase*> ol;
|
||||
ol << lo;
|
||||
objects[gid] = ol;
|
||||
//qDebug() << "light" << name;
|
||||
}
|
||||
//qDebug() << "readed" << objects.size();
|
||||
|
||||
QVector<QPair<QPair<QString, QString>, QMatrix4x4> > scene;
|
||||
readScene(mvse, QMatrix4x4(), scene);
|
||||
for (int i = 0; i < scene.size(); ++i) {
|
||||
QPair<QPair<QString, QString>, QMatrix4x4> so = scene[i];
|
||||
if (so.first.first.isEmpty()) continue;
|
||||
QVector<GLObjectBase * > ol = objects.value(so.first.first);
|
||||
foreach (GLObjectBase * o, ol) {
|
||||
o = o->clone();
|
||||
o->setName(so.first.second);
|
||||
o->setTransform(so.second);
|
||||
root->addChild(o);
|
||||
//qDebug() << " add" << so.first.second << o->name();
|
||||
}
|
||||
//qDebug() << "add" << so.first << ol.size();
|
||||
}
|
||||
|
||||
for (int i = 0; i < root->childCount(); ++i) {
|
||||
GLObjectBase * o = root->child(i);
|
||||
if (o->type() == GLObjectBase::glLight) {
|
||||
Light * l = (Light*)o;
|
||||
if (l->light_type == Light::Directional || l->light_type == Light::Cone) {
|
||||
QString tn = l->name() + ".Target";
|
||||
//qDebug() << "search target" << tn;
|
||||
for (int s = 0; s < scene.size(); ++s) {
|
||||
QPair<QPair<QString, QString>, QMatrix4x4> so = scene[s];
|
||||
if (so.first.second == tn) {
|
||||
//qDebug() << "found target" << tn;
|
||||
QVector3D tp = so.second.column(3).toVector3D();
|
||||
l->direction = (tp - l->pos()).normalized();
|
||||
//qDebug() << "dir" << l->direction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QVector<GLObjectBase * > > dol = objects.values();
|
||||
for (int i = 0; i < dol.size(); ++i)
|
||||
for (int j = 0; j < dol[i].size(); ++j)
|
||||
delete dol[i][j];
|
||||
|
||||
root->setScale(0.001f);
|
||||
qDebug() << "[Loader DAE] Loaded" << root->childCount() << "objects from" << filepath;
|
||||
return root;
|
||||
}
|
||||
35
test/qglview/loader_dae.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
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_DAE_H
|
||||
#define LOADER_DAE_H
|
||||
|
||||
#include "gltexture_manager.h"
|
||||
#include "globject.h"
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDomElement>
|
||||
|
||||
namespace LoaderDAE {
|
||||
Material materialByName(const QVector<Material> & materials, const QString & name);
|
||||
QVector<Material> readMaterials(QDomElement le, QDomElement li, bool fbx);
|
||||
}
|
||||
|
||||
GLObjectBase * loadFromDAEFile(const QString & filepath, float scale = 1.0);
|
||||
|
||||
#endif // LOADER_DAE_H
|
||||
270
test/qglview/loader_obj.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
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_obj.h"
|
||||
|
||||
|
||||
void LoaderOBJ::initOBJMesh(GLObjectBase * o, const QVector<Vector3d> & src_vertices, const QVector<Vector3d> & src_normals, const QVector<Vector3d> & src_texcoords) {
|
||||
QVector<GLfloat> & vertices(o->VBO().vertices()), & normals(o->VBO().normals()), & uvs(o->VBO().texcoords());
|
||||
QVector<Vector3i> & faces(o->faces), & uvws(o->uvws), & norms(o->norms);
|
||||
//Vector3d pos = Vector3d(o->pos());
|
||||
bool has_uv = !uvws.isEmpty();
|
||||
Vector3i cf, ct, cn;
|
||||
Vector3d v[3], t[3], n[3];
|
||||
//for (int i = 0; i < points.size(); ++i)
|
||||
// points[i] -= pos;
|
||||
int fcnt = faces.size() * 3;
|
||||
vertices.resize(fcnt * 3);
|
||||
normals.resize(vertices.size());
|
||||
if (has_uv) uvs.resize(fcnt * 2);
|
||||
int ind = 0, induv = 0;
|
||||
//qDebug() << "initOBJMesh" << faces.size();
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
cf = faces[i];
|
||||
ct = uvws[i];
|
||||
cn = norms[i];
|
||||
v[0] = src_vertices[cf.p0];
|
||||
v[1] = src_vertices[cf.p1];
|
||||
v[2] = src_vertices[cf.p2];
|
||||
n[0] = src_normals[cn.p0];
|
||||
n[1] = src_normals[cn.p1];
|
||||
n[2] = src_normals[cn.p2];
|
||||
vertices[ind] = v[0].x; normals[ind] = n[0].x; ++ind;
|
||||
vertices[ind] = v[0].y; normals[ind] = n[0].y; ++ind;
|
||||
vertices[ind] = v[0].z; normals[ind] = n[0].z; ++ind;
|
||||
vertices[ind] = v[1].x; normals[ind] = n[1].x; ++ind;
|
||||
vertices[ind] = v[1].y; normals[ind] = n[1].y; ++ind;
|
||||
vertices[ind] = v[1].z; normals[ind] = n[1].z; ++ind;
|
||||
vertices[ind] = v[2].x; normals[ind] = n[2].x; ++ind;
|
||||
vertices[ind] = v[2].y; normals[ind] = n[2].y; ++ind;
|
||||
vertices[ind] = v[2].z; normals[ind] = n[2].z; ++ind;
|
||||
if (has_uv) {
|
||||
if ((ct.p0 >= 0) && (ct.p1 >= 0) && (ct.p2 >= 0)) {
|
||||
t[0] = src_texcoords[ct.p0];
|
||||
t[1] = src_texcoords[ct.p1];
|
||||
t[2] = src_texcoords[ct.p2];
|
||||
uvs[induv] = t[0].x; ++induv;
|
||||
uvs[induv] = t[0].y; ++induv;
|
||||
uvs[induv] = t[1].x; ++induv;
|
||||
uvs[induv] = t[1].y; ++induv;
|
||||
uvs[induv] = t[2].x; ++induv;
|
||||
uvs[induv] = t[2].y; ++induv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector3d readVector3d(QString s) {
|
||||
Vector3d ret;
|
||||
QStringList sl(s.trimmed().split(" "));
|
||||
sl.removeAll(""); sl.removeAll(" ");
|
||||
if (sl.size() > 0) ret.x = sl[0].toFloat();
|
||||
if (sl.size() > 1) ret.y = sl[1].toFloat();
|
||||
if (sl.size() > 2) ret.z = sl[2].toFloat();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Vector2d readVector2d(QString s) {
|
||||
Vector2d ret;
|
||||
QStringList sl(s.trimmed().split(" "));
|
||||
sl.removeAll(""); sl.removeAll(" ");
|
||||
if (sl.size() > 0) ret.x = sl[0].toFloat();
|
||||
if (sl.size() > 1) ret.y = sl[1].toFloat();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QColor readColor(QString s) {
|
||||
Vector3d c = readVector3d(s);
|
||||
return QColor::fromRgbF(c.x, c.y, c.z);
|
||||
}
|
||||
|
||||
|
||||
void readFaces(QString s, GLObjectBase * co) {
|
||||
QStringList sl(s.trimmed().split(" "));
|
||||
sl.removeAll(""); sl.removeAll(" ");
|
||||
static Vector3i inds[4];
|
||||
for (int i = 0; i < sl.size(); ++i) {
|
||||
inds[i].p0 = inds[i].p1 = inds[i].p2 = 0;
|
||||
QStringList sl2(sl[i].split("/"));
|
||||
if (sl2.size() > 4) continue;
|
||||
inds[i].p0 = sl2[0].toInt();
|
||||
inds[i].p1 = sl2[1].toInt();
|
||||
inds[i].p2 = sl2[2].toInt();
|
||||
}
|
||||
if (sl.size() == 3) {
|
||||
co->faces << Vector3i(inds[0].p0 - 1, inds[1].p0 - 1, inds[2].p0 - 1);
|
||||
co->uvws << Vector3i(inds[0].p1 - 1, inds[1].p1 - 1, inds[2].p1 - 1);
|
||||
co->norms << Vector3i(inds[0].p2 - 1, inds[1].p2 - 1, inds[2].p2 - 1);
|
||||
}
|
||||
if (sl.size() == 4) {
|
||||
co->faces << Vector3i(inds[0].p0 - 1, inds[1].p0 - 1, inds[2].p0 - 1);
|
||||
co->uvws << Vector3i(inds[0].p1 - 1, inds[1].p1 - 1, inds[2].p1 - 1);
|
||||
co->norms << Vector3i(inds[0].p2 - 1, inds[1].p2 - 1, inds[2].p2 - 1);
|
||||
co->faces << Vector3i(inds[0].p0 - 1, inds[2].p0 - 1, inds[3].p0 - 1);
|
||||
co->uvws << Vector3i(inds[0].p1 - 1, inds[2].p1 - 1, inds[3].p1 - 1);
|
||||
co->norms << Vector3i(inds[0].p2 - 1, inds[2].p2 - 1, inds[3].p2 - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QVector<Material> readMTL(QString obj_path, QString path) {
|
||||
QVector<Material> ret;
|
||||
QStringList sp = GLTextureManagerBase::searchPathes();
|
||||
sp.prepend(QFileInfo(obj_path).absoluteDir().path());
|
||||
QFile f(findFile(path, sp));
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
qDebug() << "[Loader OBJ] Warning: can`t open \"" + path + "\"";
|
||||
return ret;
|
||||
}
|
||||
QTextStream stream(&f);
|
||||
QString name;
|
||||
Material mat;
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine().trimmed();
|
||||
if (line.startsWith("newmtl")) {
|
||||
if (!mat.name.isEmpty())
|
||||
ret << mat;
|
||||
mat = Material();
|
||||
mat.name = line.mid(6).trimmed();
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Kd")) {
|
||||
mat.color_diffuse = readColor(line.mid(2).trimmed());
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Ke")) {
|
||||
mat.color_self_illumination = readColor(line.mid(2).trimmed());
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Ks")) {
|
||||
Vector3d v = readVector3d(line.mid(2).trimmed());
|
||||
mat.map_specular.color_amount = v.length();
|
||||
float mc = qMax(v.x, qMax(v.y, v.z));
|
||||
if (mc > 0.f) v /= mc;
|
||||
mat.color_specular = QColor::fromRgbF(v.x, v.y, v.z);
|
||||
//qDebug() << mat.shine_strength << mat.color_specular;
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("Ns")) {
|
||||
mat.map_specularity.color_amount = 2.f / expf(line.mid(2).trimmed().toFloat());
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("d")) {
|
||||
mat.transparency = 1.f - line.mid(1).trimmed().toFloat();
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("map_Kd")) {
|
||||
mat.map_diffuse.bitmap_path = findFile(line.mid(6).trimmed(), sp);
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("map_bump")) {
|
||||
line = line.mid(8).trimmed();
|
||||
if (line.startsWith("-bm")) {
|
||||
line = line.mid(3).trimmed();
|
||||
QString sv = line.left(line.indexOf(" "));
|
||||
line = line.mid(sv.size()).trimmed();
|
||||
mat.map_normal.color_amount = sv.toFloat();
|
||||
}
|
||||
mat.map_normal.bitmap_path = findFile(line, sp);
|
||||
//qDebug() << "BUMP" << mat.name << mat.bump_scale << mat.bump.bitmap_path;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!mat.name.isEmpty())
|
||||
ret << mat;
|
||||
qDebug() << "load from MTL" << f.fileName() << ret.size() << "materials";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Material LoaderOBJ::materialByName(const QVector<Material> & materials, const QString & name) {
|
||||
foreach (const Material & m, materials)
|
||||
if (m.name == name)
|
||||
return m;
|
||||
return Material();
|
||||
}
|
||||
|
||||
|
||||
GLObjectBase * loadFromOBJFile(const QString & filepath, float scale) {
|
||||
QFile f(filepath);
|
||||
if (!f.exists()) {
|
||||
qDebug() << "[Loader OBJ] Error: can`t open \"" + filepath + "\"";
|
||||
return nullptr;
|
||||
}
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QTextStream stream(&f);
|
||||
QVector<Vector3d> vertices, normals, texcoords;
|
||||
QVector<Material> materials;
|
||||
GLObjectBase * root = new GLObjectBase(), * co = nullptr;
|
||||
QString name;
|
||||
root->setName(QFileInfo(f).baseName());
|
||||
int cnt = 0;
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine().trimmed();
|
||||
if (line.startsWith("mtllib")) {
|
||||
materials = readMTL(filepath, line.mid(6).trimmed());
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("v ")) {
|
||||
vertices << readVector3d(line.mid(1));
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("vt ")) {
|
||||
texcoords << readVector3d(line.mid(2));
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("vn ")) {
|
||||
normals << readVector3d(line.mid(2));
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("g ")) {
|
||||
name = line.mid(1).trimmed();
|
||||
if (co != nullptr) {
|
||||
LoaderOBJ::initOBJMesh(co, vertices, normals, texcoords);
|
||||
root->addChild(co);
|
||||
}
|
||||
co = new GLObjectBase();
|
||||
co->setName(name);
|
||||
//qDebug() << "new object" << co->name();
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("f ")) {
|
||||
readFaces(line.mid(2), co);
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("usemtl")) {
|
||||
if (!co->faces.isEmpty()) {
|
||||
LoaderOBJ::initOBJMesh(co, vertices, normals, texcoords);
|
||||
root->addChild(co);
|
||||
co = new GLObjectBase();
|
||||
co->setName(name + "_" + QString::number(cnt++));
|
||||
}
|
||||
co->material() = LoaderOBJ::materialByName(materials, line.mid(6).trimmed());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (co != nullptr) {
|
||||
LoaderOBJ::initOBJMesh(co, vertices, normals, texcoords);
|
||||
root->addChild(co);
|
||||
}
|
||||
qDebug() << "[Loader OBJ] Loaded" << root->childCount() << "objects from" << filepath;
|
||||
return root;
|
||||
}
|
||||
42
test/qglview/loader_obj.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
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_OBJ_H
|
||||
#define LOADER_OBJ_H
|
||||
|
||||
#include "gltexture_manager.h"
|
||||
#include "globject.h"
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace LoaderOBJ {
|
||||
#pragma pack(push, 1)
|
||||
struct Face {
|
||||
ushort v0;
|
||||
ushort v1;
|
||||
ushort v2;
|
||||
ushort flags;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
void initOBJMesh(GLObjectBase * o, const QVector<Vector3d> & vertices, const QVector<Vector3d> & normals, const QVector<Vector3d> & texcoords);
|
||||
Material materialByName(const QVector<Material> & materials, const QString & name);
|
||||
}
|
||||
|
||||
GLObjectBase * loadFromOBJFile(const QString & filepath, float scale = 1.0);
|
||||
|
||||
#endif // LOADER_3DS_H
|
||||
69
test/qglview/loader_qgl.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
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 "chunkstream.h"
|
||||
|
||||
|
||||
GLObjectBase * 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_4_8);
|
||||
char sign[4];
|
||||
s.readRawData(sign, 4);
|
||||
if ((sign[0] != 'Q') || (sign[1] != 'G') || (sign[2] != 'L') || (sign[3] != 'F')) {
|
||||
qDebug() << "[Loader QGL] Error: \"" + filepath + "\" is not valid QGL file!";
|
||||
return 0;
|
||||
}
|
||||
GLObjectBase * root = 0;
|
||||
ushort version = 0xFFFF;
|
||||
f.peek((char*)&version, 2);
|
||||
if (version == 1) {
|
||||
s.skipRawData(2);
|
||||
s >> root;
|
||||
} else {
|
||||
qDebug() << "[Loader QGL] Error: \"" + filepath + "\" unsupported version!";
|
||||
return 0;
|
||||
}
|
||||
root->buildTransform();
|
||||
if (root->name().isEmpty())
|
||||
root->setName(QFileInfo(f).baseName());
|
||||
qDebug() << "[Loader QGL] Loaded" << root->childCount() << "objects from" << filepath;
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
bool saveToQGLFile(const QString & filepath, const GLObjectBase * o) {
|
||||
QFile f(filepath);
|
||||
if (!f.open(QIODevice::ReadWrite))
|
||||
return false;
|
||||
f.resize(0);
|
||||
QDataStream s(&f);
|
||||
s.setVersion(QDataStream::Qt_4_8);
|
||||
char sign[4] = {'Q', 'G', 'L', 'F'};
|
||||
ushort version = 1;
|
||||
s.writeRawData(sign, 4);
|
||||
s.writeRawData((char*)&version, 2);
|
||||
s << o;
|
||||
return true;
|
||||
}
|
||||
31
test/qglview/loader_qgl.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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 "globject.h"
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace LoaderQGL {
|
||||
}
|
||||
|
||||
GLObjectBase * loadFromQGLFile(const QString & filepath);
|
||||
bool saveToQGLFile(const QString & filepath, const GLObjectBase * o);
|
||||
|
||||
#endif // LOADER_QGL_H
|
||||
206
test/qglview/material_editor.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
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 "material_editor.h"
|
||||
#include "ui_material_editor.h"
|
||||
|
||||
|
||||
MaterialEditor::MaterialEditor(QWidget * parent): QWidget(parent) {
|
||||
ui = new Ui::MaterialEditor();
|
||||
ui->setupUi(this);
|
||||
ui->frameReflection->hide();
|
||||
active = true;
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::changeEvent(QEvent * e) {
|
||||
return;
|
||||
QWidget::changeEvent(e);
|
||||
switch (e->type()) {
|
||||
case QEvent::LanguageChange:
|
||||
ui->retranslateUi(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::setMaterial(const Material & m) {
|
||||
active = false;
|
||||
ui->colorDiffuse->setColor(m.color_diffuse);
|
||||
ui->colorSpecular->setColor(m.color_specular);
|
||||
ui->colorSelfIllum->setColor(m.color_self_illumination);
|
||||
ui->checkGlass->setChecked(m.glass);
|
||||
ui->spinTransparent->setValue(m.transparency);
|
||||
ui->spinReflect->setValue(m.reflectivity);
|
||||
ui->spinIOF->setValue(m.iof);
|
||||
ui->spinDispersion->setValue(m.dispersion);
|
||||
ui->mapDiffuse->setMap(m.map_diffuse);
|
||||
ui->mapSpecular->setMap(m.map_specular);
|
||||
ui->mapSelfIllum->setMap(m.map_self_illumination);
|
||||
ui->mapSpecularity->setMap(m.map_specularity);
|
||||
ui->mapBump->setMap(m.map_normal);
|
||||
ui->mapRelief->setMap(m.map_relief);
|
||||
ui->lineReflFront->setProperty("GLpath", m.map_reflection.path(0)); ui->lineReflFront->setText(QFileInfo(m.map_reflection.path(0)).fileName());
|
||||
ui->lineReflBack->setProperty("GLpath", m.map_reflection.path(1)); ui->lineReflBack->setText(QFileInfo(m.map_reflection.path(1)).fileName());
|
||||
ui->lineReflLeft->setProperty("GLpath", m.map_reflection.path(2)); ui->lineReflLeft->setText(QFileInfo(m.map_reflection.path(2)).fileName());
|
||||
ui->lineReflRight->setProperty("GLpath", m.map_reflection.path(3)); ui->lineReflRight->setText(QFileInfo(m.map_reflection.path(3)).fileName());
|
||||
ui->lineReflTop->setProperty("GLpath", m.map_reflection.path(4)); ui->lineReflTop->setText(QFileInfo(m.map_reflection.path(4)).fileName());
|
||||
ui->lineReflBottom->setProperty("GLpath", m.map_reflection.path(5)); ui->lineReflBottom->setText(QFileInfo(m.map_reflection.path(5)).fileName());
|
||||
active = true;
|
||||
}
|
||||
|
||||
|
||||
Material MaterialEditor::material() {
|
||||
Material m;
|
||||
m.color_diffuse = ui->colorDiffuse->color();
|
||||
m.color_specular = ui->colorSpecular->color();
|
||||
m.color_self_illumination = ui->colorSelfIllum->color();
|
||||
m.glass = ui->checkGlass->isChecked();
|
||||
m.transparency = ui->spinTransparent->value();
|
||||
m.reflectivity = ui->spinReflect->value();
|
||||
m.iof = ui->spinIOF->value();
|
||||
m.dispersion = ui->spinDispersion->value();
|
||||
m.map_diffuse = ui->mapDiffuse->map();
|
||||
m.map_specular = ui->mapSpecular->map();
|
||||
m.map_self_illumination = ui->mapSelfIllum->map();
|
||||
m.map_specularity = ui->mapSpecularity->map();
|
||||
m.map_normal = ui->mapBump->map();
|
||||
m.map_relief = ui->mapRelief->map();
|
||||
m.map_reflection.setPath(0, ui->lineReflFront->property("GLpath").toString());
|
||||
m.map_reflection.setPath(1, ui->lineReflBack->property("GLpath").toString());
|
||||
m.map_reflection.setPath(2, ui->lineReflLeft->property("GLpath").toString());
|
||||
m.map_reflection.setPath(3, ui->lineReflRight->property("GLpath").toString());
|
||||
m.map_reflection.setPath(4, ui->lineReflTop->property("GLpath").toString());
|
||||
m.map_reflection.setPath(5, ui->lineReflBottom->property("GLpath").toString());
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflFrontSelect_clicked() {
|
||||
QString str = QFileDialog::getOpenFileName(this, "Select image", ui->lineReflFront->property("GLpath").toString(), "Images(*.bmp *.jpg *.jpeg *.png *.tif *.tiff *.tga);;All files(*)");
|
||||
if (str.isEmpty()) return;
|
||||
ui->lineReflFront->setProperty("GLpath", str);
|
||||
ui->lineReflFront->setText(QFileInfo(str).fileName());
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflBackSelect_clicked() {
|
||||
QString str = QFileDialog::getOpenFileName(this, "Select image", ui->lineReflBack->property("GLpath").toString(), "Images(*.bmp *.jpg *.jpeg *.png *.tif *.tiff *.tga);;All files(*)");
|
||||
if (str.isEmpty()) return;
|
||||
ui->lineReflBack->setProperty("GLpath", str);
|
||||
ui->lineReflBack->setText(QFileInfo(str).fileName());
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflLeftSelect_clicked() {
|
||||
QString str = QFileDialog::getOpenFileName(this, "Select image", ui->lineReflLeft->property("GLpath").toString(), "Images(*.bmp *.jpg *.jpeg *.png *.tif *.tiff *.tga);;All files(*)");
|
||||
if (str.isEmpty()) return;
|
||||
ui->lineReflLeft->setProperty("GLpath", str);
|
||||
ui->lineReflLeft->setText(QFileInfo(str).fileName());
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflRightSelect_clicked() {
|
||||
QString str = QFileDialog::getOpenFileName(this, "Select image", ui->lineReflRight->property("GLpath").toString(), "Images(*.bmp *.jpg *.jpeg *.png *.tif *.tiff *.tga);;All files(*)");
|
||||
if (str.isEmpty()) return;
|
||||
ui->lineReflRight->setProperty("GLpath", str);
|
||||
ui->lineReflRight->setText(QFileInfo(str).fileName());
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflTopSelect_clicked() {
|
||||
QString str = QFileDialog::getOpenFileName(this, "Select image", ui->lineReflTop->property("GLpath").toString(), "Images(*.bmp *.jpg *.jpeg *.png *.tif *.tiff *.tga);;All files(*)");
|
||||
if (str.isEmpty()) return;
|
||||
ui->lineReflTop->setProperty("GLpath", str);
|
||||
ui->lineReflTop->setText(QFileInfo(str).fileName());
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflBottomSelect_clicked() {
|
||||
QString str = QFileDialog::getOpenFileName(this, "Select image", ui->lineReflBottom->property("GLpath").toString(), "Images(*.bmp *.jpg *.jpeg *.png *.tif *.tiff *.tga);;All files(*)");
|
||||
if (str.isEmpty()) return;
|
||||
ui->lineReflBottom->setProperty("GLpath", str);
|
||||
ui->lineReflBottom->setText(QFileInfo(str).fileName());
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflFrontClear_clicked() {
|
||||
ui->lineReflFront->setText("");
|
||||
ui->lineReflFront->setProperty("GLpath", "");
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflBackClear_clicked() {
|
||||
ui->lineReflBack->setText("");
|
||||
ui->lineReflBack->setProperty("GLpath", "");
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflLeftClear_clicked() {
|
||||
ui->lineReflLeft->setText("");
|
||||
ui->lineReflLeft->setProperty("GLpath", "");
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflRightClear_clicked() {
|
||||
ui->lineReflRight->setText("");
|
||||
ui->lineReflRight->setProperty("GLpath", "");
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflTopClear_clicked() {
|
||||
ui->lineReflTop->setText("");
|
||||
ui->lineReflTop->setProperty("GLpath", "");
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonReflBottomClear_clicked() {
|
||||
ui->lineReflBottom->setText("");
|
||||
ui->lineReflBottom->setProperty("GLpath", "");
|
||||
materialChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialEditor::on_buttonLoadCubeDir_clicked() {
|
||||
QString dir = QFileDialog::getExistingDirectory(this, "Select directory", ui->lineReflFront->property("GLpath").toString());
|
||||
if (dir.isEmpty()) return;
|
||||
GLCubeTexture cb(0);
|
||||
cb.loadPathesFromDirectory(dir);
|
||||
active = false;
|
||||
ui->lineReflFront->setProperty("GLpath", cb.path(0)); ui->lineReflFront->setText(QFileInfo(cb.path(0)).fileName());
|
||||
ui->lineReflBack->setProperty("GLpath", cb.path(1)); ui->lineReflBack->setText(QFileInfo(cb.path(1)).fileName());
|
||||
ui->lineReflLeft->setProperty("GLpath", cb.path(2)); ui->lineReflLeft->setText(QFileInfo(cb.path(2)).fileName());
|
||||
ui->lineReflRight->setProperty("GLpath", cb.path(3)); ui->lineReflRight->setText(QFileInfo(cb.path(3)).fileName());
|
||||
ui->lineReflTop->setProperty("GLpath", cb.path(4)); ui->lineReflTop->setText(QFileInfo(cb.path(4)).fileName());
|
||||
ui->lineReflBottom->setProperty("GLpath", cb.path(5)); ui->lineReflBottom->setText(QFileInfo(cb.path(5)).fileName());
|
||||
active = true;
|
||||
materialChanged();
|
||||
}
|
||||
65
test/qglview/material_editor.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
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 MATERIAL_EDITOR_H
|
||||
#define MATERIAL_EDITOR_H
|
||||
|
||||
#include <QFileDialog>
|
||||
#include "glmaterial.h"
|
||||
|
||||
namespace Ui {
|
||||
class MaterialEditor;
|
||||
};
|
||||
|
||||
class MaterialEditor: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MaterialEditor(QWidget * parent = 0);
|
||||
|
||||
void setMaterial(const Material & m);
|
||||
Material material();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent * e);
|
||||
|
||||
bool active;
|
||||
Ui::MaterialEditor * ui;
|
||||
|
||||
private slots:
|
||||
void materialChanged() {if (active) emit changed();}
|
||||
void on_buttonReflFrontSelect_clicked();
|
||||
void on_buttonReflFrontClear_clicked();
|
||||
void on_buttonReflBackSelect_clicked();
|
||||
void on_buttonReflBackClear_clicked();
|
||||
void on_buttonReflLeftSelect_clicked();
|
||||
void on_buttonReflLeftClear_clicked();
|
||||
void on_buttonReflRightSelect_clicked();
|
||||
void on_buttonReflRightClear_clicked();
|
||||
void on_buttonReflTopSelect_clicked();
|
||||
void on_buttonReflTopClear_clicked();
|
||||
void on_buttonReflBottomSelect_clicked();
|
||||
void on_buttonReflBottomClear_clicked();
|
||||
void on_buttonLoadCubeDir_clicked();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
};
|
||||
|
||||
#endif // MATERIAL_EDITOR_H
|
||||
779
test/qglview/material_editor.ui
Normal file
@@ -0,0 +1,779 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MaterialEditor</class>
|
||||
<widget class="QWidget" name="MaterialEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>470</width>
|
||||
<height>791</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:bold;</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Diffuse</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="ColorButton" name="colorDiffuse">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
<property name="useAlphaChannel">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="MaterialMapEditor" name="mapDiffuse" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:bold;</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Specular</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="ColorButton" name="colorSpecular">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
<property name="useAlphaChannel">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="MaterialMapEditor" name="mapSpecular" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:bold;</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Self illumination</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="ColorButton" name="colorSelfIllum">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
<property name="useAlphaChannel">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="MaterialMapEditor" name="mapSelfIllum" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:bold;</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Specularity</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="MaterialMapEditor" name="mapSpecularity" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:bold;</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Normal</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="MaterialMapEditor" name="mapBump" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:bold;</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Relief</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="MaterialMapEditor" name="mapRelief" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font:normal;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="checkGlass">
|
||||
<property name="text">
|
||||
<string>Glass</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Transparency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="SpinSlider" name="spinTransparent">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Reflectivity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="SpinSlider" name="spinReflect">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>IOF</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="SpinSlider" name="spinIOF">
|
||||
<property name="maximum">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Dispersion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="SpinSlider" name="spinDispersion">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Reflection map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QFrame" name="frameReflection">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Front:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Back:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Left:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>Right:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>Top:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>Bottom:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineReflLeft"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflLeftClear">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflLeftSelect">
|
||||
<property name="text">
|
||||
<string>^</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineReflFront"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflFrontClear">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflFrontSelect">
|
||||
<property name="text">
|
||||
<string>^</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineReflBack"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflBackClear">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflBackSelect">
|
||||
<property name="text">
|
||||
<string>^</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineReflRight"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflRightClear">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflRightSelect">
|
||||
<property name="text">
|
||||
<string>^</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineReflTop"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflTopClear">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflTopSelect">
|
||||
<property name="text">
|
||||
<string>^</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineReflBottom"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflBottomClear">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonReflBottomSelect">
|
||||
<property name="text">
|
||||
<string>^</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="buttonLoadCubeDir">
|
||||
<property name="text">
|
||||
<string>load from directory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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>MaterialMapEditor</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>material_map_editor.h</header>
|
||||
<container>1</container>
|
||||
<slots>
|
||||
<signal>changed()</signal>
|
||||
</slots>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>colorDiffuse</sender>
|
||||
<signal>colorChanged(QColor)</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>326</x>
|
||||
<y>49</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>282</x>
|
||||
<y>17</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>colorSpecular</sender>
|
||||
<signal>colorChanged(QColor)</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>325</x>
|
||||
<y>128</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>284</x>
|
||||
<y>45</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinTransparent</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>443</x>
|
||||
<y>448</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>283</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinReflect</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>443</x>
|
||||
<y>470</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>284</x>
|
||||
<y>174</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinIOF</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>443</x>
|
||||
<y>492</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>284</x>
|
||||
<y>236</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>checkGlass</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>443</x>
|
||||
<y>382</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>284</x>
|
||||
<y>84</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>colorSelfIllum</sender>
|
||||
<signal>colorChanged(QColor)</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>376</x>
|
||||
<y>202</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>326</x>
|
||||
<y>63</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>spinDispersion</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>460</x>
|
||||
<y>514</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>326</x>
|
||||
<y>288</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mapDiffuse</sender>
|
||||
<signal>changed()</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>445</x>
|
||||
<y>63</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>469</x>
|
||||
<y>63</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mapSpecular</sender>
|
||||
<signal>changed()</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>443</x>
|
||||
<y>143</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>467</x>
|
||||
<y>143</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mapSelfIllum</sender>
|
||||
<signal>changed()</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>447</x>
|
||||
<y>216</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>468</x>
|
||||
<y>216</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mapBump</sender>
|
||||
<signal>changed()</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>450</x>
|
||||
<y>308</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>469</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mapRelief</sender>
|
||||
<signal>changed()</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>450</x>
|
||||
<y>353</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>469</x>
|
||||
<y>304</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mapSpecularity</sender>
|
||||
<signal>changed()</signal>
|
||||
<receiver>MaterialEditor</receiver>
|
||||
<slot>materialChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>442</x>
|
||||
<y>257</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>474</x>
|
||||
<y>250</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>materialChanged()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
88
test/qglview/material_map_editor.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
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 "material_map_editor.h"
|
||||
#include "ui_material_map_editor.h"
|
||||
|
||||
|
||||
MaterialMapEditor::MaterialMapEditor(QWidget * parent): QWidget(parent) {
|
||||
ui = new Ui::MaterialMapEditor();
|
||||
ui->setupUi(this);
|
||||
active = true;
|
||||
}
|
||||
|
||||
|
||||
void MaterialMapEditor::changeEvent(QEvent * e) {
|
||||
return;
|
||||
QWidget::changeEvent(e);
|
||||
switch (e->type()) {
|
||||
case QEvent::LanguageChange:
|
||||
ui->retranslateUi(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MaterialMapEditor::resizeEvent(QResizeEvent * e) {
|
||||
ui->iconedLabel->setFixedWidth(ui->iconedLabel->height());
|
||||
ui->iconedLabel->setIconSize(ui->iconedLabel->size());
|
||||
}
|
||||
|
||||
|
||||
void MaterialMapEditor::updateIcon() {
|
||||
ui->iconedLabel->setIcon(QIcon(ui->linePath->property("GLpath").toString()));
|
||||
}
|
||||
|
||||
|
||||
void MaterialMapEditor::setMap(const Map & m) {
|
||||
active = false;
|
||||
ui->sliderAmount->setValue(m.color_amount);
|
||||
ui->sliderOffset->setValue(m.color_offset);
|
||||
ui->linePath->setProperty("GLpath", m.bitmap_path); ui->linePath->setText(QFileInfo(m.bitmap_path).fileName());
|
||||
updateIcon();
|
||||
active = true;
|
||||
}
|
||||
|
||||
|
||||
Map MaterialMapEditor::map() {
|
||||
Map m;
|
||||
m.color_amount = ui->sliderAmount->value();
|
||||
m.color_offset = ui->sliderOffset->value();
|
||||
m.bitmap_path = ui->linePath->property("GLpath").toString();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
void MaterialMapEditor::on_buttonSelect_clicked() {
|
||||
QString str = QFileDialog::getOpenFileName(this, "Select image", ui->linePath->property("GLpath").toString(), "Images(*.bmp *.jpg *.jpeg *.png *.tif *.tiff *.tga);;All files(*)");
|
||||
if (str.isEmpty()) return;
|
||||
ui->linePath->setProperty("GLpath", str);
|
||||
ui->linePath->setText(QFileInfo(str).fileName());
|
||||
updateIcon();
|
||||
mapChanged();
|
||||
}
|
||||
|
||||
|
||||
void MaterialMapEditor::on_buttonClear_clicked() {
|
||||
ui->linePath->setText("");
|
||||
ui->linePath->setProperty("GLpath", "");
|
||||
updateIcon();
|
||||
mapChanged();
|
||||
}
|
||||
56
test/qglview/material_map_editor.h
Normal 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 MATERIAL_MAP_EDITOR_H
|
||||
#define MATERIAL_MAP_EDITOR_H
|
||||
|
||||
#include <QFileDialog>
|
||||
#include "glmaterial.h"
|
||||
|
||||
namespace Ui {
|
||||
class MaterialMapEditor;
|
||||
};
|
||||
|
||||
class MaterialMapEditor: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MaterialMapEditor(QWidget * parent = 0);
|
||||
|
||||
void setMap(const Map & m);
|
||||
Map map();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent * e);
|
||||
void resizeEvent(QResizeEvent * e);
|
||||
void updateIcon();
|
||||
|
||||
bool active;
|
||||
Ui::MaterialMapEditor * ui;
|
||||
|
||||
private slots:
|
||||
void mapChanged() {if (active) emit changed();}
|
||||
void on_buttonSelect_clicked();
|
||||
void on_buttonClear_clicked();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
};
|
||||
|
||||
#endif // MATERIAL_MAP_EDITOR_H
|
||||
178
test/qglview/material_map_editor.ui
Normal file
@@ -0,0 +1,178 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MaterialMapEditor</class>
|
||||
<widget class="QWidget" name="MaterialMapEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>509</width>
|
||||
<height>74</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="IconedLabel" name="iconedLabel">
|
||||
<property name="direction">
|
||||
<enum>IconedLabel::RightToLeft</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="linePath"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonClear">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonSelect">
|
||||
<property name="text">
|
||||
<string>^</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Amount:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="SpinSlider" name="sliderAmount">
|
||||
<property name="minimum">
|
||||
<double>-10.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<double>0.200000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Offset:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="SpinSlider" name="sliderOffset">
|
||||
<property name="minimum">
|
||||
<double>-10.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<double>0.200000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SpinSlider</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>spinslider.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>IconedLabel</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>iconedlabel.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>linePath</sender>
|
||||
<signal>textChanged(QString)</signal>
|
||||
<receiver>MaterialMapEditor</receiver>
|
||||
<slot>mapChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>175</x>
|
||||
<y>19</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>99</x>
|
||||
<y>73</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>sliderAmount</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>MaterialMapEditor</receiver>
|
||||
<slot>mapChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>440</x>
|
||||
<y>38</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>512</x>
|
||||
<y>37</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>sliderOffset</sender>
|
||||
<signal>valueChanged(double)</signal>
|
||||
<receiver>MaterialMapEditor</receiver>
|
||||
<slot>mapChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>497</x>
|
||||
<y>66</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>511</x>
|
||||
<y>65</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>mapChanged()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
95
test/qglview/openglwindow.cpp
Normal 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(2, 0);
|
||||
format.setProfile(QSurfaceFormat::NoProfile);
|
||||
}
|
||||
#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
test/qglview/openglwindow.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <QWindow>
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
class QPainter;
|
||||
class QOpenGLContext;
|
||||
class QOpenGLPaintDevice;
|
||||
|
||||
|
||||
class OpenGLWindow : public QWindow, protected QOpenGLFunctions
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
12
test/qglview/plugin/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
project(qglview_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} qglview)
|
||||
qt_install(TARGETS ${PROJECT_NAME} DESTINATION QtPlugins/designer)
|
||||
14
test/qglview/plugin/qglview_designerplugin.cpp
Normal 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;
|
||||
}
|
||||
|
||||
22
test/qglview/plugin/qglview_designerplugin.h
Normal 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
|
||||
95
test/qglview/plugin/qglviewplugin.cpp
Normal 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");
|
||||
}
|
||||
|
||||
33
test/qglview/plugin/qglviewplugin.h
Normal 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
|
||||
408
test/qglview/propertyeditor.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
#include "propertyeditor.h"
|
||||
|
||||
|
||||
QWidget * Delegate::widgetForProperty(QWidget * parent, const QModelIndex & index) const {
|
||||
QWidget * w = 0;
|
||||
int type = 0;
|
||||
QVariant value = index.data(Qt::UserRole);
|
||||
if (index.data(Qt::UserRole + 2).toString() == "__flags") return 0;
|
||||
if (index.data(Qt::UserRole + 1).toString() == "__flag") {
|
||||
qulonglong key = index.data(Qt::UserRole).toULongLong();
|
||||
value = index.parent().data(Qt::UserRole);
|
||||
//QMetaProperty prop = index.parent().data(Qt::UserRole + 1).value<QMetaProperty>();
|
||||
w = new QCheckBox(parent); type = 14; ((QCheckBox*)w)->setChecked(((value.toULongLong() & key) == key && key != 0) || (value.toULongLong() == 0 && key == 0));
|
||||
((QCheckBox*)w)->setText("0x" + QString::number(key, 16).toUpper());
|
||||
connect((QCheckBox*)w, SIGNAL(clicked(bool)), this, SLOT(changedFlag()));
|
||||
//qDebug() << prop.enumerator().name();
|
||||
} else {
|
||||
if (value.canConvert<PropertyValuePair>()) {
|
||||
PropertyValuePair prop = value.value<PropertyValuePair>();
|
||||
if (prop.first.isEnumType()) {
|
||||
w = new QComboBox(parent); type = 13; ((QComboBox*)w)->setCurrentIndex(value.toInt());
|
||||
w->setProperty("__prop", QVariant::fromValue<QMetaProperty>(prop.first));
|
||||
QMetaEnum menum = prop.first.enumerator();
|
||||
for (int i = 0; i < menum.keyCount(); ++i) {
|
||||
((QComboBox*)w)->addItem(QString(menum.key(i)) + " (0x" + QString::number(menum.value(i), 16).toUpper() + ")", menum.value(i));
|
||||
if (menum.value(i) == prop.second.toInt())
|
||||
((QComboBox*)w)->setCurrentIndex(i);
|
||||
}
|
||||
connect((QComboBox*)w, SIGNAL(currentIndexChanged(int)), this, SLOT(changed()));
|
||||
}
|
||||
} else {
|
||||
switch (value.type()) {
|
||||
case QVariant::Int: w = new QSpinBox(parent); type = 2; ((QSpinBox*)w)->setRange(-0x7FFFFFFF, 0x7FFFFFFF); connect((QSpinBox*)w, SIGNAL(valueChanged(int)), this, SLOT(changed())); break;
|
||||
case QVariant::UInt: w = new QSpinBox(parent); type = 3; ((QSpinBox*)w)->setRange(0, 0xFFFFFFFF); connect((QSpinBox*)w, SIGNAL(valueChanged(int)), this, SLOT(changed())); break;
|
||||
case QVariant::LongLong: w = new QSpinBox(parent); type = 4; ((QSpinBox*)w)->setRange(-0x7FFFFFFF, 0x7FFFFFFF); connect((QSpinBox*)w, SIGNAL(valueChanged(int)), this, SLOT(changed())); break;
|
||||
case QVariant::ULongLong: w = new QSpinBox(parent); type = 5; ((QSpinBox*)w)->setRange(0, 0xFFFFFFFF); connect((QSpinBox*)w, SIGNAL(valueChanged(int)), this, SLOT(changed())); break;
|
||||
case QVariant::Double: w = new QDoubleSpinBox(parent); type = 6; ((QDoubleSpinBox*)w)->setRange(-999999999, 999999999); ((QDoubleSpinBox*)w)->setDecimals(3); connect((QDoubleSpinBox*)w, SIGNAL(valueChanged(double)), this, SLOT(changed())); break;
|
||||
case QVariant::Bool: w = new QCheckBox(parent); type = 7; ((QCheckBox*)w)->setChecked(value.toBool()); connect((QCheckBox*)w, SIGNAL(toggled(bool)), this, SLOT(changed())); break;
|
||||
case QVariant::Color: w = new ColorButton(parent); type = 8; ((ColorButton*)w)->setUseAlphaChannel(true); ((ColorButton*)w)->setColor(value.value<QColor>()); connect((ColorButton*)w, SIGNAL(colorChanged(QColor)), this, SLOT(changed())); break;
|
||||
case QVariant::Point: w = new QPointEdit(parent); type = 9; ((QPointEdit*)w)->setDecimals(0); ((QPointEdit*)w)->setValue(QPointF(value.toPoint())); connect((QPointEdit*)w, SIGNAL(valueChanged(QPointF)), this, SLOT(changed())); break;
|
||||
case QVariant::PointF: w = new QPointEdit(parent); type = 10; ((QPointEdit*)w)->setDecimals(3); ((QPointEdit*)w)->setValue(value.toPointF()); connect((QPointEdit*)w, SIGNAL(valueChanged(QPointF)), this, SLOT(changed())); break;
|
||||
case QVariant::Rect: w = new QRectEdit(parent); type = 11; ((QRectEdit*)w)->setDecimals(0); ((QRectEdit*)w)->setValue(QRectF(value.toRect())); connect((QRectEdit*)w, SIGNAL(valueChanged(QRectF)), this, SLOT(changed())); break;
|
||||
case QVariant::RectF: w = new QRectEdit(parent); type = 12; ((QRectEdit*)w)->setDecimals(3); ((QRectEdit*)w)->setValue(value.toRectF()); connect((QRectEdit*)w, SIGNAL(valueChanged(QRectF)), this, SLOT(changed())); break;
|
||||
case QVariant::String: default: w = new CLineEdit(parent); type = 1; ((CLineEdit*)w)->setDefaultText(value.toString()); connect((CLineEdit*)w, SIGNAL(textChanged(QString)), this, SLOT(changed())); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (w == 0) return 0;
|
||||
/*QPalette pal = w->palette();
|
||||
pal.setColor(QPalette::Window, Qt::white);
|
||||
w->setPalette(pal);*/
|
||||
w->setAutoFillBackground(true);
|
||||
w->setProperty("__type", type);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
void Delegate::setWidgetProperty(QWidget * w, const QVariant & value) const {
|
||||
if (w == 0) return;
|
||||
switch (w->property("__type").toInt()) {
|
||||
case 1: ((CLineEdit*)w)->setText(value.toString()); break;
|
||||
case 2: case 3: case 4: case 5: ((QSpinBox*)w)->setValue(value.toInt()); break;
|
||||
case 6: ((QDoubleSpinBox*)w)->setValue(value.toDouble()); break;
|
||||
case 7: ((QCheckBox*)w)->setChecked(value.toBool()); break;
|
||||
case 8: ((ColorButton*)w)->setColor(value.value<QColor>()); break;
|
||||
case 9: ((QPointEdit*)w)->setValue(value.value<QPoint>()); break;
|
||||
case 10: ((QPointEdit*)w)->setValue(value.value<QPointF>()); break;
|
||||
case 11: ((QRectEdit*)w)->setValue(value.value<QRect>()); break;
|
||||
case 12: ((QRectEdit*)w)->setValue(value.value<QRectF>()); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const QVariant Delegate::widgetProperty(QWidget * w) const {
|
||||
if (w == 0) return QVariant();
|
||||
switch (w->property("__type").toInt()) {
|
||||
case 1: return QVariant::fromValue<QString>(((CLineEdit*)w)->text()); break;
|
||||
case 2: return QVariant::fromValue<int>(((QSpinBox*)w)->value()); break;
|
||||
case 3: return QVariant::fromValue<uint>(((QSpinBox*)w)->value()); break;
|
||||
case 4: return QVariant::fromValue<qlonglong>(((QSpinBox*)w)->value()); break;
|
||||
case 5: return QVariant::fromValue<qulonglong>(((QSpinBox*)w)->value()); break;
|
||||
case 6: return QVariant::fromValue<double>(((QDoubleSpinBox*)w)->value()); break;
|
||||
case 7: return QVariant::fromValue<bool>(((QCheckBox*)w)->isChecked()); break;
|
||||
case 8: return QVariant::fromValue<QColor>(((ColorButton*)w)->color()); break;
|
||||
case 9: return QVariant::fromValue<QPoint>(((QPointEdit*)w)->value().toPoint()); break;
|
||||
case 10: return QVariant::fromValue<QPointF>(((QPointEdit*)w)->value()); break;
|
||||
case 11: return QVariant::fromValue<QRect>(((QRectEdit*)w)->value().toRect()); break;
|
||||
case 12: return QVariant::fromValue<QRectF>(((QRectEdit*)w)->value()); break;
|
||||
case 13: return QVariant::fromValue<PropertyValuePair>(PropertyValuePair(w->property("__prop").value<QMetaProperty>(), ((QComboBox*)w)->itemData(((QComboBox*)w)->currentIndex()))); break;
|
||||
default: return QVariant(); break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
void Delegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const {
|
||||
if (index.data(Qt::UserRole + 1).toString() != "__flag")
|
||||
model->setData(index, widgetProperty(editor), Qt::UserRole);
|
||||
}
|
||||
|
||||
|
||||
void Delegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const {
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
QVariant value = index.data(Qt::UserRole);
|
||||
QStyle * style = QApplication::style();
|
||||
QStyleOption * so = 0;
|
||||
QStyleOptionComplex * soc = 0;
|
||||
QString text;
|
||||
QRect rect;
|
||||
QPalette::ColorRole role = (option.state.testFlag(QStyle::State_Selected) && option.state.testFlag(QStyle::State_Active) ? QPalette::HighlightedText : QPalette::WindowText);
|
||||
if (index.data(Qt::UserRole + 2).toString() == "__flags") {
|
||||
text = "0x" + QString::number(value.toInt(), 16).toUpper();
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
return;
|
||||
}
|
||||
if (index.data(Qt::UserRole + 1) == "__flag") {
|
||||
qulonglong key = index.data(Qt::UserRole).toULongLong();
|
||||
value = index.parent().data(Qt::UserRole);
|
||||
so = new QStyleOptionButton();
|
||||
so->rect = option.rect;
|
||||
so->palette = option.palette;
|
||||
so->fontMetrics = option.fontMetrics;
|
||||
((QStyleOptionButton*)so)->state = (((value.toULongLong() & key) == key && key != 0) || (value.toULongLong() == 0 && key == 0) ? QStyle::State_On : QStyle::State_Off) | option.state;
|
||||
((QStyleOptionButton*)so)->text = "0x" + QString::number(key, 16).toUpper();
|
||||
if (option.state.testFlag(QStyle::State_Selected))
|
||||
so->palette.setColor(QPalette::WindowText, so->palette.color(QPalette::HighlightedText));
|
||||
style->drawControl(QStyle::CE_CheckBox, so, painter);
|
||||
} else {
|
||||
if (value.canConvert<PropertyValuePair>()) {
|
||||
PropertyValuePair prop = value.value<PropertyValuePair>();
|
||||
if (prop.first.isEnumType()) {
|
||||
QMetaEnum menum = prop.first.enumerator();
|
||||
for (int i = 0; i < menum.keyCount(); ++i) {
|
||||
if (menum.value(i) == prop.second.toInt()) {
|
||||
text = QString(menum.key(i)) + " (0x" + QString::number(menum.value(i), 16).toUpper() + ")";
|
||||
break;
|
||||
}
|
||||
}
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
}
|
||||
} else {
|
||||
switch (value.type()) {
|
||||
case QVariant::Int:
|
||||
text.setNum(value.toInt());
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::UInt:
|
||||
text.setNum(value.toUInt());
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::LongLong:
|
||||
text.setNum(value.toLongLong());
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::ULongLong:
|
||||
text.setNum(value.toULongLong());
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::Double:
|
||||
text.setNum(value.toDouble(), 'f', 3);
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::Bool:
|
||||
so = new QStyleOptionButton();
|
||||
so->rect = option.rect;
|
||||
so->state = option.state;
|
||||
so->palette = option.palette;
|
||||
so->fontMetrics = option.fontMetrics;
|
||||
((QStyleOptionButton*)so)->state = (value.toBool() ? QStyle::State_On : QStyle::State_Off) | option.state;
|
||||
style->drawControl(QStyle::CE_CheckBox, so, painter);
|
||||
break;
|
||||
case QVariant::Color:
|
||||
rect = option.rect;//style->subElementRect(QStyle::QStyle::SE_FrameContents, so);
|
||||
rect.setRect(rect.x() + 3, rect.y() + 3, rect.width() - 6, rect.height() - 6);
|
||||
painter->fillRect(rect, ab);
|
||||
painter->fillRect(rect, value.value<QColor>());
|
||||
break;
|
||||
case QVariant::Point:
|
||||
text = pointString(value.toPoint());
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::PointF:
|
||||
text = pointString(value.toPointF());
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::Rect:
|
||||
text = rectString(value.toRect());
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::RectF:
|
||||
text = rectString(value.toRectF());
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role);
|
||||
break;
|
||||
case QVariant::String: default:
|
||||
style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, value.toString()),
|
||||
Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, value.toString(), role);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*so = new QStyleOptionFrame();
|
||||
so->rect = option.rect;
|
||||
so->state = option.state;
|
||||
so->palette = option.palette;
|
||||
so->fontMetrics = option.fontMetrics;
|
||||
((QStyleOptionFrame*)so)->state = (value.toBool() ? QStyle::State_On : QStyle::State_Off);
|
||||
style->drawPrimitive(QStyle::PE_PanelLineEdit, so, painter);
|
||||
style->drawPrimitive(QStyle::PE_FrameLineEdit, so, painter);
|
||||
break;*/
|
||||
if (so != 0) delete so;
|
||||
if (soc != 0) delete soc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Delegate::changedFlag() {
|
||||
QAbstractItemModel * model = const_cast<QAbstractItemModel * >(cmi.model());
|
||||
model->setData(cmi, qobject_cast<QCheckBox * >(sender())->isChecked(), Qt::UserRole + 3);
|
||||
QModelIndex p = cmi.parent(), mi;
|
||||
int row = 0;
|
||||
qulonglong val = 0;
|
||||
QList<QModelIndex> chldr;
|
||||
mi = p.child(row, 1);
|
||||
while (mi.isValid()) {
|
||||
chldr << mi;
|
||||
model->setData(mi, !mi.data(Qt::UserRole + 4).toBool(), Qt::UserRole + 4);
|
||||
mi = p.child(++row, 1);
|
||||
}
|
||||
bool cc = cmi.data(Qt::UserRole + 3).toBool();
|
||||
qulonglong cv = cmi.data(Qt::UserRole).toULongLong();
|
||||
//qDebug() << "*****";
|
||||
if (cc && cv == 0) {
|
||||
val = 0;
|
||||
//qDebug() << "null" << cv;
|
||||
} else {
|
||||
if (!cc && cv != 0) {
|
||||
//qDebug() << "uncheck" << cv;
|
||||
for (int i = 0; i < chldr.size(); ++i) {
|
||||
if (chldr[i] == cmi) continue;
|
||||
//qDebug() << (chldr[i].data(Qt::UserRole).toULongLong() & cv);
|
||||
if (chldr[i].data(Qt::UserRole).toULongLong() & cv)
|
||||
model->setData(chldr[i], false, Qt::UserRole + 3);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < chldr.size(); ++i) {
|
||||
//qDebug() << chldr[i].data(Qt::UserRole + 3).toBool();
|
||||
if (chldr[i].data(Qt::UserRole + 3).toBool())
|
||||
val |= chldr[i].data(Qt::UserRole).toULongLong();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < chldr.size(); ++i) {
|
||||
if (chldr[i] == cmi) continue;
|
||||
cv = chldr[i].data(Qt::UserRole).toULongLong();
|
||||
model->setData(chldr[i], ((val & cv) == cv && cv != 0) || (val == 0 && cv == 0), Qt::UserRole + 3);
|
||||
}
|
||||
//qDebug() << val;
|
||||
model->setData(p, val, Qt::UserRole);
|
||||
model->setData(p.sibling(p.row(), 1), val, Qt::UserRole);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PropertyEditor::PropertyEditor(QWidget * parent): QTreeWidget(parent) {
|
||||
object = 0;
|
||||
active_ = false;
|
||||
configTree();
|
||||
connect(this, SIGNAL(itemClicked(QTreeWidgetItem * , int)), this, SLOT(itemClicked(QTreeWidgetItem * , int)));
|
||||
connect(this, SIGNAL(itemChanged(QTreeWidgetItem * , int)), this, SLOT(itemChanged(QTreeWidgetItem * , int)));
|
||||
}
|
||||
|
||||
|
||||
PropertyEditor::~PropertyEditor() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PropertyEditor::changeEvent(QEvent * e) {
|
||||
QTreeWidget::changeEvent(e);
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
configTree();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PropertyEditor::configTree() {
|
||||
setColumnCount(2);
|
||||
setRootIsDecorated(false);
|
||||
setColumnWidth(0, 170);
|
||||
setColumnWidth(1, 10);
|
||||
header()->setStretchLastSection(true);
|
||||
QStringList lbls;
|
||||
lbls << tr("Property") << tr("Value");
|
||||
setHeaderLabels(lbls);
|
||||
setAlternatingRowColors(true);
|
||||
setItemDelegateForColumn(1, new Delegate());
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PropertyEditor::itemClicked(QTreeWidgetItem * item, int column) {
|
||||
if (column == 0)
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
|
||||
else {
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
|
||||
editItem(item, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PropertyEditor::itemChanged(QTreeWidgetItem * item, int column) {
|
||||
if (!active_) return;
|
||||
if (column != 1) return;
|
||||
QVariant value = item->data(1, Qt::UserRole);
|
||||
if (value.canConvert<PropertyValuePair>()) {
|
||||
value = value.value<PropertyValuePair>().second;
|
||||
}
|
||||
object->setProperty(item->text(0).toLatin1(), value);
|
||||
}
|
||||
|
||||
|
||||
void PropertyEditor::rebuild() {
|
||||
clear();
|
||||
configTree();
|
||||
if (object == 0) return;
|
||||
active_ = false;
|
||||
const QMetaObject * mo = object->metaObject();
|
||||
QList<const QMetaObject * > mol;
|
||||
while (mo != 0) {
|
||||
mol.push_front(mo);
|
||||
mo = mo->superClass();
|
||||
}
|
||||
int ps, pe;
|
||||
QTreeWidgetItem * ti, * tli, * tfi;
|
||||
QVariant value;
|
||||
// QWidget * pw = 0;
|
||||
int chue = 0;
|
||||
QColor bc;
|
||||
font_b = font();
|
||||
font_b.setBold(true);
|
||||
foreach (const QMetaObject * o, mol) {
|
||||
ps = o->propertyOffset();
|
||||
pe = o->propertyCount();// - ps;
|
||||
//qDebug() << i->className() << ps << pe;
|
||||
tli = new QTreeWidgetItem();
|
||||
tli->setText(0, o->className());
|
||||
tli->setFont(0, font_b);
|
||||
setItemBackColor(tli, Qt::darkGray);
|
||||
setItemForeColor(tli, Qt::white);
|
||||
addTopLevelItem(tli);
|
||||
setFirstItemColumnSpanned(tli, true);
|
||||
tli->setExpanded(true);
|
||||
for (int i = ps; i < pe; ++i) {
|
||||
props << o->property(i);
|
||||
value = o->property(i).read(object);
|
||||
ti = new QTreeWidgetItem();
|
||||
ti->setSizeHint(1, QSize(20, 20));
|
||||
bc.setHsv(chue, 60, 245 + (i % 2) * 20 - 10);
|
||||
setItemBackColor(ti, bc);
|
||||
ti->setText(0, o->property(i).name());
|
||||
if (props.back().isFlagType()) {
|
||||
QMetaEnum menum = props.back().enumerator();
|
||||
for (int j = 0; j < menum.keyCount(); ++j) {
|
||||
tfi = new QTreeWidgetItem();
|
||||
tfi->setText(0, menum.key(j));
|
||||
tfi->setData(1, Qt::UserRole, menum.value(j));
|
||||
tfi->setData(1, Qt::UserRole + 1, "__flag");
|
||||
tfi->setData(1, Qt::UserRole + 2, value.toULongLong());
|
||||
tfi->setData(1, Qt::UserRole + 3, (value.toULongLong() & menum.value(j)) > 0);
|
||||
tfi->setSizeHint(1, QSize(20, 20));
|
||||
bc.setHsv(chue, 60, 245 + ((i + j + 1) % 2) * 20 - 10);
|
||||
setItemBackColor(tfi, bc);
|
||||
ti->addChild(tfi);
|
||||
}
|
||||
ti->setData(0, Qt::UserRole, value);
|
||||
ti->setData(1, Qt::UserRole, value);
|
||||
ti->setData(1, Qt::UserRole + 2, "__flags");
|
||||
ti->setData(0, Qt::UserRole + 1, QVariant::fromValue<QMetaProperty>(props.back()));
|
||||
}
|
||||
else if (props.back().isEnumType())
|
||||
value.setValue<PropertyValuePair>(PropertyValuePair(props.back(), value));
|
||||
//ti->setText(1, value.toString());
|
||||
ti->setData(1, Qt::UserRole, value);
|
||||
tli->addChild(ti);
|
||||
//const_cast<QModelIndex & >(indexFromItem(ti, 1)).;
|
||||
//if (pw != 0) setItemWidget(ti, 1, pw);
|
||||
}
|
||||
chue += 60;
|
||||
chue %= 360;
|
||||
}
|
||||
active_ = true;
|
||||
}
|
||||
|
||||
|
||||
void PropertyEditor::refresh() {
|
||||
|
||||
}
|
||||
77
test/qglview/propertyeditor.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef PROPERTYEDITOR_H
|
||||
#define PROPERTYEDITOR_H
|
||||
|
||||
#include <QTreeWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QMetaProperty>
|
||||
#include <QEvent>
|
||||
#include <QDebug>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <qpiconfigwidget.h>
|
||||
|
||||
|
||||
class Delegate: public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Delegate(QObject * parent = 0): QStyledItemDelegate() {ab = QBrush(QImage(":/icons/alpha.png"));}
|
||||
|
||||
QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const {cmi = const_cast<QModelIndex & >(index); return widgetForProperty(parent, index);}
|
||||
void setEditorData(QWidget * editor, const QModelIndex & index) const {setWidgetProperty(editor, index.data(Qt::UserRole));}
|
||||
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
|
||||
void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const {editor->setGeometry(option.rect);}
|
||||
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
|
||||
|
||||
private:
|
||||
QWidget * widgetForProperty(QWidget * parent, const QModelIndex & index) const;
|
||||
void setWidgetProperty(QWidget * w, const QVariant & value) const;
|
||||
const QVariant widgetProperty(QWidget * w) const;
|
||||
QString pointString(const QPoint & p) const {return QString::number(p.x()) + " x " + QString::number(p.y());}
|
||||
QString pointString(const QPointF & p) const {return QString::number(p.x()) + " x " + QString::number(p.y());}
|
||||
QString rectString(const QRect & r) const {return QString::number(r.x()) + " x " + QString::number(r.y()) + " : " +
|
||||
QString::number(r.width()) + " x " + QString::number(r.height());}
|
||||
QString rectString(const QRectF & r) const {return QString::number(r.x()) + " x " + QString::number(r.y()) + " : " +
|
||||
QString::number(r.width()) + " x " + QString::number(r.height());}
|
||||
|
||||
QBrush ab;
|
||||
mutable QModelIndex cmi;
|
||||
|
||||
private slots:
|
||||
void changed() {setModelData((QWidget * )sender(), const_cast<QAbstractItemModel * >(cmi.model()), cmi);}
|
||||
void changedFlag();
|
||||
|
||||
};
|
||||
|
||||
typedef QPair<QMetaProperty, QVariant> PropertyValuePair;
|
||||
Q_DECLARE_METATYPE (PropertyValuePair)
|
||||
Q_DECLARE_METATYPE (QMetaProperty)
|
||||
|
||||
class PropertyEditor: public QTreeWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PropertyEditor(QWidget * parent = 0);
|
||||
virtual ~PropertyEditor();
|
||||
|
||||
void assignObject(QObject * o) {object = o; rebuild();}
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent * e);
|
||||
|
||||
private:
|
||||
void configTree();
|
||||
void setItemBackColor(QTreeWidgetItem * i, const QColor & c) {i->setBackgroundColor(0, c); i->setBackgroundColor(1, c);}
|
||||
void setItemForeColor(QTreeWidgetItem * i, const QColor & c) {i->setForeground(0, c); i->setForeground(1, c);}
|
||||
void rebuild();
|
||||
void refresh();
|
||||
|
||||
QObject * object;
|
||||
QFont font_b;
|
||||
QList<QMetaProperty> props;
|
||||
bool active_;
|
||||
|
||||
private slots:
|
||||
void itemClicked(QTreeWidgetItem * item, int column);
|
||||
void itemChanged(QTreeWidgetItem * item, int column);
|
||||
|
||||
};
|
||||
|
||||
#endif // PROPERTYEDITOR_H
|
||||
770
test/qglview/qglview.cpp
Normal file
@@ -0,0 +1,770 @@
|
||||
/*
|
||||
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 <QApplication>
|
||||
#include <QKeyEvent>
|
||||
|
||||
|
||||
QGLView::QGLView(): OpenGLWindow(), fbo_selection(3) {
|
||||
// setFrameShape(QFrame::NoFrame);
|
||||
// setViewportUpdateMode(FullViewportUpdate);
|
||||
// setCacheMode(CacheNone);
|
||||
// setMouseTracking(true);
|
||||
// setFocusPolicy(Qt::WheelFocus);
|
||||
// setScene(new QGraphicsScene());
|
||||
// setInteractive(true);
|
||||
setIcon(QIcon("://icons/qglview.png"));
|
||||
timer = 0;
|
||||
need_init_ = is_first_draw = true;
|
||||
objects_.is_root = true;
|
||||
objects_.view_ = this;
|
||||
backColor_ = Qt::darkGray;
|
||||
hoverHaloColor_ = QColor(195, 140, 255, 96);
|
||||
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_ = true;
|
||||
shaders_supported = selecting_ = customMouseMove_ = false;
|
||||
sel_button = Qt::LeftButton;
|
||||
sel_mod = Qt::NoModifier;
|
||||
renderer_ = nullptr;
|
||||
fps_cnt = 0;
|
||||
fps_tm = fps_ = 0.;
|
||||
sel_obj = hov_obj = nullptr;
|
||||
fogDensity_ = fogEnd_ = 1.;
|
||||
fogStart_ = 0.;
|
||||
fogMode_ = Exp;
|
||||
hoverHaloFill_ = 0.333f;
|
||||
selectionHaloFill_ = 0.5f;
|
||||
//lmode = Simple;
|
||||
shader_select = shader_halo = nullptr;
|
||||
setFeature(qglMSAA, false);
|
||||
setFeature(qglFXAA, false);
|
||||
setFeature(qglLinearFiltering, true);
|
||||
setFeature(qglAnisotropicLevel, 8);
|
||||
setFeature(qglHDR, false);
|
||||
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 = GLObjectBase::Fill;
|
||||
sel_mode = QGLView::SingleSelection;
|
||||
// sel_pen = QPen(Qt::black, 1, Qt::DashLine);
|
||||
// sel_brush = QBrush(QColor(170, 100, 255, 120));
|
||||
camera()->setAim(QVector3D());
|
||||
camera()->setPos(QVector3D(2, 2, 2));
|
||||
camera()->setName("Camera");
|
||||
addObject(camera());
|
||||
emit cameraPosChanged(camera()->pos());
|
||||
//camera().aim_ = camera().pos_;
|
||||
ktm_.restart();
|
||||
}
|
||||
|
||||
|
||||
QGLView::~QGLView() {
|
||||
stop();
|
||||
if (shader_select) delete shader_select;
|
||||
if (shader_halo) delete shader_halo;
|
||||
}
|
||||
|
||||
|
||||
void QGLView::stop() {
|
||||
if (timer) killTimer(timer);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::start(float freq) {
|
||||
timer = startTimer(freq <= 0.f ? 0 : int(1000.f / freq));
|
||||
}
|
||||
|
||||
|
||||
GLRendererBase * QGLView::renderer() {
|
||||
return renderer_;
|
||||
}
|
||||
|
||||
|
||||
void QGLView::setRenderer(GLRendererBase * r, GLRendererBase ** prev) {
|
||||
if (prev != nullptr) *prev = renderer_;
|
||||
renderer_ = r;
|
||||
}
|
||||
|
||||
|
||||
void QGLView::addObject(GLObjectBase * o) {
|
||||
objects_.addChild(o);
|
||||
o->setView(this);
|
||||
collectLights();
|
||||
QList<GLObjectBase*> cl = o->children(true);
|
||||
cl << o;
|
||||
foreach (GLObjectBase * i, cl) {
|
||||
emit objectAdded(i);
|
||||
}
|
||||
if (is_init) {
|
||||
o->init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int QGLView::objectsCount(bool all) {
|
||||
if (!all) return objects_.childCount();
|
||||
int cnt = 0;
|
||||
objectsCountInternal(&cnt, &objects_);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
void QGLView::removeObject(GLObjectBase * o, bool inChildren) {
|
||||
o->setView(nullptr);
|
||||
if (inChildren)
|
||||
removeObjectInternal(o, &objects_);
|
||||
else
|
||||
objects_.removeChild(o);
|
||||
objectDeleted(o);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::removeObject(GLObjectBase & o, bool inChildren) {
|
||||
removeObject(&o, inChildren);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::clearObjects(bool deleteAll) {
|
||||
removeObject(camera_);
|
||||
objects_.clearChildren(deleteAll);
|
||||
addObject(camera());
|
||||
selectObject(nullptr);
|
||||
hov_obj = nullptr;
|
||||
}
|
||||
|
||||
|
||||
QList<GLObjectBase *> QGLView::objects(bool all) {
|
||||
return objects_.children(all);
|
||||
}
|
||||
|
||||
|
||||
int QGLView::lightsCount() const {
|
||||
return lights_.size();
|
||||
}
|
||||
|
||||
|
||||
void QGLView::removeLight(int index) {
|
||||
removeObject(lights_.at(index));
|
||||
lights_.removeAt(index);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::removeLight(Light * l) {
|
||||
foreach (Light * i, lights_)
|
||||
if (i == l) removeObject(i);
|
||||
lights_.removeAll(l);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::clearLights(bool deleteAll) {
|
||||
if (deleteAll)
|
||||
foreach (Light * i, lights_) delete i;
|
||||
lights_.clear();
|
||||
}
|
||||
|
||||
|
||||
void QGLView::addTexture(const QString & path) {
|
||||
textures_manager->addTexture(path);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::addAnimation(const QString & dir, const QString & name) {
|
||||
textures_manager->addAnimation(dir, name);
|
||||
}
|
||||
|
||||
|
||||
Light * QGLView::light(int index) {
|
||||
return lights_[index];
|
||||
}
|
||||
|
||||
|
||||
Light * QGLView::light(const QString & name) {
|
||||
foreach (Light * i, lights_)
|
||||
if (i->name_ == name) return i;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void QGLView::selectObject(GLObjectBase * o) {
|
||||
if (o == sel_obj) return;
|
||||
GLObjectBase * pso = sel_obj;
|
||||
sel_obj = o;
|
||||
emit selectionChanged(sel_obj, pso);
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
QRect g_rect(QPoint(), size());
|
||||
emit glBeforePaint();
|
||||
//qDebug() << "paintGL";
|
||||
//QMutexLocker ml_v(&v_mutex);
|
||||
glEnable(GL_CULL_FACE);
|
||||
//glDisable(GL_CULL_FACE);
|
||||
camera()->apply(aspect);
|
||||
//objects_.preparePos(camera());
|
||||
start_rp.cam_offset_matrix = camera()->offsetMatrix();
|
||||
start_rp.proj_matrix = getGLMatrix(GL_PROJECTION_MATRIX);
|
||||
start_rp.view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX);
|
||||
//objects_.buildTransform();
|
||||
|
||||
/// Selection detect
|
||||
//glClearFramebuffer(QColor(100, 0, 0, 0));
|
||||
if (mouseSelect_) {
|
||||
glReleaseTextures();
|
||||
glEnableDepth();
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_TEXTURE_CUBE_MAP);
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_RESCALE_NORMAL);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
fbo_selection.bind();
|
||||
fbo_selection.setWriteBuffer(0);
|
||||
glClearFramebuffer(QColor(0, 0, 0, 0));
|
||||
if (shaders_supported && shader_select->isLinked()) shader_select->bind();
|
||||
renderSelection();
|
||||
if (shaders_supported && shader_select->isLinked()) shader_select->release();
|
||||
uchar cgid[4] = {0, 0, 0, 0};
|
||||
uint iid = 0;
|
||||
GLObjectBase * so = nullptr;
|
||||
if (!g_rect.contains(lastPos)) {
|
||||
if (hov_obj != nullptr) {
|
||||
hov_obj = nullptr;
|
||||
emit hoverChanged(nullptr, hov_obj);
|
||||
}
|
||||
} else {
|
||||
glReadPixels(lastPos.x(), height() - lastPos.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, cgid);
|
||||
iid = uint(cgid[0] << 24) | uint(cgid[1] << 16) | uint(cgid[2] << 8) | cgid[3];
|
||||
so = ids.value(iid, nullptr);
|
||||
//qDebug() <<cgid[0]<<cgid[1]<<cgid[2]<<cgid[3]<< iid;
|
||||
if (so != hov_obj) {
|
||||
emit hoverChanged(so, hov_obj);
|
||||
hov_obj = so;
|
||||
}
|
||||
//if (so != 0) qDebug() << sel_obj->name() << cgid[3];
|
||||
}
|
||||
if (selectionHalo_ && sel_obj) {
|
||||
fbo_selection.setWriteBuffer(2);
|
||||
renderHalo(sel_obj, qHash((quint64)sel_obj), selectionHaloColor_, selectionHaloFill_);
|
||||
}
|
||||
if (hoverHalo_ && hov_obj) {
|
||||
fbo_selection.setWriteBuffer(1);
|
||||
renderHalo(hov_obj, iid, hoverHaloColor_, hoverHaloFill_);
|
||||
}
|
||||
fbo_selection.release();
|
||||
glEnableDepth();
|
||||
/*glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);*/
|
||||
}
|
||||
|
||||
camera()->apply(aspect);
|
||||
start_rp.cam_offset_matrix = camera()->offsetMatrix();
|
||||
cur_mvpm = start_rp.proj_matrix * start_rp.view_matrix * start_rp.cam_offset_matrix;
|
||||
//objects_.preparePos(camera());
|
||||
|
||||
static GLRendererBase * prev_rend = nullptr;
|
||||
glShadeModel(GL_SMOOTH);
|
||||
if (prev_rend != renderer_) {
|
||||
prev_rend = renderer_;
|
||||
if (renderer_ != nullptr) {
|
||||
renderer_->init(width(), height());
|
||||
renderer_->resize(width(), height());
|
||||
renderer_->reloadShaders();
|
||||
}
|
||||
}
|
||||
emit glBeginPaint();
|
||||
if (renderer_ != nullptr) {
|
||||
renderer_->rp.prepare();
|
||||
renderer_->prepareScene();
|
||||
renderer_->renderScene();
|
||||
}
|
||||
emit glPainting();
|
||||
if (selectionHalo_ || hoverHalo_) {
|
||||
glReleaseTextures();
|
||||
glUseProgram(0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_CUBE_MAP);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisableDepth();
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
if (selectionHalo_ && sel_obj) {
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_selection.colorTexture(2));
|
||||
//qDebug() << "draw sel";
|
||||
glDrawQuad();
|
||||
}
|
||||
if (hoverHalo_ && hov_obj) {
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_selection.colorTexture(1));
|
||||
//qDebug() << "draw hover";
|
||||
glDrawQuad();
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
glResetAllTransforms();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
emit glEndPaint();
|
||||
|
||||
/*releaseShaders();
|
||||
glActiveTextureChannel(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColor4f(0.3, 0.5, 0.8, 0.5);
|
||||
glResetAllTransforms();
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.f, 0.f); glVertex2f(-1.f, -1.f);
|
||||
glTexCoord2f(1.f, 0.f); glVertex2f(1.f, -1.);
|
||||
glTexCoord2f(1.f, 1.f); glVertex2f(1.f, 1.f);
|
||||
glTexCoord2f(0.f, 1.f); glVertex2f(-1.f, 1.f);
|
||||
glEnd();*/
|
||||
/*
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glDisable(GL_LIGHTING);
|
||||
glActiveTextureChannel(0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo->texture());
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(1.f, 1.f, 1.f);
|
||||
glTexCoord2f(0.f, 0.f); glVertex2f(-1.f, -1.f);
|
||||
glTexCoord2f(0.f, 1.f); glVertex2f(-1.f, 1.f);
|
||||
glTexCoord2f(1.f, 1.f); glVertex2f(1.f, 1.f);
|
||||
glTexCoord2f(1.f, 0.f); glVertex2f(1.f, -1.);
|
||||
glEnd();
|
||||
glEnable(GL_DEPTH_TEST);*/
|
||||
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() {
|
||||
//initializeOpenGLFunctions();
|
||||
glEnable(GL_TEXTURE_MAX_ANISOTROPY_EXT);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glEnableDepth();
|
||||
glEnable(GL_CULL_FACE);
|
||||
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
|
||||
glActiveTexture(GL_TEXTURE0 + 3);
|
||||
glEnable(GL_TEXTURE_GEN_S);
|
||||
glEnable(GL_TEXTURE_GEN_T);
|
||||
glEnable(GL_TEXTURE_GEN_R);
|
||||
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
||||
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
||||
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
||||
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);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glCullFace(GL_BACK);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glColorMaterial(GL_FRONT, GL_DIFFUSE);
|
||||
|
||||
textures_manager->loadTextures();
|
||||
objects_.initInternal();
|
||||
checkCaps();
|
||||
|
||||
shader_select = new QOpenGLShaderProgram(context());
|
||||
shader_halo = new QOpenGLShaderProgram(context());
|
||||
reloadThisShaders();
|
||||
is_init = true;
|
||||
//resizeGL(width(), height());
|
||||
need_init_ = false;
|
||||
emit glInitializeDone();
|
||||
}
|
||||
|
||||
|
||||
void QGLView::renderHalo(const GLObjectBase * obj, const uint iid, const QColor & color, const float & fill) {
|
||||
if (!shaders_supported) return;
|
||||
if (!shader_halo) return;
|
||||
if (!shader_halo->isLinked()) return;
|
||||
if (obj) {
|
||||
shader_halo->bind();
|
||||
shader_halo->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_selection.colorTexture());
|
||||
shader_halo->setUniformValue("t0", 0);
|
||||
shader_halo->setUniformValue("dt", QVector2D(1.f / width(), 1.f / height()));
|
||||
shader_halo->setUniformValue("selected", QVector4D(float((iid >> 24) & 0xFF) / 255.f,
|
||||
float((iid >> 16) & 0xFF) / 255.f,
|
||||
float((iid >> 8) & 0xFF) / 255.f,
|
||||
float(iid & 0xFF) / 255.f));
|
||||
shader_halo->setUniformValue("color", color);
|
||||
shader_halo->setUniformValue("fill", GLfloat(fill));
|
||||
//qDebug() << "render halo" << iid << shader_halo->log() << shader_halo->programId();
|
||||
glDisableDepth();
|
||||
glDrawQuad(shader_halo);
|
||||
glDepthMask(GL_TRUE);
|
||||
//glFlush();
|
||||
shader_halo->release();
|
||||
} else {
|
||||
glClearFramebuffer(Qt::black, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QGLView::renderSelection() {
|
||||
// cid = 1;
|
||||
ids.clear();
|
||||
if (shaders_supported) {
|
||||
if (shader_select) {
|
||||
if (shader_select->isLinked()) {
|
||||
sh_id_loc = shader_select->uniformLocation("id");
|
||||
shader_select->setUniformValue("z_far", GLfloat(depthEnd()));
|
||||
shader_select->setUniformValue("z_near", GLfloat(depthStart()));
|
||||
}
|
||||
}
|
||||
}
|
||||
//qDebug() << sh_id_loc;
|
||||
start_rp.view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX);
|
||||
glPushMatrix();
|
||||
renderSingleSelection(objects_);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void QGLView::renderSingleSelection(GLObjectBase & o) {
|
||||
if (!o.isInit()) {
|
||||
o.init();
|
||||
o.loadTextures();
|
||||
}
|
||||
if (!o.visible_ || !o.select_) return;
|
||||
QMatrix4x4 curview = start_rp.view_matrix * start_rp.cam_offset_matrix * o.itransform_;
|
||||
uint id = qHash((quint64)&o);
|
||||
ids.insert(id, &o);
|
||||
glLineWidth(o.line_width > 0.f ? o.line_width : lineWidth_);
|
||||
glPointSize(o.line_width > 0.f ? o.line_width : lineWidth_);
|
||||
if (shaders_supported){
|
||||
if (shader_select) {
|
||||
if (shader_select->isLinked()) {
|
||||
setUniformMatrices(shader_select, start_rp.proj_matrix, curview);
|
||||
shader_select->setUniformValue(sh_id_loc, QVector4D(float((id >> 24) & 0xFF) / 255.f,
|
||||
float((id >> 16) & 0xFF) / 255.f,
|
||||
float((id >> 8) & 0xFF) / 255.f,
|
||||
float(id & 0xFF) / 255.f));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setGLMatrix(curview);
|
||||
glColor4f(float((id >> 24) & 0xFF) / 255.f,
|
||||
float((id >> 16) & 0xFF) / 255.f,
|
||||
float((id >> 8) & 0xFF) / 255.f,
|
||||
float(id & 0xFF) / 255.f);
|
||||
}
|
||||
//qDebug() << o.name() << "assign to" << sh_id_loc << cid;
|
||||
//glColor4f(float((cid >> 24) & 0xFF) / 255.f, float((cid >> 16) & 0xFF) / 255.f, float((cid >> 8) & 0xFF) / 255.f, float(cid & 0xFF) / 255.f);
|
||||
// ++cid;
|
||||
o.draw(nullptr, true);
|
||||
foreach (GLObjectBase * i, o.children_)
|
||||
renderSingleSelection(*i);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::collectLights() {
|
||||
lights_.clear();
|
||||
collectObjectLights(&objects_);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::objectDeleted(GLObjectBase * o) {
|
||||
//qDebug() << "del" << o;
|
||||
if (sel_obj == o) selectObject(nullptr);
|
||||
if (hov_obj == o) hov_obj = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void QGLView::collectObjectLights(GLObjectBase * o) {
|
||||
if (o->type_ == GLObjectBase::glLight) {
|
||||
lights_ << globject_cast<Light * >(o);
|
||||
o->view_ = this;
|
||||
}
|
||||
foreach (GLObjectBase * i, o->children())
|
||||
collectObjectLights(i);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::objectsCountInternal(int * cnt, GLObjectBase * where) {
|
||||
++(*cnt);
|
||||
foreach (GLObjectBase * i, where->children_)
|
||||
objectsCountInternal(cnt, i);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::removeObjectInternal(GLObjectBase * o, GLObjectBase * where) {
|
||||
foreach (GLObjectBase * i, where->children_) {
|
||||
if (o == i)
|
||||
where->removeChild(i);
|
||||
else
|
||||
removeObjectInternal(o, i);
|
||||
objectDeleted(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QGLView::checkCaps() {
|
||||
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropic);
|
||||
//glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_chanels);
|
||||
//qDebug() << max_texture_chanels;
|
||||
//qDebug() << max_texture_chanels;
|
||||
shaders_supported = QOpenGLShaderProgram::hasOpenGLShaderPrograms();
|
||||
}
|
||||
|
||||
|
||||
void QGLView::reloadThisShaders() {
|
||||
if (!shaders_supported) return;
|
||||
loadShaders(shader_select, "selection", "://shaders");
|
||||
loadShaders(shader_halo, "selection_halo", "://shaders");
|
||||
//loadShaders(shader_rope, "rope", "://shaders");
|
||||
}
|
||||
|
||||
void QGLView::glReleaseTextures(int channels) {
|
||||
for (int i = channels - 1; i >= 0; --i) {
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QGLView::applyFog() {
|
||||
GLfloat fog_col[4] = {float(fogColor_.redF()), float(fogColor_.greenF()), float(fogColor_.blueF()), .0f};
|
||||
if (fogEnabled_) {
|
||||
glEnable(GL_FOG);
|
||||
glFogf(GL_FOG_DENSITY, fogDensity_);
|
||||
glFogf(GL_FOG_START, fogStart_);
|
||||
glFogf(GL_FOG_END, fogEnd_);
|
||||
glFogi(GL_FOG_MODE, fogMode_);
|
||||
fog_col[0] = fogColor_.redF();
|
||||
fog_col[1] = fogColor_.greenF();
|
||||
fog_col[2] = fogColor_.blueF();
|
||||
glFogfv(GL_FOG_COLOR, fog_col);
|
||||
} else glDisable(GL_FOG);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
if (renderer_) renderer_->resize(width, height);
|
||||
mouse_first = true;
|
||||
//qDebug() << "resize" << width << height;
|
||||
fbo_selection.resize(width, height);
|
||||
iaspect = (aspect == 0.f) ? 0. : 1 / aspect;
|
||||
glViewport(0, 0, width, height);
|
||||
emit glResize(width, height);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::mouseReleaseEvent(QMouseEvent * e) {
|
||||
// qDebug() << "mouseReleaseEvent" << e << isActive();
|
||||
// QGraphicsView::mouseReleaseEvent(e);
|
||||
//setCursor(QCursor(Qt::ArrowCursor));
|
||||
selecting_ = false;
|
||||
if (mouseSelect_ && e->button() == Qt::LeftButton) {
|
||||
if ((lastPos - downPos).manhattanLength() < 8) {
|
||||
if (sel_obj != hov_obj)
|
||||
selectObject(hov_obj);
|
||||
}
|
||||
}
|
||||
emit glMouseReleaseEvent(e);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::mousePressEvent(QMouseEvent * e) {
|
||||
// qDebug() << "mousePressEvent" << e << isActive();
|
||||
// QGraphicsView::mousePressEvent(e);
|
||||
// mouseThis_ = (scene()->itemAt(mapToScene(e->pos()) , QTransform() ) == 0);
|
||||
selecting_ = false;
|
||||
if (!QRect(QPoint(), size()).contains(e->pos())) return;
|
||||
/// TODO select by rect
|
||||
//if (e->button() == sel_button && e->modifiers() == sel_mod)
|
||||
// selecting_ = true;
|
||||
lastPos = e->pos();
|
||||
downPos = lastPos;
|
||||
//qDebug() << mouseThis_;
|
||||
emit glMousePressEvent(e);
|
||||
}
|
||||
|
||||
|
||||
void QGLView::mouseMoveEvent(QMouseEvent * e) {
|
||||
// qDebug() << "mouseMoveEvent" << e << isActive();
|
||||
// QGraphicsView::mouseMoveEvent(e);
|
||||
//lastPos = e->pos();
|
||||
if (selecting_) {
|
||||
return;
|
||||
}
|
||||
// if (!QRect(QPoint(), size()).contains(e->pos())) return;
|
||||
//if (scene()->itemAt(mapToScene(e->pos())) != 0) return;
|
||||
///qDebug() << e->x() << e->y();
|
||||
QRect g_rect(QPoint(), size());
|
||||
if (mouseRotate_) {
|
||||
float dx = e->x() - lastPos.x();
|
||||
float dy = e->y() - lastPos.y();
|
||||
if (e->buttons() & Qt::LeftButton) {
|
||||
//camera().angle_z += dx / 4.;
|
||||
//camera().angle_xy += dy / 4.;
|
||||
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() & Qt::RightButton) {
|
||||
float ad = camera()->distance();
|
||||
camera()->moveLeft(dx / 1000.f * ad);
|
||||
camera()->moveUp(dy / 1000.f * ad);
|
||||
//camera().pos.setX(camera().pos.x() + camera().pos.z() * dx / 500.);
|
||||
//camera().pos.setY(camera().pos.y() - camera().pos.z() * dy / 500.);
|
||||
emit cameraPosChanged(camera()->pos());
|
||||
}
|
||||
//lights[0]->pos_ = camera().pos();
|
||||
}
|
||||
if (customMouseMove_) emit customMouseMoveEvent(e->pos(), lastPos, e->buttons());
|
||||
lastPos = e->pos();
|
||||
if (grabMouse_) {
|
||||
//if (!isrunning) return;
|
||||
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;
|
||||
//qDebug() << "first" << e->pos();
|
||||
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); //camera().pos.setZ(camera().pos.z() - 0.1 * camera().pos.z());
|
||||
if (e->delta() < 0) camera()->flyFarer(0.1f); //camera().pos.setZ(camera().pos.z() + 0.1 * camera().pos.z());
|
||||
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();
|
||||
}
|
||||
296
test/qglview/qglview.h
Normal 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/>.
|
||||
*/
|
||||
|
||||
#ifndef QGLVIEW_H
|
||||
#define QGLVIEW_H
|
||||
|
||||
#include "openglwindow.h"
|
||||
#include "glframebuffer.h"
|
||||
#include "glprimitives.h"
|
||||
#include "glparticles_system.h"
|
||||
#include "glrendererbase.h"
|
||||
#include <QTime>
|
||||
|
||||
|
||||
class QGLView: public OpenGLWindow, public QGLViewBase
|
||||
{
|
||||
friend class GLRendererBase;
|
||||
friend class GLObjectBase;
|
||||
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 (float fogDensity READ fogDensity WRITE setFogDensity)
|
||||
Q_PROPERTY (float fogStart READ fogStart WRITE setFogStart)
|
||||
Q_PROPERTY (float fogEnd READ fogEnd WRITE setFogEnd)
|
||||
Q_PROPERTY (FogMode fogMode READ fogMode WRITE setFogMode)
|
||||
Q_PROPERTY (bool fogEnabled READ isFogEnabled WRITE setFogEnabled)
|
||||
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 (SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
|
||||
|
||||
public:
|
||||
QGLView();
|
||||
virtual ~QGLView();
|
||||
|
||||
enum FogMode {Linear = GL_LINEAR, Exp = GL_EXP, Exp2 = GL_EXP2};
|
||||
enum SelectionMode {NoSelection, SingleSelection, MultiSelection};
|
||||
enum Feature {
|
||||
qglMSAA,
|
||||
qglFXAA,
|
||||
qglLinearFiltering,
|
||||
qglAnisotropicLevel,
|
||||
qglHDR,
|
||||
qglEyeAccomodationEnabled,
|
||||
qglEyeAccomodationTime,
|
||||
qglEyeAccomodationMaxSpeed,
|
||||
qglBloomEnabled,
|
||||
qglBloomThreshold,
|
||||
qglBloomFactor,
|
||||
qglBloomRadius,
|
||||
qglMotionBlurEnabled,
|
||||
qglMotionBlurFactor,
|
||||
qglMotionBlurSteps,
|
||||
qglShadowsEnabled,
|
||||
qglShadowsMapSize,
|
||||
qglShadowsSoftEnabled,
|
||||
qglReflectionsEnabled,
|
||||
qglReflectionsBlur,
|
||||
qglSSAOEnabled,
|
||||
qglSSAORadius,
|
||||
qglDepthOfFieldEnabled,
|
||||
qglDepthOfFieldAutoFocusEnabled,
|
||||
qglDepthOfFieldAutoFocusSpeed,
|
||||
qglDepthOfFieldFocus,
|
||||
qglDepthOfFieldDiaphragm
|
||||
};
|
||||
|
||||
Q_ENUMS (FogMode)
|
||||
Q_ENUMS (SelectionMode)
|
||||
|
||||
void stop();
|
||||
void start(float freq = 60.);
|
||||
|
||||
GLRendererBase * renderer();
|
||||
void setRenderer(GLRendererBase * r, GLRendererBase ** prev = nullptr);
|
||||
|
||||
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_;}
|
||||
FogMode fogMode() const {return fogMode_;}
|
||||
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 = (GLObjectBase::RenderMode)mode;}
|
||||
|
||||
void addObject(GLObjectBase * o);
|
||||
// void addObject(GLObjectBase & o) {addObject(&o);}
|
||||
int objectsCount(bool all = false);
|
||||
void removeObject(GLObjectBase * o, bool inChildren = true);
|
||||
void removeObject(GLObjectBase & o, bool inChildren = true);
|
||||
void clearObjects(bool deleteAll = false);
|
||||
QList<GLObjectBase * > objects(bool all = false);
|
||||
|
||||
int lightsCount() const;
|
||||
void removeLight(int index);
|
||||
void removeLight(Light * l);
|
||||
void clearLights(bool deleteAll = false);
|
||||
QList<Light * > lights() {return lights_;}
|
||||
|
||||
void addTexture(const QString & path);
|
||||
void addAnimation(const QString & dir, const QString & name);
|
||||
|
||||
const GLObjectBase & rootObject() {return objects_;}
|
||||
GLObjectBase * object(int index) {return objects_.child(index);}
|
||||
GLObjectBase * object(const QString & name) {return objects_.child(name);}
|
||||
Light * light(int index);
|
||||
Light * light(const QString & name);
|
||||
|
||||
SelectionMode selectionMode() const {return sel_mode;}
|
||||
Qt::MouseButton selectionButton() const {return sel_button;}
|
||||
Qt::KeyboardModifier selectionModifier() const {return sel_mod;}
|
||||
|
||||
void setSelectionMode(SelectionMode v) {sel_mode = v;}
|
||||
void setSelectionButton(Qt::MouseButton v) {sel_button = v;}
|
||||
void setSelectionModifier(Qt::KeyboardModifier v) {sel_mod = v;}
|
||||
void selectObject(GLObjectBase * o);
|
||||
GLObjectBase * selectedObject() const {return sel_obj;}
|
||||
|
||||
void glReleaseTextures(int channels = 8);
|
||||
|
||||
GLfloat aspect, iaspect;
|
||||
QMatrix4x4 cur_mvpm;
|
||||
|
||||
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 applyFog();
|
||||
void renderSelection();
|
||||
|
||||
void checkCaps();
|
||||
void collectLights();
|
||||
|
||||
private:
|
||||
void objectDeleted(GLObjectBase * o);
|
||||
void collectObjectLights(GLObjectBase * o);
|
||||
void objectsCountInternal(int * cnt, GLObjectBase * where);
|
||||
void removeObjectInternal(GLObjectBase * o, GLObjectBase * where);
|
||||
void renderSingleSelection(GLObjectBase & o);
|
||||
//void renderSingleShadow(GLObjectBase & o);
|
||||
void renderHalo(const GLObjectBase * obj, const uint iid, const QColor & color, const float & fill);
|
||||
void reloadThisShaders();
|
||||
void processKeys();
|
||||
bool setupViewport();
|
||||
|
||||
QPoint lastPos, downPos;
|
||||
GLObjectBase objects_;
|
||||
QList<Light * > lights_;
|
||||
// uint cid;
|
||||
QHash<uint, GLObjectBase * > ids;
|
||||
QSet<int> keys_;
|
||||
FogMode fogMode_;
|
||||
QColor backColor_, fogColor_, ambientColor_, hoverHaloColor_, selectionHaloColor_;
|
||||
QTime time, ktm_;
|
||||
GLint max_anisotropic, max_texture_chanels;
|
||||
GLObjectBase::RenderMode rmode;
|
||||
GLObjectBase * sel_obj, * hov_obj;
|
||||
GLFramebuffer fbo_selection;
|
||||
QOpenGLShaderProgram * shader_select, * shader_halo;
|
||||
GLRendererBase * renderer_;
|
||||
SelectionMode sel_mode;
|
||||
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;
|
||||
bool is_first_draw, is_init, fogEnabled_, lightEnabled_, grabMouse_, mouse_first, mouseRotate_, mouseSelect_, customMouseMove_;
|
||||
bool shaders_supported, changed_, cameraOrbit_, need_init_;
|
||||
bool hoverHalo_, selectionHalo_, shaders_bind, selecting_;
|
||||
|
||||
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 setFogMode(const FogMode & arg) {fogMode_ = 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() {if (renderer_ != nullptr) renderer_->reloadShaders(); reloadThisShaders();}
|
||||
void deselect() {sel_obj = nullptr;}
|
||||
|
||||
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(GLObjectBase * cur, GLObjectBase * prev);
|
||||
void selectionChanged(GLObjectBase * cur, GLObjectBase * prev);
|
||||
void objectAdded(GLObjectBase * );
|
||||
void doubleClick();
|
||||
|
||||
};
|
||||
|
||||
#endif // QGLVIEW_H
|
||||
76
test/qglview/qglview.qrc
Normal file
@@ -0,0 +1,76 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/document-save-all.png</file>
|
||||
<file>icons/document-new.png</file>
|
||||
<file>icons/document-import.png</file>
|
||||
<file>icons/dialog-close.png</file>
|
||||
<file>icons/edit-clear.png</file>
|
||||
<file>icons/edit-guides.png</file>
|
||||
<file>icons/type-camera.png</file>
|
||||
<file>icons/type-geo.png</file>
|
||||
<file>icons/type-light.png</file>
|
||||
<file>icons/view-grid.png</file>
|
||||
<file>icons/zoom-fit-best.png</file>
|
||||
<file>icons/configure.png</file>
|
||||
<file>icons/document-save.png</file>
|
||||
<file>icons/edit-clear-locationbar-rtl.png</file>
|
||||
<file>icons/edit-find.png</file>
|
||||
<file>icons/list-add.png</file>
|
||||
<file>icons/edit-delete.png</file>
|
||||
<file>icons/item.png</file>
|
||||
<file>icons/node-add.png</file>
|
||||
<file>icons/application-exit.png</file>
|
||||
<file>icons/document-open.png</file>
|
||||
<file>icons/document-save-.png</file>
|
||||
<file>icons/node.png</file>
|
||||
<file>icons/edit-copy.png</file>
|
||||
<file>icons/edit-paste.png</file>
|
||||
<file>icons/qglview.png</file>
|
||||
<file>shaders/bloom_0.frag</file>
|
||||
<file>shaders/bloom_1.frag</file>
|
||||
<file>shaders/bloom_pass_0.frag</file>
|
||||
<file>shaders/bloom_pass_0.vert</file>
|
||||
<file>shaders/bloom_pass_1.frag</file>
|
||||
<file>shaders/bloom_pass_1.vert</file>
|
||||
<file>shaders/downscale.frag</file>
|
||||
<file>shaders/downscale.vert</file>
|
||||
<file>shaders/dsl_pass_0.frag</file>
|
||||
<file>shaders/dsl_pass_0.vert</file>
|
||||
<file>shaders/dsl_pass_1.frag</file>
|
||||
<file>shaders/dsl_pass_1.vert</file>
|
||||
<file>shaders/dsl_pass_2.frag</file>
|
||||
<file>shaders/dsl_pass_2.vert</file>
|
||||
<file>shaders/fbo_add.frag</file>
|
||||
<file>shaders/fbo_add.vert</file>
|
||||
<file>shaders/FXAA.frag</file>
|
||||
<file>shaders/FXAA.vert</file>
|
||||
<file>shaders/hdr.frag</file>
|
||||
<file>shaders/hdr.vert</file>
|
||||
<file>shaders/hdr_scale_0.frag</file>
|
||||
<file>shaders/hdr_scale_1.frag</file>
|
||||
<file>shaders/light_models.frag</file>
|
||||
<file>shaders/motion_blur.frag</file>
|
||||
<file>shaders/motion_blur.vert</file>
|
||||
<file>shaders/post.frag</file>
|
||||
<file>shaders/ppl.frag</file>
|
||||
<file>shaders/ppl.vert</file>
|
||||
<file>shaders/selection.frag</file>
|
||||
<file>shaders/selection.vert</file>
|
||||
<file>shaders/selection_halo.frag</file>
|
||||
<file>shaders/selection_halo.vert</file>
|
||||
<file>shaders/shadow.frag</file>
|
||||
<file>shaders/shadow.vert</file>
|
||||
<file>shaders/ssao_blur.frag</file>
|
||||
<file>shaders/ssao_blur.vert</file>
|
||||
<file>shaders/ssao_merge.frag</file>
|
||||
<file>shaders/ssao_merge.vert</file>
|
||||
<file>shaders/ssr.frag</file>
|
||||
<file>shaders/ssr.vert</file>
|
||||
<file>shaders/ssr_blur.frag</file>
|
||||
<file>shaders/ssr_blur.vert</file>
|
||||
<file>shaders/ssr_merge.frag</file>
|
||||
<file>shaders/ssr_merge.vert</file>
|
||||
<file>shaders/dof.frag</file>
|
||||
<file>shaders/dof.vert</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
34
test/qglview/qglview_test/main.cpp
Normal 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();
|
||||
}
|
||||
338
test/qglview/qglview_test/qglview_window.cpp
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
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 "loader_qgl.h"
|
||||
#include "loader_ase.h"
|
||||
#include "loader_3ds.h"
|
||||
#include "loader_obj.h"
|
||||
#include "loader_dae.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);
|
||||
icon_geo = QIcon(":/icons/type-geo.png");
|
||||
icon_camera = QIcon(":/icons/type-camera.png");
|
||||
icon_light = QIcon(":/icons/type-light.png");
|
||||
|
||||
sel_obj = nullptr;
|
||||
view->view()->camera()->setAim(QVector3D());
|
||||
view->view()->camera()->setPos(QVector3D(2, 2, 2));
|
||||
// view->setFrameShape(QFrame::NoFrame);
|
||||
view->view()->setRenderer(new RendererSimple(view->view()));
|
||||
view->view()->setMouseRotateEnabled(true);
|
||||
view->view()->setMouseSelectionEnabled(true);
|
||||
view->view()->setSelectionHaloEnabled(true);
|
||||
view->view()->setHoverHaloEnabled(true);
|
||||
view->view()->setHoverHaloFillAlpha(0.);
|
||||
view->view()->setSelectionHaloFillAlpha(0.);
|
||||
view->view()->setBackColor(Qt::lightGray);
|
||||
view->view()->setDepthStart(0.001);
|
||||
view->view()->setDepthEnd(100000.);
|
||||
|
||||
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));
|
||||
checkMSAA->setChecked(view->view()->isFeatureEnabled(QGLView::qglMSAA));
|
||||
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());
|
||||
|
||||
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);
|
||||
axis->addChild(obj);
|
||||
obj = new GLPrimitiveLine(QVector3D(-al, 0, 0), QVector3D(al, 0, 0));
|
||||
obj->material().color_diffuse = Qt::darkRed; obj->setAcceptLight(false);
|
||||
axis->addChild(obj);
|
||||
obj = new GLPrimitiveLine(QVector3D(0, -al, 0), QVector3D(0, al, 0));
|
||||
obj->material().color_diffuse = Qt::darkGreen; obj->setAcceptLight(false);
|
||||
axis->addChild(obj);
|
||||
view->view()->addObject(axis);
|
||||
|
||||
cam_light = new Light();
|
||||
cam_light->intensity = 0.5;
|
||||
cam_light->setName("Camera_Light");
|
||||
view->view()->camera()->addChild(cam_light);
|
||||
view->view()->start(-1);
|
||||
startTimer(1000/60);
|
||||
|
||||
connect(view->view(), SIGNAL(selectionChanged(GLObjectBase*,GLObjectBase*)), this, SLOT(selectionChanged(GLObjectBase*,GLObjectBase*)));
|
||||
connect(view->view(), SIGNAL(keyEvent(Qt::Key, Qt::KeyboardModifiers)), this, SLOT(view_keyEvent(Qt::Key, Qt::KeyboardModifiers)));
|
||||
connect(matEditor, SIGNAL(changed()), this, SLOT(materialChanged()));
|
||||
|
||||
//view->view()->addObject(&partsys);
|
||||
partsys.material().color_diffuse = Qt::red;
|
||||
treeProps->assignObject(&partsys);
|
||||
session.load();
|
||||
}
|
||||
|
||||
|
||||
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.;
|
||||
//cam_light->intensity = checkCameraLight->isChecked() ? 0.5 : 0.;
|
||||
cam_light->setVisible(checkCameraLight->isChecked());
|
||||
//((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) {
|
||||
prev_path = path;
|
||||
importFile(path);
|
||||
}
|
||||
|
||||
|
||||
void QGLViewWindow::importFile(const QString & path) {
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QFileInfo fi(path);
|
||||
GLObjectBase * o = nullptr;
|
||||
if (fi.suffix().toLower() == "qgl") o = loadFromQGLFile(path);
|
||||
if (fi.suffix().toLower() == "ase") o = loadFromASEFile(path);
|
||||
if (fi.suffix().toLower() == "3ds") o = loadFrom3DSFile(path);
|
||||
if (fi.suffix().toLower() == "obj") o = loadFromOBJFile(path);
|
||||
if (fi.suffix().toLower() == "dae") o = loadFromDAEFile(path);
|
||||
QApplication::restoreOverrideCursor();
|
||||
if (!o) {
|
||||
QMessageBox::critical(this, "Import", "Can`t load " + path + "!");
|
||||
return;
|
||||
}
|
||||
o->setName(fi.baseName());
|
||||
view->view()->addObject(o);
|
||||
objectsTreeChanged();
|
||||
}
|
||||
|
||||
|
||||
void QGLViewWindow::makeObjetTree(const GLObjectBase * o, QTreeWidgetItem * ti) {
|
||||
if (o == axis) return;
|
||||
for (int i = 0; i < o->childCount(); ++i) {
|
||||
const GLObjectBase * co = o->child(i);
|
||||
QTreeWidgetItem * ci = new QTreeWidgetItem(ti);
|
||||
ci->setText(0, co->name());
|
||||
ci->setData(0, Qt::UserRole, quintptr(co));
|
||||
switch (co->type()) {
|
||||
case GLObjectBase::glMesh: ci->setIcon(0, icon_geo); break;
|
||||
case GLObjectBase::glLight: ci->setIcon(0, icon_light); break;
|
||||
case GLObjectBase::glCamera: ci->setIcon(0, icon_camera); break;
|
||||
default: break;
|
||||
}
|
||||
makeObjetTree(co, ci);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QGLViewWindow::selectionChanged(GLObjectBase * cur, GLObjectBase *) {
|
||||
sel_obj = cur;
|
||||
//qDebug() << "selected" << (cur != 0 ? cur->name() : "0");
|
||||
labelName->setText(cur != nullptr ? cur->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);
|
||||
if (sel_obj == nullptr) return;
|
||||
matEditor->setMaterial(sel_obj->material());
|
||||
//qDebug() << sel_obj->boundingBox();
|
||||
}
|
||||
|
||||
|
||||
void QGLViewWindow::materialChanged() {
|
||||
if (sel_obj == nullptr) return;
|
||||
sel_obj->setMaterial(matEditor->material());
|
||||
}
|
||||
|
||||
|
||||
void QGLViewWindow::on_comboRenderer_currentIndexChanged(int val) {
|
||||
GLRendererBase * pr = nullptr;
|
||||
switch (val) {
|
||||
case 0: view->view()->setRenderer(new RendererSimple(view->view()), &pr); break;
|
||||
case 1: view->view()->setRenderer(new RendererDeferredShading(view->view()), &pr); break;
|
||||
//case 2: view->view()->setRenderer(new RendererRT(view), &pr); break;
|
||||
}
|
||||
if (pr != nullptr) delete pr;
|
||||
}
|
||||
|
||||
|
||||
void QGLViewWindow::on_actionReset_triggered() {
|
||||
view->view()->removeObject(axis, false);
|
||||
view->view()->clearObjects(true);
|
||||
view->view()->addObject(axis);
|
||||
objectsTreeChanged();
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
importFile(f);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
view->view()->removeObject(axis);
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
saveToQGLFile(f, &(view->view()->rootObject()));
|
||||
QApplication::restoreOverrideCursor();
|
||||
view->view()->addObject(axis);
|
||||
}
|
||||
|
||||
|
||||
void QGLViewWindow::on_actionSaveSelected_triggered() {
|
||||
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;
|
||||
importFile(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_treeObjects_itemClicked(QTreeWidgetItem * ti, int) {
|
||||
((GLObjectBase*)(ti->data(0, Qt::UserRole).toULongLong()))->select();
|
||||
//qDebug() << ((GLObjectBase*)(ti->data(0, Qt::UserRole).toULongLong()))->type();
|
||||
if (sel_obj->type() == GLObjectBase::glCamera)
|
||||
view->view()->setCamera((Camera*)sel_obj);
|
||||
}
|
||||
|
||||
|
||||
void QGLViewWindow::objectsTreeChanged() {
|
||||
treeObjects->clear();
|
||||
makeObjetTree(&(view->view()->rootObject()), treeObjects->invisibleRootItem());
|
||||
treeObjects->expandAll();
|
||||
}
|
||||
|
||||
|
||||
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<GLObjectBase * > ol = view->view()->objects(true);
|
||||
qDebug() << ol.size();
|
||||
foreach (GLObjectBase * i, ol) {
|
||||
i->VBO().rebuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
144
test/qglview/qglview_test/qglview_window.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
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 "loader_3ds.h"
|
||||
#include "loader_ase.h"
|
||||
#include "renderer_simple.h"
|
||||
#include "renderer_deferred_shading.h"
|
||||
#include "session_manager.h"
|
||||
//#include "renderer_rt.h"
|
||||
#include "glparticles_system.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);
|
||||
|
||||
private:
|
||||
// Qt`s overloaded
|
||||
void changeEvent(QEvent * e);
|
||||
void timerEvent(QTimerEvent * );
|
||||
|
||||
void importFile(const QString & path);
|
||||
void makeObjetTree(const GLObjectBase * o, QTreeWidgetItem * ti);
|
||||
|
||||
QTranslator translator;
|
||||
QIcon icon_geo, icon_camera, icon_light;
|
||||
QString prev_path;
|
||||
GLObjectBase * sel_obj, * axis;
|
||||
Light * cam_light;
|
||||
GLPrimitiveCube * box;
|
||||
Material m;
|
||||
SessionManager session;
|
||||
bool isChanged;
|
||||
|
||||
GLParticlesSystem partsys;
|
||||
|
||||
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_comboRenderer_currentIndexChanged(int val);
|
||||
void on_comboViewRenderMode_currentIndexChanged(int val) {static int modes[] = {GL_POINT, GL_LINE, GL_FILL}; view->view()->setRenderMode((GLObjectBase::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_checkMSAA_clicked(bool val) {view->view()->setFeature(QGLView::qglMSAA, 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_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 view_keyEvent(Qt::Key k, Qt::KeyboardModifiers m);
|
||||
|
||||
void on_treeObjects_itemClicked(QTreeWidgetItem * ti, int);
|
||||
|
||||
void objectsTreeChanged();
|
||||
void materialChanged();
|
||||
void selectionChanged(GLObjectBase * cur, GLObjectBase *);
|
||||
|
||||
void on_pushButton_clicked();
|
||||
void on_pushButton_2_clicked() {view->view()->reloadShaders();}
|
||||
void on_pushButton_3_clicked();
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
QMatrix4x4 cam_mat;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGLVIEWWINDOW_H
|
||||
1234
test/qglview/qglview_test/qglview_window.ui
Normal file
@@ -0,0 +1,1234 @@
|
||||
<?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>1056</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>QGLView converter</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0">
|
||||
<item>
|
||||
<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>10</red>
|
||||
<green>10</green>
|
||||
<blue>10</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>10</red>
|
||||
<green>10</green>
|
||||
<blue>10</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>
|
||||
</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="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>
|
||||
</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>
|
||||
<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="GLObjectEditor" 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="MaterialEditor" name="matEditor" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<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_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>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="GLWidget" name="view" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Objects</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeObjects">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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>21</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>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar_"/>
|
||||
<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="../../piqt_utils/piconnedit/piconnedit.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>
|
||||
</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 location="global">glwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MaterialEditor</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">material_editor.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>GLObjectEditor</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>globject_editor.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PropertyEditor</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>propertyeditor.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../qad/application/qad_application.qrc"/>
|
||||
<include location="../../piqt_utils/piconnedit/piconnedit.qrc"/>
|
||||
<include location="../qglview.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
597
test/qglview/renderer_deferred_shading.cpp
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
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 "renderer_deferred_shading.h"
|
||||
#include <QBoxLayout>
|
||||
|
||||
|
||||
RendererDeferredShading::RendererDeferredShading(QGLView * view_): GLRendererBase(view_),
|
||||
fbo_g(5, true, GL_RGBA16F), fbo_out(3, false, GL_RGBA16F), fbo_hsmall(1, false, GL_RGB16F) {
|
||||
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);
|
||||
for (int i = 0; i < shaders.size(); ++i)
|
||||
*(shaders[i].second) = nullptr;
|
||||
lights_per_pass = 8;
|
||||
tnoise = 0;
|
||||
exposure_ = 1.;
|
||||
df = new QWidget();
|
||||
df->setLayout(new QBoxLayout(QBoxLayout::TopToBottom));
|
||||
label_exp = new QLabel();
|
||||
label_exp_step = new QLabel();
|
||||
df->layout()->addWidget(label_exp);
|
||||
df->layout()->addWidget(label_exp_step);
|
||||
QPalette pal(df->palette());
|
||||
pal.setBrush(QPalette::Window, QColor(255, 255, 255, 192));
|
||||
df->setPalette(pal);
|
||||
if (view_)
|
||||
;//view_->addObject(df);
|
||||
}
|
||||
|
||||
|
||||
RendererDeferredShading::~RendererDeferredShading() {
|
||||
for (int i = 0; i < shaders.size(); ++i) {
|
||||
QOpenGLShaderProgram * p(*(shaders[i].second));
|
||||
if (p) delete p;
|
||||
}
|
||||
delete df;
|
||||
}
|
||||
|
||||
|
||||
void RendererDeferredShading::renderScene() {
|
||||
//qDebug() << lights_per_pass;
|
||||
QMatrix4x4 mproj = rp.proj_matrix;
|
||||
QMatrix4x4 mproji = rp.proj_matrix_i;
|
||||
QMatrix4x4 mview = rp.view_matrix;
|
||||
QMatrix4x4 mviewi = rp.view_matrix_i;
|
||||
QMatrix4x4 mviewproji = (mproj * mview).inverted();
|
||||
QMatrix4x4 moffset = view.camera()->offsetMatrix();
|
||||
QMatrix4x4 moffseti = moffset.inverted();
|
||||
rp.prev_proj_matrix = prev_proj;
|
||||
rp.prev_view_matrix = prev_view;
|
||||
QMatrix4x4 vc_proji;
|
||||
vc_proji.perspective(90., 1., view.camera()->depthStart(), view.camera()->depthEnd());
|
||||
vc_proji = vc_proji.inverted();
|
||||
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));
|
||||
//qDebug() << corner_dirs[0] << corner_dirs[1] << corner_dirs[2] << corner_dirs[3];
|
||||
fbo_g.bind();
|
||||
int buffs[] = {0, 1, 2, 3, 4};
|
||||
fbo_g.setWriteBuffers(buffs, 5);
|
||||
if (white_image_id == 0) {
|
||||
glActiveTexture(GL_TEXTURE0 + 6);
|
||||
white_image_id = view.textureManager()->loadTexture(white_image, false);
|
||||
glBindTexture(GL_TEXTURE_2D, white_image_id);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
if (violent_image_id == 0) {
|
||||
glActiveTexture(GL_TEXTURE0 + 7);
|
||||
violent_image_id = view.textureManager()->loadTexture(violent_image, false);
|
||||
glBindTexture(GL_TEXTURE_2D, violent_image_id);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
glEnableDepth();
|
||||
glClearFramebuffer(QColor(0, 0, 0, 0));
|
||||
glDisable(GL_RESCALE_NORMAL);
|
||||
shader_ds_0->bind();
|
||||
rp.setUniform(shader_ds_0);
|
||||
shader_ds_0->setUniformValue("z_far", view.depthEnd());
|
||||
shader_ds_0->setUniformValue("z_near", view.depthStart());
|
||||
shader_ds_0->setUniformValue("t0", 0);
|
||||
shader_ds_0->setUniformValue("t1", 1);
|
||||
shader_ds_0->setUniformValue("t2", 2);
|
||||
shader_ds_0->setUniformValue("t3", 3);
|
||||
shader_ds_0->setUniformValue("t4", 4);
|
||||
shader_ds_0->setUniformValue("dt", QVector2D(1.f / view.width(), 1.f / view.height()));
|
||||
//qDebug() << rp.view_matrix << prev_view;
|
||||
//shader_ds_0->setUniformValue("qgl_ModelViewMatrix", rp.view_matrix);
|
||||
renderObjects(GLObjectBase::Solid, 0, shader_ds_0, true, false, false);
|
||||
//glReleaseShaders();
|
||||
fbo_g.release();
|
||||
|
||||
if (view.isFeatureEnabled(QGLView::qglShadowsEnabled)) {
|
||||
shader_shadow->bind();
|
||||
int sms = view.feature(QGLView::qglShadowsMapSize).toInt();
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_TEXTURE_CUBE_MAP);
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_RESCALE_NORMAL);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
//qDebug() << "render shadows";
|
||||
for (int i = 0; i < view.lightsCount(); ++i) {
|
||||
Light * l = view.light(i);
|
||||
if (l->light_type == Light::Omni) continue;
|
||||
l->shadow_map.resize(sms, sms);
|
||||
l->shadow_map.bind();
|
||||
l->shadow_map.setWriteBuffer(0);
|
||||
glClearFramebuffer();
|
||||
//glClear(GL_DEPTH_BUFFER_BIT);
|
||||
renderShadow(l, shader_shadow, moffseti*mviewi);
|
||||
l->shadow_map.release();
|
||||
}
|
||||
}
|
||||
// glUseProgram(0);
|
||||
//// fbo_g.bindColorTextures();
|
||||
// glBindTexture(GL_TEXTURE_2D, fbo_g.colorTexture(0));
|
||||
// glActiveTexture(GL_TEXTURE0);
|
||||
// glDrawQuad();
|
||||
// return;
|
||||
|
||||
glResetAllTransforms();
|
||||
glSetLightEnabled(false);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
//glBlendFunc(GL_ONE, GL_ONE);
|
||||
glDisableDepth();
|
||||
rp.prepare();
|
||||
//qDebug() << rp.view_matrix;
|
||||
shader_ds_1->bind();
|
||||
shader_ds_1->setUniformValue("z_far", view.depthEnd());
|
||||
shader_ds_1->setUniformValue("z_near", view.depthStart());
|
||||
shader_ds_1->setUniformValue("t0", 0);
|
||||
shader_ds_1->setUniformValue("t1", 1);
|
||||
shader_ds_1->setUniformValue("t2", 2);
|
||||
shader_ds_1->setUniformValue("t3", 3);
|
||||
shader_ds_1->setUniformValue("t4", 4);
|
||||
shader_ds_1->setUniformValue("td", 5);
|
||||
shader_ds_1->setUniformValue("back_color", view.backColor());
|
||||
shader_ds_1->setUniformValue("mat_proji", mproji);
|
||||
shader_ds_1->setUniformValue("mat_view", mview);
|
||||
shader_ds_1->setUniformValue("mat_viewi", mviewi);
|
||||
shader_ds_1->setUniformValue("mat_viewproji", mviewproji);
|
||||
shader_ds_1->setUniformValue("shadow_on", view.isFeatureEnabled(QGLView::qglShadowsEnabled) ? 1 : 0);
|
||||
shader_ds_1->setUniformValue("dt", QVector2D(1.f / view.width(), 1.f / view.height()));
|
||||
rp.setUniform(shader_ds_1);
|
||||
fbo_g.bindColorTextures();
|
||||
fbo_g.bindDepthTexture(5);
|
||||
fbo_out.bind();
|
||||
fbo_out.setWriteBuffer(0);
|
||||
glClearFramebuffer(Qt::black, false);
|
||||
//QVector<QVector4D> lpos;
|
||||
//qDebug() << view_matrix;
|
||||
shader_ds_1->setUniformValue("t_pp", 6);
|
||||
int passes = (view.lightsCount() - 1) / lights_per_pass + 1;
|
||||
if (passes < 1) passes = 1;
|
||||
//qDebug() << "render in" << passes << "passes (" << lights_per_pass << ")";
|
||||
int wi, ri;
|
||||
for (int l = 0; l < passes; ++l) {
|
||||
wi = 1 - l % 2;
|
||||
ri = l % 2;
|
||||
//qDebug() << " pass" << l << "read from" << ri << "write to" << wi;
|
||||
glActiveTexture(GL_TEXTURE0 + 6);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
fbo_out.setWriteBuffer(wi);
|
||||
setupDSLights(l, mview * moffset);
|
||||
glDrawQuad(shader_ds_1, corner_dirs);
|
||||
//break;
|
||||
}
|
||||
//fbo_out.release();
|
||||
wi = 1 - passes % 2;
|
||||
ri = passes % 2;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
|
||||
if (view.isFeatureEnabled(QGLView::qglSSAOEnabled)) {
|
||||
fbo_out.setWriteBuffer(2);
|
||||
fbo_out.setReadBuffer(ri);
|
||||
glBlitFramebuffer(0, 0, fbo_out.width(), fbo_out.height(), 0, 0, fbo_out.width(), fbo_out.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(2));
|
||||
glActiveTexture(GL_TEXTURE0 + 2);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_g.colorTexture(1));
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
//glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
//glActiveTextureChannel(1);
|
||||
//glBindTexture(GL_TEXTURE_2D, fbo_g.colorTexture(0));
|
||||
int lri = ri, lwi = wi;//, lms = ri;
|
||||
shader_ssao_blur->bind();
|
||||
shader_ssao_blur->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_ssao_blur->setUniformValue("dt", QVector2D(1.f / fbo_out.width(), 1.f / fbo_out.height()));
|
||||
shader_ssao_blur->setUniformValue("t0", 0);
|
||||
shader_ssao_blur->setUniformValue("ts", 1);
|
||||
shader_ssao_blur->setUniformValue("tg1", 2);
|
||||
int passes = view.feature(QGLView::qglSSAORadius).toInt();
|
||||
int crad = 1;
|
||||
for (int p = 0; p < passes; ++p) {
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(lri));
|
||||
fbo_out.setWriteBuffer(lwi);
|
||||
shader_ssao_blur->setUniformValue("radius", GLfloat(crad));
|
||||
glDrawQuad(shader_ssao_blur);
|
||||
piSwap<int>(lwi, lri);
|
||||
crad *= 2;
|
||||
}
|
||||
//qDebug() << wi << ri << lms;
|
||||
/*wi = lri;
|
||||
ri = 1 - lms;*/
|
||||
glEnable(GL_TEXTURE_1D);
|
||||
if (tnoise == 0) {
|
||||
glGenTextures(1, &tnoise);
|
||||
glBindTexture(GL_TEXTURE_1D, tnoise);
|
||||
QByteArray ba;
|
||||
for (int i = 0; i < 32*3; ++i)
|
||||
ba.push_back(char(random() % 256));
|
||||
//qDebug() << ba;
|
||||
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB8, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, ba.constData());
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(lri));
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(2));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glActiveTexture(GL_TEXTURE0 + 2);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_g.colorTexture(1));
|
||||
glActiveTexture(GL_TEXTURE0 + 3);
|
||||
glBindTexture(GL_TEXTURE_1D, tnoise);
|
||||
shader_ssao_merge->bind();
|
||||
shader_ssao_merge->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_ssao_merge->setUniformValue("z_far", view.depthEnd());
|
||||
shader_ssao_merge->setUniformValue("z_near", view.depthStart());
|
||||
shader_ssao_merge->setUniformValue("mat_proj", mproj);
|
||||
shader_ssao_merge->setUniformValue("n0", 3);
|
||||
shader_ssao_merge->setUniformValue("t0", 0);
|
||||
shader_ssao_merge->setUniformValue("ts", 1);
|
||||
shader_ssao_merge->setUniformValue("tg1", 2);
|
||||
fbo_out.setWriteBuffer(lwi);
|
||||
glDrawQuad(shader_ssao_merge, corner_dirs);
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
wi = lri;
|
||||
ri = lwi;
|
||||
//piSwap<int>(wi, ri);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
//piSwap<int>(wi, ri);
|
||||
}
|
||||
|
||||
if (view.isFeatureEnabled(QGLView::qglReflectionsEnabled)) {
|
||||
fbo_out.setWriteBuffer(2);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//_MIPMAP_LINEAR);
|
||||
//glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_g.colorTexture(0));
|
||||
glActiveTexture(GL_TEXTURE0 + 2);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_g.colorTexture(1));
|
||||
fbo_g.bindDepthTexture(7);
|
||||
shader_ssr->bind();
|
||||
shader_ssr->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_ssr->setUniformValue("z_far", view.depthEnd());
|
||||
shader_ssr->setUniformValue("z_near", view.depthStart());
|
||||
shader_ssr->setUniformValue("mat_proj", mproj);
|
||||
shader_ssr->setUniformValue("t0", 1);
|
||||
shader_ssr->setUniformValue("t1", 2);
|
||||
shader_ssr->setUniformValue("ts", 0);
|
||||
shader_ssr->setUniformValue("td", 7);
|
||||
glDrawQuad(shader_ssr, corner_dirs);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
int lri = 2, lwi = wi, lms = ri;
|
||||
if (view.isFeatureEnabled(QGLView::qglReflectionsBlur)) {
|
||||
shader_ssr_blur->bind();
|
||||
shader_ssr_blur->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_ssr_blur->setUniformValue("dt", QVector2D(1.f / fbo_out.width(), 1.f / fbo_out.height()));
|
||||
shader_ssr_blur->setUniformValue("t0", 0);
|
||||
int passes = 5;
|
||||
int crad = 1;
|
||||
for (int p = 0; p < passes; ++p) {
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(lri));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//_MIPMAP_LINEAR);
|
||||
fbo_out.setWriteBuffer(lwi);
|
||||
shader_ssr_blur->setUniformValue("radius", GLfloat(crad));
|
||||
glDrawQuad(shader_ssr_blur);
|
||||
piSwap<int>(lwi, lri);
|
||||
crad *= 2;
|
||||
}
|
||||
}
|
||||
//qDebug() << wi << ri << lms;
|
||||
wi = lri;
|
||||
ri = 1 - lms;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(wi));
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_g.colorTexture(1));
|
||||
glActiveTexture(GL_TEXTURE0 + 2);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(lms));
|
||||
shader_ssr_merge->bind();
|
||||
shader_ssr_merge->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_ssr_merge->setUniformValue("t0", 0);
|
||||
shader_ssr_merge->setUniformValue("tg1", 1);
|
||||
shader_ssr_merge->setUniformValue("ts", 2);
|
||||
fbo_out.setWriteBuffer(ri);
|
||||
glDrawQuad(shader_ssr_blur);
|
||||
wi = ri;
|
||||
ri = 1 - ri;
|
||||
//piSwap<int>(wi, ri);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(wi));
|
||||
piSwap<int>(wi, ri);
|
||||
}
|
||||
|
||||
if (view.isFeatureEnabled(QGLView::qglDepthOfFieldEnabled)) {
|
||||
if (view.isFeatureEnabled(QGLView::qglDepthOfFieldAutoFocusEnabled)) {
|
||||
GLfloat cw;
|
||||
//glReadBuffer();
|
||||
fbo_g.bind();
|
||||
glReadPixels(fbo_out.width() / 2, fbo_out.height() / 2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &cw);
|
||||
fbo_out.bind();
|
||||
const float _pe = 2.4e-7f;
|
||||
float cz = cw + cw - 1;
|
||||
cz = ((_pe - 2.f) * view.depthStart()) / (cz + _pe - 1.f); // infinite depth
|
||||
float z = view.feature(QGLView::qglDepthOfFieldFocus).toFloat(),
|
||||
s = view.feature(QGLView::qglDepthOfFieldAutoFocusSpeed).toFloat();
|
||||
z = z * (1.f - s) + cz * s;
|
||||
view.setFeature(QGLView::qglDepthOfFieldFocus, z);
|
||||
}
|
||||
shader_dof->bind();
|
||||
shader_dof->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_dof->setUniformValue("z_far", view.depthEnd());
|
||||
shader_dof->setUniformValue("z_near", view.depthStart());
|
||||
shader_dof->setUniformValue("focus", view.feature(QGLView::qglDepthOfFieldFocus).toFloat());
|
||||
shader_dof->setUniformValue("diaphragm", view.feature(QGLView::qglDepthOfFieldDiaphragm).toFloat());
|
||||
shader_dof->setUniformValue("t0", 0);
|
||||
shader_dof->setUniformValue("td", 7);
|
||||
fbo_g.bindDepthTexture(7);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
int passes = 3;
|
||||
float crad = 1.;
|
||||
for (int p = 0; p < passes; ++p) {
|
||||
shader_dof->setUniformValue("radius", crad);
|
||||
fbo_out.setWriteBuffer(wi);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
shader_dof->setUniformValue("dt", QVector2D(1.f / fbo_out.width(), 0.f));
|
||||
glDrawQuad(shader_dof);
|
||||
piSwap<int>(wi, ri);
|
||||
fbo_out.setWriteBuffer(wi);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
shader_dof->setUniformValue("dt", QVector2D(0.f, 1.f / fbo_out.height()));
|
||||
glDrawQuad(shader_dof);
|
||||
piSwap<int>(wi, ri);
|
||||
crad *= 2.f;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
}
|
||||
|
||||
if (view.isFeatureEnabled(QGLView::qglEyeAccomodationEnabled)) {
|
||||
fbo_hsmall.bind();
|
||||
fbo_hsmall.setWriteBuffer(0);
|
||||
shader_small->bind();
|
||||
shader_small->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_small->setUniformValue("t0", 0);
|
||||
glDrawQuad(shader_small);
|
||||
hcontent.resize(fbo_hsmall.width() * fbo_hsmall.height());
|
||||
glReadPixels(0, 0, fbo_hsmall.width(), fbo_hsmall.height(), GL_RGB, GL_FLOAT, hcontent.data());
|
||||
GLfloat max[3] = {0.,0.,0.};//min[3] = {10000.,10000.,10000.},;
|
||||
for (int i = 0; i < hcontent.size(); ++i) {
|
||||
//if (min[0] > hcontent[i].x) min[0] = hcontent[i].x;
|
||||
if (max[0] < hcontent[i].x) max[0] = hcontent[i].x;
|
||||
//if (min[1] > hcontent[i].y) min[1] = hcontent[i].y;
|
||||
if (max[1] < hcontent[i].y) max[1] = hcontent[i].y;
|
||||
//if (min[2] > hcontent[i].z) min[2] = hcontent[i].z;
|
||||
if (max[2] < hcontent[i].z) max[2] = hcontent[i].z;
|
||||
}
|
||||
GLfloat mluma = (0.299f * max[0]) + (0.587f * max[1]) + (0.114f * max[2]);
|
||||
float nexp = mluma / 16.f, dexp = nexp - exposure_, mestep = exposure_ * view.feature(QGLView::qglEyeAccomodationMaxSpeed).toFloat();
|
||||
dexp /= view.feature(QGLView::qglEyeAccomodationTime).toFloat();
|
||||
if (dexp > 0.f && dexp > mestep/4) dexp = mestep/4;
|
||||
if (dexp < 0.f && dexp < -mestep) dexp = -mestep;
|
||||
exposure_ += dexp;
|
||||
label_exp->setText(QString("exposure: %1").arg(exposure_));
|
||||
label_exp_step->setText(QString("d_exposure: %1").arg(dexp));
|
||||
//qDebug() << min[0] << max[0] << min[1] << max[1] << min[2] << max[2];
|
||||
fbo_hsmall.release();
|
||||
|
||||
//glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
fbo_out.bind();
|
||||
fbo_out.setWriteBuffer(wi);
|
||||
shader_hdr->bind();
|
||||
shader_hdr->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_hdr->setUniformValue("t0", 0);
|
||||
shader_hdr->setUniformValue("exposure", GLfloat(1.f/exposure_));
|
||||
glDrawQuad(shader_hdr);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(wi));
|
||||
piSwap<int>(wi, ri);
|
||||
}
|
||||
|
||||
if (view.isFeatureEnabled(QGLView::qglMotionBlurEnabled)) {
|
||||
fbo_out.setWriteBuffer(wi);
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_g.colorTexture(4));
|
||||
shader_motion_blur->bind();
|
||||
shader_motion_blur->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_motion_blur->setUniformValue("dt", QVector2D(1.f / fbo_out.width(), 1.f / fbo_out.height()));
|
||||
shader_motion_blur->setUniformValue("t0", 0);
|
||||
shader_motion_blur->setUniformValue("ts", 1);
|
||||
shader_motion_blur->setUniformValue("factor", view.feature(QGLView::qglMotionBlurFactor).toFloat());
|
||||
shader_motion_blur->setUniformValue("steps", view.feature(QGLView::qglMotionBlurSteps).toInt());
|
||||
glDrawQuad(shader_motion_blur);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(wi));
|
||||
piSwap<int>(wi, ri);
|
||||
}
|
||||
|
||||
if (view.isFeatureEnabled(QGLView::qglBloomEnabled)) {
|
||||
fbo_out.setWriteBuffer(2);
|
||||
fbo_out.setReadBuffer(ri);
|
||||
glBlitFramebuffer(0, 0, fbo_out.width(), fbo_out.height(), 0, 0, fbo_out.width(), fbo_out.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
//QTime tm;
|
||||
//tm.restart();
|
||||
fbo_out.setWriteBuffer(wi);
|
||||
shader_bloom_0->bind();
|
||||
shader_bloom_0->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_bloom_0->setUniformValue("factor", view.feature(QGLView::qglBloomFactor).toFloat());
|
||||
shader_bloom_0->setUniformValue("threshold", view.feature(QGLView::qglBloomThreshold).toFloat());
|
||||
shader_bloom_0->setUniformValue("t0", 0);
|
||||
glDrawQuad(shader_bloom_0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
piSwap<int>(wi, ri);
|
||||
|
||||
shader_bloom_1->bind();
|
||||
shader_bloom_1->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_bloom_1->setUniformValue("dt", QVector2D(1.f / fbo_out.width(), 1.f / fbo_out.height()));
|
||||
shader_bloom_1->setUniformValue("t0", 0);
|
||||
int radius = view.feature(QGLView::qglBloomRadius).toInt();
|
||||
int passes = qMax<int>(int(ceil(log2(radius))), 1);
|
||||
int crad = 1;
|
||||
for (int p = 0; p < passes; ++p) {
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
fbo_out.setWriteBuffer(wi);
|
||||
if (p == passes - 1)
|
||||
crad = piMax(1, radius - crad);
|
||||
shader_bloom_1->setUniformValue("radius", crad);
|
||||
glDrawQuad(shader_bloom_1);
|
||||
piSwap<int>(wi, ri);
|
||||
crad *= 2;
|
||||
}
|
||||
//qDebug() << tm.elapsed();
|
||||
fbo_out.setWriteBuffer(wi);
|
||||
// glActiveTextureChannel(0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri));
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(2));
|
||||
shader_fbo_add->bind();
|
||||
shader_fbo_add->setUniformValue("qgl_ModelViewProjectionMatrix", QMatrix4x4());
|
||||
shader_fbo_add->setUniformValue("t0", 0);
|
||||
shader_fbo_add->setUniformValue("t1", 1);
|
||||
glDrawQuad(shader_fbo_add);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(wi));
|
||||
piSwap<int>(wi, ri);
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
fbo_out.release();
|
||||
|
||||
if (view.isFeatureEnabled(QGLView::qglFXAA)) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
shader_fxaa->bind();
|
||||
shader_fxaa->setUniformValue("dt", QVector2D(1.f / view.width(), 1.f / view.height()));
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
glDrawQuad();
|
||||
if (view.isFeatureEnabled(QGLView::qglFXAA))
|
||||
shader_fxaa->release();
|
||||
prev_proj = mproj;
|
||||
prev_view = mview;
|
||||
}
|
||||
|
||||
|
||||
void RendererDeferredShading::init(int width, int height) {
|
||||
initializeOpenGLFunctions();
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
|
||||
void RendererDeferredShading::resize(int width, int height) {
|
||||
fbo_g.resize(width, height);
|
||||
fbo_out.resize(width, height);
|
||||
fbo_hsmall.resize(width / 16, height / 16);
|
||||
// view.setSceneRect(QRect(0, 0, width, height));
|
||||
//df->move(-width / 2, -height / 2);
|
||||
}
|
||||
|
||||
|
||||
void RendererDeferredShading::reloadShaders() {
|
||||
for (int i = 0; i < shaders.size(); ++i) {
|
||||
QOpenGLShaderProgram * p(*(shaders[i].second));
|
||||
if (!p) p = new QOpenGLShaderProgram(view.context());
|
||||
loadShaders(p, shaders[i].first, "://shaders");
|
||||
*(shaders[i].second) = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererDeferredShading::setupShadersTextures(GLObjectBase & object, GLRendererBase::RenderingParameters & rp) {
|
||||
glActiveTexture(GL_TEXTURE0 + 6);
|
||||
glBindTexture(GL_TEXTURE_2D, white_image_id);
|
||||
glActiveTexture(GL_TEXTURE0 + 7);
|
||||
glBindTexture(GL_TEXTURE_2D, violent_image_id);
|
||||
}
|
||||
|
||||
|
||||
void RendererDeferredShading::setupDSLights(int pass, const QMatrix4x4 & view_matrix) {
|
||||
int light_start, light_end, lmax, shadow_start = 7;
|
||||
light_start = pass * lights_per_pass;
|
||||
light_end = qMin<int>((pass + 1) * lights_per_pass, view.lights().size());
|
||||
lmax = light_start + lights_per_pass;
|
||||
amb_light.intensity = (pass == 0 ? 1. : 0.);
|
||||
amb_light.setColor(pass == 0 ? view.ambientColor() : Qt::black);
|
||||
amb_light.setName("ambient");
|
||||
setUniformLight(shader_ds_1, &amb_light, "qgl_AmbientLight");
|
||||
amb_light.intensity = 0.;
|
||||
QVector<Light*> lv;
|
||||
for (int i = light_start; i < light_end; ++i) {
|
||||
lv << view.lights()[i];
|
||||
glActiveTexture(GL_TEXTURE0 + shadow_start + i - light_start);
|
||||
glBindTexture(GL_TEXTURE_2D, lv.back()->shadow_map.depthTexture());
|
||||
if (view.isFeatureEnabled(QGLView::qglShadowsSoftEnabled)) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
}
|
||||
amb_light.setName("null");
|
||||
for (int i = light_end; i < lmax; ++i)
|
||||
lv << &amb_light;
|
||||
//QStringList lnl; foreach (Light * l, lv) lnl << l->name();
|
||||
//qDebug() << " lights" << light_start << "->" << light_end << ", inactive" << (lmax - light_end) << lnl;
|
||||
setUniformLights(shader_ds_1, lv, view_matrix, shadow_start);
|
||||
}
|
||||
|
||||
|
||||
void RendererDeferredShading::setupAmbientLight(const QColor & a, bool first_pass) {
|
||||
|
||||
}
|
||||
67
test/qglview/renderer_deferred_shading.h
Normal 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/>.
|
||||
*/
|
||||
|
||||
#ifndef RENDERER_DEFERRED_SHADING_H
|
||||
#define RENDERER_DEFERRED_SHADING_H
|
||||
|
||||
#include "qglview.h"
|
||||
#include <QLabel>
|
||||
|
||||
|
||||
class RendererDeferredShading: public GLRendererBase
|
||||
{
|
||||
public:
|
||||
RendererDeferredShading(QGLView * view);
|
||||
virtual ~RendererDeferredShading();
|
||||
|
||||
virtual void renderScene();
|
||||
void init(int width, int height);
|
||||
void resize(int width, int height);
|
||||
void reloadShaders();
|
||||
|
||||
protected:
|
||||
void setupShadersTextures(GLObjectBase & object, RenderingParameters & rp);
|
||||
void setupShadersLights(int lights_count) {cplc = lights_count;}
|
||||
void setupDSLights(int pass, const QMatrix4x4 & view_matrix);
|
||||
void setupAmbientLight(const QColor & a, bool first_pass);
|
||||
|
||||
private:
|
||||
typedef QPair<QString, QOpenGLShaderProgram **> ShaderPair;
|
||||
|
||||
int cplc, lights_per_pass;
|
||||
float exposure_;
|
||||
GLFramebuffer fbo_g, 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;
|
||||
GLuint tnoise;
|
||||
QVector<ShaderPair> shaders;
|
||||
|
||||
QMatrix4x4 prev_view, prev_proj;
|
||||
QMatrix3x3 nm;
|
||||
QVector4D corner_dirs[4];
|
||||
QVector<Vector3d> hcontent;
|
||||
Light amb_light;
|
||||
|
||||
QWidget * df;
|
||||
QLabel * label_exp, * label_exp_step;
|
||||
|
||||
};
|
||||
|
||||
#endif // RENDERER_DEFERRED_SHADING_H
|
||||
130
test/qglview/renderer_simple.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
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 "renderer_simple.h"
|
||||
|
||||
|
||||
RendererSimple::RendererSimple(QGLView * view_): GLRendererBase(view_), fbo(2)
|
||||
, fbo_c(1, true, GL_RGBA32F) /// WARNING
|
||||
{
|
||||
shader_fxaa = 0;
|
||||
shader = 0; /// WARNING
|
||||
}
|
||||
|
||||
|
||||
void RendererSimple::reloadShaders() {
|
||||
if (shader_fxaa == 0) {
|
||||
shader_fxaa = new QOpenGLShaderProgram(view.context());
|
||||
loadShaders(shader_fxaa, "FXAA", "://shaders");
|
||||
}
|
||||
/*if (shader == 0) {
|
||||
shader = new QOpenGLShaderProgram(view.context()); /// WARNING
|
||||
loadShaders(shader, "test", "shaders"); /// WARNING
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void RendererSimple::resizeFBO(int w, int h) {
|
||||
initializeOpenGLFunctions();
|
||||
fbo.resize(w, h);
|
||||
fbo_c.resize(w, h); /// WARNING
|
||||
}
|
||||
|
||||
|
||||
void RendererSimple::renderScene() {
|
||||
int passes = (view.lightsCount() - 1) / 8 + 1;
|
||||
//QMatrix4x4 pm = getGLMatrix(GL_PROJECTION_MATRIX), mvm = getGLMatrix(GL_MODELVIEW_MATRIX), pmvm = pm * mvm, lpm, lmvm, lpmvm;
|
||||
glSetCapEnabled(GL_MULTISAMPLE, view.isFeatureEnabled(QGLView::qglMSAA));
|
||||
if (passes < 1) passes = 1;
|
||||
//glEnable(GL_FOG);
|
||||
if (view.isFeatureEnabled(QGLView::qglFXAA)) fbo.bind();
|
||||
//glEnable(GL_TEXTURE_2D);
|
||||
if (passes > 1) {
|
||||
fbo.bind();
|
||||
fbo.setWriteBuffer(0);
|
||||
glClearFramebuffer();
|
||||
}
|
||||
glEnable(GL_RESCALE_NORMAL);
|
||||
for (int l = 0; l < passes; ++l) {
|
||||
if (passes > 1) fbo.setWriteBuffer(1);
|
||||
if (l == 0) {
|
||||
glClearFramebuffer(view.backColor());
|
||||
glEnableDepth();
|
||||
} else {
|
||||
glClearFramebuffer(Qt::black, false);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDepthFunc(GL_EQUAL);
|
||||
}
|
||||
//view.camera().apply(view.aspect);
|
||||
rp.cam_offset_matrix = view.camera()->offsetMatrix();
|
||||
rp.prepare();
|
||||
setupLights(l, 8);
|
||||
|
||||
|
||||
/*fbo_c.bind();
|
||||
glClearFramebuffer();
|
||||
//shader->bind(); /// WARNING
|
||||
renderObjects(GLObjectBase::Solid, l, 0, true, view.isLightEnabled(), view.isFogEnabled());
|
||||
//shader->release(); /// WARNING
|
||||
if (QRect(QPoint(), fbo_c.size()).contains(mpos)) {
|
||||
//qDebug() << mpos;
|
||||
GLfloat data[4] = {0, 0, 0, 0};
|
||||
glReadPixels(mpos.x(), fbo_c.height() - mpos.y(), 1, 1, GL_RGBA, GL_FLOAT, data);
|
||||
//qDebug() << QVector3D(data[0], data[1], data[2]);
|
||||
}
|
||||
fbo_c.release();*/
|
||||
//qDebug() << rp.viewproj_matrix << (getGLMatrix(GL_PROJECTION_MATRIX)*getGLMatrix(GL_MODELVIEW_MATRIX));
|
||||
renderObjects(GLObjectBase::Solid, l, nullptr, true, view.isLightEnabled(), view.isFogEnabled());
|
||||
|
||||
|
||||
//renderObjects(GLObjectBase::Solid, l, 0, true, true, view.isFogEnabled());
|
||||
renderObjects(GLObjectBase::Transparent, l, nullptr, true, true, view.isFogEnabled());
|
||||
if (passes > 1) {
|
||||
glSetLightEnabled(false);
|
||||
glSetCapEnabled(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
view.glReleaseTextures();
|
||||
glBindTexture(GL_TEXTURE_2D, fbo.colorTexture(1));
|
||||
glDisableDepth();
|
||||
fbo.setWriteBuffer(0);
|
||||
glDrawQuad();
|
||||
}
|
||||
}
|
||||
if (view.isFeatureEnabled(QGLView::qglFXAA) || passes > 1) {
|
||||
fbo.release();
|
||||
//glClearFramebuffer();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo.colorTexture());
|
||||
glSetLightEnabled(false);
|
||||
glSetCapEnabled(GL_BLEND, false);
|
||||
glDisableDepth();
|
||||
if (view.isFeatureEnabled(QGLView::qglFXAA)) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
shader_fxaa->bind();
|
||||
shader_fxaa->setUniformValue("dt", QVector2D(1.f / view.width(), 1.f / view.height()));
|
||||
glDrawQuad();
|
||||
shader_fxaa->release();
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glDrawQuad();
|
||||
}
|
||||
}
|
||||
}
|
||||
47
test/qglview/renderer_simple.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
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_SIMPLE_H
|
||||
#define RENDERER_SIMPLE_H
|
||||
|
||||
#include "qglview.h"
|
||||
|
||||
class RendererSimple: public GLRendererBase
|
||||
{
|
||||
public:
|
||||
RendererSimple(QGLView * view);
|
||||
virtual ~RendererSimple() {if (shader_fxaa != 0) delete shader_fxaa;}
|
||||
|
||||
virtual void renderScene();
|
||||
virtual void reloadShaders();
|
||||
virtual void init(int width, int height) {resizeFBO(width, height);}
|
||||
virtual void resize(int width, int height) {resizeFBO(width, height);}
|
||||
|
||||
QPoint mpos;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
void resizeFBO(int w, int h);
|
||||
|
||||
GLFramebuffer fbo, fbo_c;
|
||||
QOpenGLShaderProgram * shader_fxaa, * shader;
|
||||
|
||||
};
|
||||
|
||||
#endif // RENDERER_SIMPLE_H
|
||||
230
test/qglview/shaders/FXAA.frag
Normal file
@@ -0,0 +1,230 @@
|
||||
#version 130
|
||||
|
||||
in vec4 posPos;
|
||||
|
||||
uniform sampler2D tex0; // 0
|
||||
//uniform float vx_offset;
|
||||
uniform vec2 dt;
|
||||
uniform float FXAA_SPAN_MAX = 8.;
|
||||
uniform float FXAA_REDUCE_MUL = 1. / 8.;
|
||||
|
||||
#define FxaaInt2 ivec2
|
||||
//#define vec2 vec2
|
||||
|
||||
vec3 FxaaPixelShader(vec4 posPos, // Output of FxaaVertexShader interpolated across screen.
|
||||
sampler2D tex, // Input texture.
|
||||
vec2 rcpFrame) { // Constant {1.0/frameWidth, 1.0/frameHeight}.
|
||||
/*---------------------------------------------------------*/
|
||||
// #define FXAA_REDUCE_MIN (1. / 128.)
|
||||
#define FXAA_REDUCE_MIN (1. / 128.)
|
||||
//#define FXAA_REDUCE_MUL (1.0/8.0)
|
||||
//#define FXAA_SPAN_MAX 8.0
|
||||
/*---------------------------------------------------------*/
|
||||
vec3 rgbNW = texture2D(tex, posPos.zw).xyz;
|
||||
vec3 rgbNE = textureOffset(tex, posPos.zw, ivec2(1, 0)).xyz;
|
||||
vec3 rgbSW = textureOffset(tex, posPos.zw, ivec2(0, 1)).xyz;
|
||||
vec3 rgbSE = textureOffset(tex, posPos.zw, ivec2(1, 1)).xyz;
|
||||
vec3 rgbM = texture2D(tex, posPos.xy).xyz;
|
||||
/*---------------------------------------------------------*/
|
||||
vec3 luma = vec3(0.299, 0.587, 0.114);
|
||||
float lumaNW = dot(rgbNW, luma);
|
||||
float lumaNE = dot(rgbNE, luma);
|
||||
float lumaSW = dot(rgbSW, luma);
|
||||
float lumaSE = dot(rgbSE, luma);
|
||||
float lumaM = dot(rgbM, luma);
|
||||
/*---------------------------------------------------------*/
|
||||
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
|
||||
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
|
||||
/*---------------------------------------------------------*/
|
||||
vec2 dir;
|
||||
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
|
||||
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
|
||||
/*---------------------------------------------------------*/
|
||||
float dirReduce = max(
|
||||
(lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),
|
||||
FXAA_REDUCE_MIN);
|
||||
float rcpDirMin = 1. / (min(abs(dir.x), abs(dir.y)) + dirReduce);
|
||||
dir = min(vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),
|
||||
max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
|
||||
dir * rcpDirMin)) * rcpFrame.xy;
|
||||
/*--------------------------------------------------------*/
|
||||
vec3 rgbA = (1. / 2.) * (
|
||||
texture2D(tex, posPos.xy + dir * (1. / 3. - 0.5)).xyz +
|
||||
texture2D(tex, posPos.xy + dir * (2. / 3. - 0.5)).xyz);
|
||||
vec3 rgbB = rgbA * (1. / 2.) + (1. / 4.) * (
|
||||
texture2D(tex, posPos.xy + dir * (0. / 3. - 0.5)).xyz +
|
||||
texture2D(tex, posPos.xy + dir * (3. / 3. - 0.5)).xyz);
|
||||
float lumaB = dot(rgbB, luma);
|
||||
if ((lumaB < lumaMin) || (lumaB > lumaMax)) return rgbA;
|
||||
return rgbB;
|
||||
}
|
||||
|
||||
|
||||
vec3 Fxaa3PixelShader (
|
||||
// {xy} = center of pixel
|
||||
vec4 pos,
|
||||
// {xyzw} = not used on FXAA3 Quality
|
||||
//vec4 posPos,
|
||||
// {rgb_} = color in linear or perceptual color space
|
||||
// {__a} = luma in perceptual color space (not linear)
|
||||
sampler2D tex,
|
||||
// This must be from a constant/uniform.
|
||||
// {x_} = 1.0/screenWidthInPixels
|
||||
// {_y} = 1.0/screenHeightInPixels
|
||||
vec2 rcpFrame
|
||||
// {xyzw} = not used on FXAA3 Quality
|
||||
//vec4 rcpFrameOpt
|
||||
) {
|
||||
/*--------------------------------------------------------------------------*/
|
||||
//#if (FXAA_GATHER4_ALPHA == 1)
|
||||
/*vec4 luma4A = FxaaTexOffAlpha4(tex, pos.xy, FxaaInt2(-1, -1), rcpFrame.xy);
|
||||
#if (FXAA_DISCARD == 0)
|
||||
vec4 rgbyM = texture2D(tex, pos.xy);
|
||||
#endif
|
||||
vec4 luma4B = FxaaTexAlpha4(tex, pos.xy, rcpFrame.xy);
|
||||
float lumaNE = textureOffset(tex, pos.xy, ivec(1, -1)).w;
|
||||
float lumaSW = textureOffset(tex, pos.xy, ivec(-1, 1)).w;
|
||||
float lumaNW = luma4A.w;
|
||||
float lumaN = luma4A.z;
|
||||
float lumaW = luma4A.x;
|
||||
float lumaM = luma4A.y;
|
||||
float lumaE = luma4B.z;
|
||||
float lumaS = luma4B.x;
|
||||
float lumaSE = luma4B.y;*/
|
||||
//#else
|
||||
vec3 luma = vec3(0.299, 0.587, 0.114);
|
||||
float lumaN = dot(textureLodOffset(tex, pos.xy, 0., ivec2(0, -1)).rgb, luma);
|
||||
float lumaW = dot(textureLodOffset(tex, pos.xy, 0., ivec2(-1, 0)).rgb, luma);
|
||||
vec4 rgbyM = texture2D(tex, pos.xy);
|
||||
float lumaE = dot(textureLodOffset(tex, pos.xy, 0., ivec2( 1, 0)).rgb, luma);
|
||||
float lumaS = dot(textureLodOffset(tex, pos.xy, 0., ivec2( 0, 1)).rgb, luma);
|
||||
float lumaM = dot(rgbyM.rgb, luma);
|
||||
//#endif
|
||||
/*--------------------------------------------------------------------------*/
|
||||
float rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE)));
|
||||
float rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE)));
|
||||
float range = rangeMax - rangeMin;
|
||||
//return vec4(range);
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/12.0)
|
||||
#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/6.0)
|
||||
if(range < max(FXAA_QUALITY_EDGE_THRESHOLD_MIN, rangeMax * FXAA_QUALITY_EDGE_THRESHOLD))
|
||||
/*#if (FXAA_DISCARD == 1)
|
||||
FxaaDiscard;
|
||||
#else*/
|
||||
return rgbyM.rgb;
|
||||
//return vec3(0);
|
||||
//#endif
|
||||
/*--------------------------------------------------------------------------*/
|
||||
//#if (FXAA_GATHER4_ALPHA == 0)
|
||||
float lumaNW = dot(textureLodOffset(tex, pos.xy, 0., ivec2(-1,-1)).rgb, luma);
|
||||
float lumaNE = dot(textureLodOffset(tex, pos.xy, 0., ivec2( 1,-1)).rgb, luma);
|
||||
float lumaSW = dot(textureLodOffset(tex, pos.xy, 0., ivec2(-1, 1)).rgb, luma);
|
||||
float lumaSE = dot(textureLodOffset(tex, pos.xy, 0., ivec2( 1, 1)).rgb, luma);
|
||||
//#endif
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define FXAA_QUALITY_SUBPIX_CAP (3.0/4.0)
|
||||
//#define FXAA_QUALITY_SUBPIX_CAP 0
|
||||
#define FXAA_QUALITY_SUBPIX_TRIM (1.0/4.0)
|
||||
#define FXAA_QUALITY_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_QUALITY_SUBPIX_TRIM))
|
||||
/*--------------------------------------------------------------------------*/
|
||||
float lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25;
|
||||
float rangeL = abs(lumaL - lumaM);
|
||||
float blendL = clamp((rangeL / range) - FXAA_QUALITY_SUBPIX_TRIM, 0., 1.) * FXAA_QUALITY_SUBPIX_TRIM_SCALE;
|
||||
blendL = min(FXAA_QUALITY_SUBPIX_CAP, blendL);
|
||||
/*--------------------------------------------------------------------------*/
|
||||
float edgeVert =
|
||||
abs(lumaNW + (-2.0 * lumaN) + lumaNE) +
|
||||
10.0 * abs(lumaW + (-2.0 * lumaM) + lumaE ) +
|
||||
abs(lumaSW + (-2.0 * lumaS) + lumaSE);
|
||||
float edgeHorz =
|
||||
abs(lumaNW + (-2.0 * lumaW) + lumaSW) +
|
||||
10.0 * abs(lumaN + (-2.0 * lumaM) + lumaS ) +
|
||||
abs(lumaNE + (-2.0 * lumaE) + lumaSE);
|
||||
//return vec3(edgeHorz);
|
||||
//float edgeVert = abs(lumaS - lumaN);
|
||||
//float edgeHorz = abs(lumaE - lumaW);
|
||||
bool horzSpan = edgeHorz >= edgeVert;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
float lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x;
|
||||
//if (edgeHorz == edgeVert) ;//lengthSign = 0.;
|
||||
if(!horzSpan) {
|
||||
lumaN = lumaW;
|
||||
lumaS = lumaE;
|
||||
}
|
||||
float gradientN = abs(lumaN - lumaM);
|
||||
float gradientS = abs(lumaS - lumaM);
|
||||
lumaN = (lumaN + lumaM) * 0.5;
|
||||
lumaS = (lumaS + lumaM) * 0.5;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
bool pairN = gradientN >= gradientS;
|
||||
if(!pairN) {
|
||||
lumaN = lumaS;
|
||||
gradientN = gradientS;
|
||||
lengthSign = -lengthSign;
|
||||
}
|
||||
vec2 posN;
|
||||
posN = pos.xy + (horzSpan ? vec2(0.0, lengthSign * 0.5) : vec2(lengthSign * 0.5, 0.0));
|
||||
//posN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5);
|
||||
//posN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0);
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define FXAA_SEARCH_STEPS 8
|
||||
#define FXAA_SEARCH_THRESHOLD (1.0/8.0)
|
||||
/*--------------------------------------------------------------------------*/
|
||||
gradientN *= FXAA_SEARCH_THRESHOLD;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
vec2 posP = posN;
|
||||
vec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y);
|
||||
float lumaEndN = 0.;
|
||||
float lumaEndP = 0.;
|
||||
bool doneN = false;
|
||||
bool doneP = false;
|
||||
posN += offNP * (-1.5);
|
||||
posP += offNP * ( 1.5);
|
||||
for(int i = 0; i < FXAA_SEARCH_STEPS; i++) {
|
||||
lumaEndN = dot(texture2DLod(tex, posN.xy, 0.).rgb, luma);
|
||||
lumaEndP = dot(texture2DLod(tex, posP.xy, 0.).rgb, luma);
|
||||
bool doneN2 = abs(lumaEndN - lumaN) >= gradientN;
|
||||
bool doneP2 = abs(lumaEndP - lumaN) >= gradientN;
|
||||
if(doneN2 && !doneN) posN += offNP;
|
||||
if(doneP2 && !doneP) posP -= offNP;
|
||||
if(doneN2 && doneP2) break;
|
||||
doneN = doneN2;
|
||||
doneP = doneP2;
|
||||
if(!doneN) posN -= offNP * 2.0;
|
||||
if(!doneP) posP += offNP * 2.0;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
float dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y;
|
||||
float dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
bool directionN = dstN < dstP;
|
||||
lumaEndN = directionN ? lumaEndN : lumaEndP;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
if(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0))
|
||||
lengthSign = 0.0;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
float spanLength = (dstP + dstN);
|
||||
dstN = directionN ? dstN : dstP;
|
||||
float subPixelOffset = 0.5 + (dstN * (-1.0/spanLength));
|
||||
subPixelOffset += blendL * (1.0/8.0);
|
||||
subPixelOffset *= lengthSign;
|
||||
vec3 rgbF = texture2DLod(tex, pos.xy + (horzSpan ? vec2(0., subPixelOffset) : vec2(subPixelOffset, 0.)), 0.).xyz;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*#if (FXAA_LINEAR == 1)
|
||||
lumaL *= lumaL;
|
||||
#endif*/
|
||||
float lumaF = dot(rgbF, vec3(0.299, 0.587, 0.114)) + (1.0/(65536.0*256.0));
|
||||
float lumaB = mix(lumaF, lumaL, blendL);
|
||||
float scale = min(4.0, lumaB/lumaF);
|
||||
rgbF *= scale;
|
||||
return vec3(rgbF);//, lumaM.rgb);
|
||||
//, lumaM.rgb);
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
gl_FragColor.rgb = Fxaa3PixelShader(posPos, tex0, dt);
|
||||
}
|
||||
|
||||
|
||||
13
test/qglview/shaders/FXAA.vert
Normal file
@@ -0,0 +1,13 @@
|
||||
#version 130
|
||||
|
||||
out vec4 posPos;
|
||||
|
||||
uniform float FXAA_SUBPIX_SHIFT = 1. / 4.;
|
||||
uniform vec2 dt;
|
||||
|
||||
void main(void) {
|
||||
posPos.xy = gl_MultiTexCoord0.xy;
|
||||
posPos.zw = gl_MultiTexCoord0.xy - (dt * (0.5 + FXAA_SUBPIX_SHIFT));
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
gl_Position = ftransform();
|
||||
}
|
||||
8
test/qglview/shaders/bloom_0.frag
Normal file
@@ -0,0 +1,8 @@
|
||||
#version 120
|
||||
|
||||
uniform sampler2D t0;
|
||||
uniform float clum;
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = max((texture2D(t0, gl_TexCoord[0].xy) / clum - 0.8) * 5., vec4(0.));
|
||||
}
|
||||
30
test/qglview/shaders/bloom_1.frag
Normal file
@@ -0,0 +1,30 @@
|
||||
#version 130
|
||||
|
||||
uniform sampler2D t0;
|
||||
uniform vec2 vsize;
|
||||
|
||||
void main(void) {
|
||||
vec2 tc = gl_TexCoord[0].xy, dt = 2. / vsize, dt2 = dt + dt;
|
||||
gl_FragColor = (texture2D(t0, tc) * 3. +
|
||||
textureOffset(t0, tc, ivec2(1, 0)) * 2. +
|
||||
textureOffset(t0, tc, ivec2(0, 1)) * 2. +
|
||||
textureOffset(t0, tc, ivec2(-1, 0)) * 2. +
|
||||
textureOffset(t0, tc, ivec2(0, -1)) * 2. +
|
||||
textureOffset(t0, tc, ivec2(1, 1)) * 1.5 +
|
||||
textureOffset(t0, tc, ivec2(1, -1)) * 1.5 +
|
||||
textureOffset(t0, tc, ivec2(-1, -1)) * 1.5 +
|
||||
textureOffset(t0, tc, ivec2(-1, 1)) * 1.5 +
|
||||
textureOffset(t0, tc, ivec2(2, 0)) +
|
||||
textureOffset(t0, tc, ivec2(0, 2)) +
|
||||
textureOffset(t0, tc, ivec2(-2, 0)) +
|
||||
textureOffset(t0, tc, ivec2(0, -2)) +
|
||||
textureOffset(t0, tc, ivec2(2, 1)) +
|
||||
textureOffset(t0, tc, ivec2(2, -1)) +
|
||||
textureOffset(t0, tc, ivec2(-2, -1)) +
|
||||
textureOffset(t0, tc, ivec2(-2, 1)) +
|
||||
textureOffset(t0, tc, ivec2(1, 2)) +
|
||||
textureOffset(t0, tc, ivec2(1, -2)) +
|
||||
textureOffset(t0, tc, ivec2(-1, -2)) +
|
||||
textureOffset(t0, tc, ivec2(-1, 2))) / 29.;
|
||||
//gl_FragColor = texture2D(t0, tc);
|
||||
}
|
||||
8
test/qglview/shaders/bloom_pass_0.frag
Normal file
@@ -0,0 +1,8 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D t0;
|
||||
uniform float factor = 1., threshold = 0.8;
|
||||
|
||||
void main(void) {
|
||||
qgl_FragData[0].rgb = max(texelFetch(t0, ivec2(gl_FragCoord.xy), 0).rgb - vec3(threshold), vec3(0.)) * factor;
|
||||
}
|
||||
6
test/qglview/shaders/bloom_pass_0.vert
Normal file
@@ -0,0 +1,6 @@
|
||||
#version 150
|
||||
|
||||
void main(void) {
|
||||
qgl_FragTexture = qgl_Texture;
|
||||
gl_Position = qgl_ftransform();
|
||||
}
|
||||
55
test/qglview/shaders/bloom_pass_1.frag
Normal file
@@ -0,0 +1,55 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D t0;
|
||||
uniform int radius = 2;
|
||||
uniform vec2 dt;
|
||||
|
||||
void main(void) {
|
||||
vec2 tc = qgl_FragTexture.xy;
|
||||
float r = float(radius);
|
||||
int o = radius, o2 = radius * 2;
|
||||
vec3 scol = (texture(t0, tc).rgb * 3. +
|
||||
texture(t0, tc + dt * vec2( o, 0 )).rgb * 2. +
|
||||
texture(t0, tc + dt * vec2( 0, o )).rgb * 2. +
|
||||
texture(t0, tc + dt * vec2( -o, 0 )).rgb * 2. +
|
||||
texture(t0, tc + dt * vec2( 0, -o)).rgb * 2. +
|
||||
texture(t0, tc + dt * vec2( o, o )).rgb * 1.5 +
|
||||
texture(t0, tc + dt * vec2( o, -o)).rgb * 1.5 +
|
||||
texture(t0, tc + dt * vec2( -o, -o )).rgb * 1.5 +
|
||||
texture(t0, tc + dt * vec2( -o, o )).rgb * 1.5 +
|
||||
texture(t0, tc + dt * vec2( o2, 0 )).rgb +
|
||||
texture(t0, tc + dt * vec2( 0, o2)).rgb +
|
||||
texture(t0, tc + dt * vec2(-o2, 0 )).rgb +
|
||||
texture(t0, tc + dt * vec2( 0, -o2)).rgb +
|
||||
texture(t0, tc + dt * vec2( o2, o )).rgb +
|
||||
texture(t0, tc + dt * vec2( o2, -o)).rgb +
|
||||
texture(t0, tc + dt * vec2(-o2, -o )).rgb +
|
||||
texture(t0, tc + dt * vec2(-o2, o )).rgb +
|
||||
texture(t0, tc + dt * vec2( o, o2)).rgb +
|
||||
texture(t0, tc + dt * vec2( o, -o2)).rgb +
|
||||
texture(t0, tc + dt * vec2( -o, -o2)).rgb +
|
||||
texture(t0, tc + dt * vec2( -o, o2)).rgb) / 29.;
|
||||
/*vec3 scol = (texelFetch(t0, tc, 0).rgb * 3. +
|
||||
texelFetch(t0, tc + ivec2( o, 0 ), 0).rgb * 2. +
|
||||
texelFetch(t0, tc + ivec2( 0, o ), 0).rgb * 2. +
|
||||
texelFetch(t0, tc + ivec2( -o, 0 ), 0).rgb * 2. +
|
||||
texelFetch(t0, tc + ivec2( 0, -o), 0).rgb * 2. +
|
||||
texelFetch(t0, tc + ivec2( o, o ), 0).rgb * 1.5 +
|
||||
texelFetch(t0, tc + ivec2( o, -o), 0).rgb * 1.5 +
|
||||
texelFetch(t0, tc + ivec2( -o, -o ), 0).rgb * 1.5 +
|
||||
texelFetch(t0, tc + ivec2( -o, o ), 0).rgb * 1.5 +
|
||||
texelFetch(t0, tc + ivec2( o2, 0 ), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2( 0, o2), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2(-o2, 0 ), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2( 0, -o2), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2( o2, o ), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2( o2, -o), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2(-o2, -o ), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2(-o2, o ), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2( o, o2), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2( o, -o2), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2( -o, -o2), 0).rgb +
|
||||
texelFetch(t0, tc + ivec2( -o, o2), 0).rgb) / 29.;*/
|
||||
qgl_FragData[0].rgb = scol;
|
||||
//qgl_FragData[0].rgb = vec3(r/10.);
|
||||
}
|
||||