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

This commit is contained in:
2019-09-02 14:08:38 +00:00
parent f862381b68
commit 3d06d2095e
929 changed files with 66799 additions and 0 deletions

View 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
View 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
View 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

View 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);
}

View 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
View 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
View 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
View 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
View 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

View 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);
}

View 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

View 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>

View 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);
}

View 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

View 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();
}

View 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

View 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());
}

View File

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

View File

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

View File

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

BIN
test/qglview/icons/item.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

BIN
test/qglview/icons/node.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

348
test/qglview/loader_3ds.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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

View 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();
}

View 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

View 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>

View 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();
}

View File

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

View 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>

View File

@@ -0,0 +1,95 @@
#include "openglwindow.h"
#include <QCoreApplication>
#include <QOpenGLContext>
#include <QOpenGLPaintDevice>
#include <QPainter>
OpenGLWindow::OpenGLWindow(QWindow *parent)
: QWindow(parent)
, m_context(nullptr)
, m_device(nullptr)
{
setFlag(Qt::FramelessWindowHint);
setSurfaceType(QWindow::OpenGLSurface);
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
// qDebug() << format;
#ifdef QT_OPENGL_ES_2
format.setRenderableType(QSurfaceFormat::OpenGLES);
#else
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
format.setVersion(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);
}

View 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;
};

View 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)

View File

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

View File

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

View File

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

View File

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

View 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() {
}

View 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
View 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
View File

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

View File

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

View File

@@ -0,0 +1,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();
}
}

View 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

View 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>

View 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) {
}

View File

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

View 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();
}
}
}

View 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

View 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);
}

View 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();
}

View 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.));
}

View 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);
}

View 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;
}

View File

@@ -0,0 +1,6 @@
#version 150
void main(void) {
qgl_FragTexture = qgl_Texture;
gl_Position = qgl_ftransform();
}

View 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.);
}

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