git-svn-id: svn://db.shs.com.ru/libs@637 a8b55f48-bf90-11e4-a774-851b48703e85
This commit is contained in:
87
qglengine/core/glbuffer.cpp
Normal file
87
qglengine/core/glbuffer.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include "glbuffer.h"
|
||||
|
||||
|
||||
Buffer::Buffer(GLenum target, GLenum _usage) {
|
||||
target_ = target;
|
||||
usage_ = _usage;
|
||||
buffer_ = 0;
|
||||
prev_size = 0;
|
||||
}
|
||||
|
||||
|
||||
Buffer::~Buffer() {
|
||||
}
|
||||
|
||||
|
||||
void Buffer::init(QOpenGLExtraFunctions * f) {
|
||||
if (!isInit()) {
|
||||
f->glGenBuffers(1, &buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Buffer::destroy(QOpenGLExtraFunctions * f) {
|
||||
if (buffer_ != 0) {
|
||||
f->glDeleteBuffers(1, &buffer_);
|
||||
}
|
||||
buffer_ = 0;
|
||||
}
|
||||
|
||||
|
||||
void Buffer::bind(QOpenGLExtraFunctions * f) {
|
||||
f->glBindBuffer(target_, buffer_);
|
||||
}
|
||||
|
||||
|
||||
void Buffer::release(QOpenGLExtraFunctions * f) {
|
||||
f->glBindBuffer(target_, 0);
|
||||
}
|
||||
|
||||
|
||||
void * Buffer::map(QOpenGLExtraFunctions * f, GLbitfield mode, int size) {
|
||||
if (size < 0) size = prev_size;
|
||||
return f->glMapBufferRange(target_, 0, size, mode);
|
||||
}
|
||||
|
||||
|
||||
void Buffer::unmap(QOpenGLExtraFunctions * f) {
|
||||
f->glUnmapBuffer(target_);
|
||||
}
|
||||
|
||||
|
||||
bool Buffer::resize(QOpenGLExtraFunctions * f, int new_size) {
|
||||
if (new_size <= 0) return false;
|
||||
//qDebug() << "check resize buffer" << buffer_ << "bytes" << new_size << ", old =" << prev_size;
|
||||
if (new_size <= prev_size) return false;
|
||||
prev_size = new_size;
|
||||
//qDebug() << "resize buffer " << buffer_ << target_ << "for" << new_size << "bytes";
|
||||
f->glBufferData(target_, new_size, 0, usage_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Buffer::load(QOpenGLExtraFunctions * f, const void * data, int size, int offset) {
|
||||
if (!data || size <= 0) return;
|
||||
//qDebug() << "load buffer" << buffer_ << "bytes" << size;
|
||||
f->glBufferSubData(target_, offset, size, data);
|
||||
}
|
||||
56
qglengine/core/glbuffer.h
Normal file
56
qglengine/core/glbuffer.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLBUFFER_H
|
||||
#define GLBUFFER_H
|
||||
|
||||
#include "gltypes.h"
|
||||
|
||||
|
||||
class Buffer
|
||||
{
|
||||
friend class ObjectBase;
|
||||
public:
|
||||
Buffer(GLenum target, GLenum usage = GL_DYNAMIC_DRAW);
|
||||
~Buffer();
|
||||
|
||||
void init (QOpenGLExtraFunctions * f);
|
||||
void destroy (QOpenGLExtraFunctions * f);
|
||||
|
||||
void bind (QOpenGLExtraFunctions * f);
|
||||
void release (QOpenGLExtraFunctions * f);
|
||||
void * map (QOpenGLExtraFunctions * f, GLbitfield mode, int size = -1);
|
||||
void unmap (QOpenGLExtraFunctions * f);
|
||||
|
||||
// returns true if size changed
|
||||
bool resize (QOpenGLExtraFunctions * f, int new_size);
|
||||
void load (QOpenGLExtraFunctions * f, const void * data, int size, int offset = 0);
|
||||
|
||||
GLuint ID() const {return buffer_;}
|
||||
GLenum usage() const {return usage_;}
|
||||
bool isInit() const {return buffer_ != 0;}
|
||||
|
||||
private:
|
||||
GLenum target_, usage_;
|
||||
GLuint buffer_;
|
||||
int prev_size;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // GLBUFFER_H
|
||||
309
qglengine/core/glframebuffer.cpp
Normal file
309
qglengine/core/glframebuffer.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include "glframebuffer.h"
|
||||
#include <QTime>
|
||||
|
||||
|
||||
Framebuffer::Framebuffer(QOpenGLExtraFunctions * f_, int colorAttachments_, bool withDepth, GLenum colorFormat_, GLenum _target): f(f_),
|
||||
pbo(GL_PIXEL_PACK_BUFFER, GL_STREAM_DRAW) {
|
||||
is_depth = withDepth;
|
||||
target_ = _target;
|
||||
color_formats.fill(colorFormat_, colorAttachments_);
|
||||
colors.fill(0, colorAttachments_);
|
||||
fbo = drbo = 0;
|
||||
tex_d = 0;
|
||||
wid = hei = 0;
|
||||
pbo_queried = 0;
|
||||
is_changed = false;
|
||||
}
|
||||
|
||||
|
||||
Framebuffer::Framebuffer(QOpenGLExtraFunctions * f_, QVector<GLenum> colors_, bool withDepth, GLenum _target): f(f_),
|
||||
pbo(GL_PIXEL_PACK_BUFFER, GL_STREAM_DRAW) {
|
||||
is_depth = withDepth;
|
||||
target_ = _target;
|
||||
color_formats = colors_;
|
||||
colors.fill(0, colors_.size());
|
||||
fbo = drbo = 0;
|
||||
tex_d = 0;
|
||||
wid = hei = 0;
|
||||
pbo_queried = 0;
|
||||
is_changed = false;
|
||||
}
|
||||
|
||||
|
||||
Framebuffer::~Framebuffer() {
|
||||
deleteGLFramebuffer(fbo);
|
||||
deleteGLRenderbuffer(drbo);
|
||||
for (int i = 0; i < colors.size(); ++i)
|
||||
deleteGLTexture(f, colors[i]);
|
||||
deleteGLTexture(f, tex_d);
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::resize(int width, int height, bool force) {
|
||||
if ((wid == width) && (hei == height) && !force) return;
|
||||
wid = width;
|
||||
hei = height;
|
||||
deleteGLFramebuffer(fbo);
|
||||
f->glGenFramebuffers(1, &fbo);
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
for (int i = 0; i < colors.size(); ++i) {
|
||||
deleteGLTexture(f, colors[i]);
|
||||
createGLTexture(f, colors[i], width, height, color_formats[i], target_);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, 4);
|
||||
//f->glTexParameteri(target_, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
|
||||
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, target_, colors[i], 0);
|
||||
}
|
||||
if (is_depth) {
|
||||
deleteGLTexture(f, tex_d);
|
||||
deleteGLRenderbuffer(drbo);
|
||||
f->glGenRenderbuffers(1, &drbo);
|
||||
f->glBindRenderbuffer(GL_RENDERBUFFER, drbo);
|
||||
f->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
|
||||
f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, drbo);
|
||||
createGLTexture(f, tex_d, width, height, GL_DEPTH_COMPONENT);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
//f->glTexParameteri(target_, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
|
||||
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target_, tex_d, 0);
|
||||
}
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
if (pbo.isInit()) {
|
||||
pbo.bind(f);
|
||||
pbo.resize(f, width*height*4);
|
||||
pbo.release(f);
|
||||
}
|
||||
is_changed = false;
|
||||
}
|
||||
|
||||
|
||||
QImage Framebuffer::grab() const {
|
||||
//glReadPixels(0, 0, wid, hei, GL_RGBA, );
|
||||
//QImage ret();
|
||||
return QImage();
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::queryPoint(int index, QPoint p) {
|
||||
pbo_queried = 0;
|
||||
if (index < 0 || index >= colors.size()) return;
|
||||
if (!rect().contains(p) || !pbo.isInit()) return;
|
||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index);
|
||||
//QTime tm; tm.restart();
|
||||
pbo.bind(f);
|
||||
f->glReadPixels(p.x(), height() - p.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
pbo_queried = 1;
|
||||
pbo.release(f);
|
||||
//qDebug() << tm.elapsed();
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::queryPoints(int index, QRect rect_) {
|
||||
pbo_queried = 0;
|
||||
if (index < 0 || index >= colors.size()) return;
|
||||
rect_ &= rect();
|
||||
if (rect_.isEmpty() || !pbo.isInit()) return;
|
||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index);
|
||||
//QTime tm; tm.restart();
|
||||
pbo.bind(f);
|
||||
f->glReadPixels(rect_.x(), height() - rect_.bottom(), rect_.width(), rect_.height(), GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
pbo_queried = rect_.width() * rect_.height();
|
||||
pbo.release(f);
|
||||
//qDebug() << tm.elapsed();
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::queryImage(int index) {
|
||||
queryPoints(index, rect());
|
||||
}
|
||||
|
||||
|
||||
uint Framebuffer::getPoint() const {
|
||||
if (!pbo.isInit() || (pbo_queried == 0)) return 0;
|
||||
//QTime tm; tm.restart();
|
||||
uint ret = 0;
|
||||
pbo.bind(f);
|
||||
//glClearError();
|
||||
void * map = pbo.map(f, GL_MAP_READ_BIT, sizeof(uint));
|
||||
//qDebug() << map << QString::number(glGetError(), 16);
|
||||
if (map)
|
||||
memcpy(&ret, map, sizeof(uint));
|
||||
pbo.unmap(f);
|
||||
pbo.release(f);
|
||||
//qDebug() << tm.elapsed();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QVector<uint> Framebuffer::getPoints() const {
|
||||
QVector<uint> ret;
|
||||
if (!pbo.isInit() || (pbo_queried == 0)) return ret;
|
||||
ret.resize(pbo_queried);
|
||||
//QTime tm; tm.restart();
|
||||
pbo.bind(f);
|
||||
//glClearError();
|
||||
void * map = pbo.map(f, GL_MAP_READ_BIT, pbo_queried * sizeof(uint));
|
||||
//qDebug() << map << QString::number(glGetError(), 16);
|
||||
if (map)
|
||||
memcpy(ret.data(), map, pbo_queried * sizeof(uint));
|
||||
pbo.unmap(f);
|
||||
pbo.release(f);
|
||||
//qDebug() << tm.elapsed();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QImage Framebuffer::getImage() const {
|
||||
QImage ret;
|
||||
if (!pbo.isInit() || (pbo_queried == 0)) return ret;
|
||||
ret = QImage(size(), QImage::Format_RGBA8888);
|
||||
int bytes = width() * height() * 4;
|
||||
//QTime tm; tm.restart();
|
||||
pbo.bind(f);
|
||||
//glClearError();
|
||||
void * map = pbo.map(f, GL_MAP_READ_BIT, bytes);
|
||||
//qDebug() << map << QString::number(glGetError(), 16);
|
||||
if (map)
|
||||
memcpy(ret.bits(), map, bytes);
|
||||
pbo.unmap(f);
|
||||
pbo.release(f);
|
||||
//qDebug() << tm.elapsed();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QVector<float> Framebuffer::grabF(int index) const {
|
||||
QVector<float> ret;
|
||||
if (index < 0 || index >= colors.size()) return ret;
|
||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index);
|
||||
ret.resize(wid * hei * 4);
|
||||
f->glReadPixels(0, 0, wid, hei, GL_RGBA, GL_FLOAT, ret.data());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::blit(int index_from, GLuint fb_to, int index_to, QRect from, QRect to, GLbitfield mask, GLenum filter) {
|
||||
if (index_from < 0 || index_from >= colors.size()) return;
|
||||
GLenum e = GL_COLOR_ATTACHMENT0 + index_to;
|
||||
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_to);
|
||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index_from);
|
||||
f->glDrawBuffers(1, &e);
|
||||
f->glBlitFramebuffer(from.x(), from.y(), from.right(), from.bottom(), to.x(), to.y(), to.right(), to.bottom(), mask, filter);
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::bind() {
|
||||
if (is_changed) resize(wid, hei);
|
||||
if (fbo == 0) return;
|
||||
//glFlush();
|
||||
f->glGetIntegerv(GL_VIEWPORT, prev_view);
|
||||
//glClearError();
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
//qDebug() << QString::number(glGetError(), 16);
|
||||
setWriteBuffers();
|
||||
f->glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
//f->glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
f->glViewport(0, 0, wid, hei);
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::release() {
|
||||
is_changed = false;
|
||||
if (fbo == 0) return;
|
||||
//glFlush();
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
f->glViewport(prev_view[0], prev_view[1], prev_view[2], prev_view[3]);
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::setWriteBuffer(int index) {
|
||||
//QVector<GLenum> buffers; buffers << GL_COLOR_ATTACHMENT0 + index;
|
||||
GLenum e = GL_COLOR_ATTACHMENT0 + index;
|
||||
f->glDrawBuffers(1, &e);
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::setWriteBuffers(int * indeces, int count) {
|
||||
QVector<GLenum> buffers;
|
||||
for (int i = 0; i < count; ++i)
|
||||
buffers << GL_COLOR_ATTACHMENT0 + indeces[i];
|
||||
f->glDrawBuffers(buffers.size(), buffers.constData());
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::setWriteBuffers() {
|
||||
QVector<GLenum> buffers;
|
||||
for (int i = 0; i < colors.size(); ++i)
|
||||
buffers << GL_COLOR_ATTACHMENT0 + i;
|
||||
f->glDrawBuffers(buffers.size(), buffers.constData());
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::enablePixelBuffer() {
|
||||
pbo.init(f);
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::bindColorTexture(int index, int channel) {
|
||||
if (index < 0 || index >= colors.size()) return;
|
||||
f->glActiveTexture(GL_TEXTURE0 + channel);
|
||||
f->glBindTexture(GL_TEXTURE_2D, colors[index]);
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::bindColorTextures() {
|
||||
for (int i = colors.size() - 1; i >= 0; --i) {
|
||||
f->glActiveTexture(GL_TEXTURE0 + i);
|
||||
f->glBindTexture(GL_TEXTURE_2D, colors[i]);
|
||||
//f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
//f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::bindDepthTexture(int channel) {
|
||||
f->glActiveTexture(GL_TEXTURE0 + channel);
|
||||
f->glBindTexture(GL_TEXTURE_2D, tex_d);
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::deleteGLRenderbuffer(GLuint & drbo) {
|
||||
if (drbo != 0)
|
||||
f->glDeleteRenderbuffers(1, &drbo);
|
||||
drbo = 0;
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::deleteGLFramebuffer(GLuint & fbo) {
|
||||
if (fbo != 0)
|
||||
f->glDeleteFramebuffers(1, &fbo);
|
||||
fbo = 0;
|
||||
}
|
||||
83
qglengine/core/glframebuffer.h
Normal file
83
qglengine/core/glframebuffer.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLFRAMEBUFFER_H
|
||||
#define GLFRAMEBUFFER_H
|
||||
|
||||
#include "glbuffer.h"
|
||||
|
||||
|
||||
class Framebuffer
|
||||
{
|
||||
public:
|
||||
Framebuffer(QOpenGLExtraFunctions * f_, int colorAttachments = 1, bool withDepth = true, GLenum colorFormat = GL_RGBA8, GLenum _target = GL_TEXTURE_2D);
|
||||
Framebuffer(QOpenGLExtraFunctions * f_, QVector<GLenum> colors_, bool withDepth = true, GLenum _target = GL_TEXTURE_2D);
|
||||
virtual ~Framebuffer();
|
||||
|
||||
GLuint id() const {return fbo;}
|
||||
GLuint colorTexture(int index = 0) const {return colors[index];}
|
||||
//GLenum colorFormat() const {return color_format;}
|
||||
GLuint depthTexture() const {return tex_d;}
|
||||
GLenum target() const {return target_;}
|
||||
int width() const {return wid;}
|
||||
int height() const {return hei;}
|
||||
QSize size() const {return QSize(wid, hei);}
|
||||
QRect rect() const {return QRect(0, 0, wid, hei);}
|
||||
QImage grab() const;
|
||||
QVector<float> grabF(int index) const;
|
||||
void queryPoint(int index, QPoint p);
|
||||
void queryPoints(int index, QRect rect);
|
||||
void queryImage(int index);
|
||||
uint getPoint() const;
|
||||
QVector<uint> getPoints() const;
|
||||
QImage getImage() const;
|
||||
int queriedPoints() const {return pbo_queried;}
|
||||
void blit(int index_from, GLuint fb_to, int index_to, QRect from, QRect to, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_NEAREST );
|
||||
|
||||
void resize(int width, int height, bool force = false);
|
||||
void bind();
|
||||
void release();
|
||||
void setReadBuffer(int index) {glReadBuffer(GL_COLOR_ATTACHMENT0 + index);}
|
||||
void setWriteBuffer(int index);
|
||||
void setWriteBuffers(int * indeces, int count);
|
||||
void setWriteBuffers();
|
||||
//void setColorFormat(GLenum format) {color_format = format; is_changed = true;}
|
||||
void enablePixelBuffer();
|
||||
|
||||
void copyDepthFrom(GLuint tex) {;}
|
||||
void bindColorTexture(int index, int channel = 0);
|
||||
void bindColorTextures();
|
||||
void bindDepthTexture(int channel);
|
||||
|
||||
private:
|
||||
void deleteGLRenderbuffer(GLuint & drbo);
|
||||
void deleteGLFramebuffer(GLuint & fbo);
|
||||
|
||||
bool is_depth, is_changed;
|
||||
int pbo_queried;
|
||||
QOpenGLExtraFunctions * f;
|
||||
mutable Buffer pbo;
|
||||
QVector<GLuint> colors;
|
||||
QVector<GLenum> color_formats;
|
||||
GLenum target_;
|
||||
GLuint fbo, drbo, tex_d;
|
||||
GLint prev_view[4], wid, hei;
|
||||
|
||||
};
|
||||
|
||||
#endif // GLFRAMEBUFFER_H
|
||||
200
qglengine/core/glmaterial.cpp
Normal file
200
qglengine/core/glmaterial.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gltypes.h"
|
||||
#include "gltexture_manager.h"
|
||||
#include "qglview.h"
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
/*
|
||||
bool CubeTexture::create() {
|
||||
//qDebug("create");
|
||||
destroy();
|
||||
glGenTextures(1, &id_);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, id_);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
//glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
|
||||
//glClearError();
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
//qDebug() << glGetError();
|
||||
changed_ = false;
|
||||
return id_ > 0;
|
||||
}
|
||||
|
||||
|
||||
void CubeTexture::load() {
|
||||
if (isEmpty()) return;
|
||||
create();
|
||||
if (!path(0).isEmpty()) loadFront(path(0));
|
||||
if (!path(1).isEmpty()) loadBack(path(1));
|
||||
if (!path(2).isEmpty()) loadLeft(path(2));
|
||||
if (!path(3).isEmpty()) loadRight(path(3));
|
||||
if (!path(4).isEmpty()) loadTop(path(4));
|
||||
if (!path(5).isEmpty()) loadBottom(path(5));
|
||||
}
|
||||
|
||||
|
||||
void CubeTexture::loadFromDirectory(const QString & dir) {
|
||||
QDir d(dir); QFileInfoList sl;
|
||||
sl = d.entryInfoList(QStringList("front.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadFront(sl[0].absoluteFilePath());
|
||||
sl = d.entryInfoList(QStringList("back.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadBack(sl[0].absoluteFilePath());
|
||||
sl = d.entryInfoList(QStringList("left.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadLeft(sl[0].absoluteFilePath());
|
||||
sl = d.entryInfoList(QStringList("right.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadRight(sl[0].absoluteFilePath());
|
||||
sl = d.entryInfoList(QStringList("top.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadTop(sl[0].absoluteFilePath());
|
||||
sl = d.entryInfoList(QStringList("bottom.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadBottom(sl[0].absoluteFilePath());
|
||||
}
|
||||
|
||||
|
||||
void CubeTexture::loadPathesFromDirectory(const QString & dir) {
|
||||
QDir d(dir); QFileInfoList sl;
|
||||
sl = d.entryInfoList(QStringList("front.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[0] = sl[0].absoluteFilePath();
|
||||
sl = d.entryInfoList(QStringList("back.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[1] = sl[0].absoluteFilePath();
|
||||
sl = d.entryInfoList(QStringList("left.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[2] = sl[0].absoluteFilePath();
|
||||
sl = d.entryInfoList(QStringList("right.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[3] = sl[0].absoluteFilePath();
|
||||
sl = d.entryInfoList(QStringList("top.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[4] = sl[0].absoluteFilePath();
|
||||
sl = d.entryInfoList(QStringList("bottom.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[5] = sl[0].absoluteFilePath();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Map::Map() {
|
||||
bitmap_id = 0;
|
||||
color_amount = 1.f;
|
||||
color_offset = 0.f;
|
||||
bitmap_scale = QPointF(1., 1.);
|
||||
_changed = true;
|
||||
_layer = 0;
|
||||
}
|
||||
|
||||
|
||||
void Map::setBitmapPath(const QString & p) {
|
||||
bitmap_path = p;
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
|
||||
void Map::load(TextureManager * tm) {
|
||||
if (bitmap_id == 0)
|
||||
bitmap_id = tm->loadTexture(bitmap_path, true, _type == mtNormal);
|
||||
}
|
||||
|
||||
|
||||
void Map::copyToQGLMap(QGLMap & m) const {
|
||||
m.amount = color_amount;
|
||||
m.offset = color_offset;
|
||||
m.scale = QVector2D(bitmap_scale);
|
||||
if (hasBitmap()) {
|
||||
m.array_index = tarMaps;
|
||||
m.map_index = _layer;
|
||||
} else {
|
||||
m.array_index = tarEmpty;
|
||||
m.map_index = (_type == mtNormal ? emrBlue : emrWhite);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Material::Material(const QString _name)/*: map_reflection(512)*/ {
|
||||
setTypes();
|
||||
name = _name;
|
||||
color_diffuse = color_specular = Qt::darkGray;
|
||||
color_emission = Qt::black;
|
||||
glass = false;
|
||||
transparency = reflectivity = 0.f;
|
||||
map_roughness.color_amount = 0.75f;
|
||||
map_specular.color_amount = 1.f;
|
||||
iof = 1.f;
|
||||
dispersion = 0.05f;
|
||||
_changed = true;
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
|
||||
uint Material::hash() {
|
||||
return qHash(name);
|
||||
}
|
||||
|
||||
|
||||
bool Material::hasTransparency() const {
|
||||
return float(color_diffuse.alphaF()) * (1.f - transparency) < 1.f;
|
||||
}
|
||||
|
||||
|
||||
bool Material::isMapsChanged() const {
|
||||
return map_diffuse ._changed ||
|
||||
map_normal ._changed ||
|
||||
map_specular ._changed ||
|
||||
map_roughness._changed ||
|
||||
map_emission ._changed ||
|
||||
map_relief ._changed;
|
||||
}
|
||||
|
||||
|
||||
bool Material::isMapChanged(int type) const {
|
||||
switch (type) {
|
||||
case mtDiffuse : return map_diffuse ._changed;
|
||||
case mtNormal : return map_normal ._changed;
|
||||
case mtSpecular : return map_specular ._changed;
|
||||
case mtRoughness: return map_roughness._changed;
|
||||
case mtEmission : return map_emission ._changed;
|
||||
case mtRelief : return map_relief ._changed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Material::load(TextureManager * tm) {
|
||||
map_diffuse .load(tm);
|
||||
map_normal .load(tm);
|
||||
map_specular .load(tm);
|
||||
map_roughness.load(tm);
|
||||
map_emission .load(tm);
|
||||
map_relief .load(tm);
|
||||
}
|
||||
|
||||
|
||||
void Material::setMapsChanged() {
|
||||
map_diffuse ._changed = true;
|
||||
map_normal ._changed = true;
|
||||
map_specular ._changed = true;
|
||||
map_roughness._changed = true;
|
||||
map_emission ._changed = true;
|
||||
map_relief ._changed = true;
|
||||
}
|
||||
|
||||
|
||||
void Material::setTypes() {
|
||||
map_diffuse ._type = mtDiffuse;
|
||||
map_normal ._type = mtNormal;
|
||||
map_specular ._type = mtSpecular;
|
||||
map_roughness._type = mtRoughness;
|
||||
map_emission ._type = mtEmission;
|
||||
map_relief ._type = mtRelief;
|
||||
}
|
||||
173
qglengine/core/glmaterial.h
Normal file
173
qglengine/core/glmaterial.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLMATERIAL_H
|
||||
#define GLMATERIAL_H
|
||||
|
||||
#include "glshaders_types.h"
|
||||
#include "chunkstream.h"
|
||||
|
||||
/*
|
||||
class Texture {
|
||||
public:
|
||||
Texture(int _width, int _height, const GLenum & _format = GL_RGBA8, const GLenum & _target = GL_TEXTURE_2D) {wid = _width; hei = _height; format_ = _format; target_ = _target; id_ = 0;}
|
||||
bool create() {destroy(); createGLTexture(id_, wid, hei, format_, target_); return id_ > 0;}
|
||||
void destroy() {if (id_ > 0) glDeleteTextures(1, &id_); id_ = 0;}
|
||||
void bind() {if (id_ > 0) glBindTexture(target_, id_);}
|
||||
void release() {glBindTexture(target_, 0);}
|
||||
int width() const {return wid;}
|
||||
int height() const {return hei;}
|
||||
GLenum format() const {return format_;}
|
||||
GLenum target() const {return target_;}
|
||||
GLuint id() const {return id_;}
|
||||
private:
|
||||
int wid, hei;
|
||||
GLenum format_, target_;
|
||||
GLuint id_;
|
||||
};
|
||||
|
||||
|
||||
class CubeTexture {
|
||||
public:
|
||||
CubeTexture(int _size, const GLenum & _format = GL_RGBA8) {size = _size; format_ = _format; id_ = 0; changed_ = false; pathes.resize(6);}
|
||||
bool create();
|
||||
void destroy() {if (id_ > 0) glDeleteTextures(1, &id_); id_ = 0;}
|
||||
void bind() {if (changed_) {changed_ = false; create();} if (id_ > 0) glBindTexture(GL_TEXTURE_CUBE_MAP, id_);}
|
||||
void release() {glBindTexture(GL_TEXTURE_CUBE_MAP, 0);}
|
||||
void resize(int _size) {size = _size; changed_ = true;}
|
||||
void loadFromDirectory(const QString & dir);
|
||||
void loadFront(const QString & path) {bind(); pathes[0] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_X);}
|
||||
void loadBack(const QString & path) {bind(); pathes[1] = path; createGLTexture(id_, rotateQImageRight(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_X);}
|
||||
void loadLeft(const QString & path) {bind(); pathes[2] = path; createGLTexture(id_, QImage(path).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);}
|
||||
void loadRight(const QString & path) {bind(); pathes[3] = path; createGLTexture(id_, rotateQImage180(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_Y);}
|
||||
void loadTop(const QString & path) {bind(); pathes[4] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);}
|
||||
void loadBottom(const QString & path) {bind(); pathes[5] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_Z);}
|
||||
void load();
|
||||
bool isEmpty() const {foreach (const QString & i, pathes) if (!i.isEmpty()) return false; return true;}
|
||||
GLenum format() const {return format_;}
|
||||
void setFormat(GLenum f) {format_ = f; changed_ = true;}
|
||||
GLuint id() const {return id_;}
|
||||
const QString & path(int side) const {return pathes[side];}
|
||||
void setPath(int side, const QString & p) {pathes[side] = p;}
|
||||
void loadPathesFromDirectory(const QString & dir);
|
||||
private:
|
||||
bool changed_;
|
||||
int size;
|
||||
GLenum format_;
|
||||
GLuint id_;
|
||||
QVector<QString> pathes;
|
||||
};
|
||||
*/
|
||||
|
||||
class Map {
|
||||
public:
|
||||
Map();
|
||||
void setBitmapPath(const QString & p);
|
||||
void clearBitmap() {setBitmapPath(QString());}
|
||||
bool hasBitmap() const {return !bitmap_path.isEmpty();}
|
||||
void load(TextureManager * tm);
|
||||
void copyToQGLMap(QGLEngineShaders::QGLMap & m) const;
|
||||
QString bitmap_path;
|
||||
GLuint bitmap_id;
|
||||
QPointF bitmap_offset;
|
||||
QPointF bitmap_scale;
|
||||
float color_amount;
|
||||
float color_offset;
|
||||
|
||||
bool _changed;
|
||||
int _type, _layer;
|
||||
};
|
||||
|
||||
class Material {
|
||||
public:
|
||||
Material(const QString _name = QString());
|
||||
uint hash();
|
||||
bool hasTransparency() const;
|
||||
bool isMapsChanged() const;
|
||||
bool isMapChanged(int type) const;
|
||||
void load(TextureManager * tm);
|
||||
void setMapsChanged();
|
||||
void setTypes();
|
||||
QString name;
|
||||
QColor color_diffuse;
|
||||
QColor color_specular;
|
||||
QColor color_emission;
|
||||
bool glass;
|
||||
float transparency;
|
||||
float reflectivity;
|
||||
float iof;
|
||||
float dispersion;
|
||||
Map map_diffuse ;
|
||||
Map map_normal ;
|
||||
Map map_specular ;
|
||||
Map map_roughness;
|
||||
Map map_emission ;
|
||||
Map map_relief ;
|
||||
bool _changed;
|
||||
int _index;
|
||||
//GLCubeTexture map_reflection;
|
||||
};
|
||||
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const Map & m) {
|
||||
ChunkStream cs;
|
||||
cs.add(1, m.bitmap_path).add(2, m.color_amount).add(3, m.color_offset).add(6, m.bitmap_scale);
|
||||
s << cs.data(); return s;
|
||||
}
|
||||
inline QDataStream & operator >>(QDataStream & s, Map & m) {
|
||||
ChunkStream cs(s);
|
||||
cs.readAll();
|
||||
cs.get(1, m.bitmap_path).get(2, m.color_amount).get(3, m.color_offset).get(6, m.bitmap_scale);
|
||||
return s;
|
||||
}
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const Material * m) {
|
||||
ChunkStream cs;
|
||||
cs.add(1, m->name).add(2, m->color_diffuse).add(3, m->color_specular).add(4, m->color_emission)
|
||||
.add(5, m->transparency).add(6, m->reflectivity).add(7, m->glass).add(8, m->map_diffuse).add(9, m->map_normal)
|
||||
.add(10, m->map_relief).add(11, m->map_specular).add(12, m->map_roughness).add(13, m->map_emission);
|
||||
s << /*qCompress*/(cs.data()); return s;
|
||||
}
|
||||
inline QDataStream & operator >>(QDataStream & s, Material *& m) {
|
||||
m = new Material();
|
||||
//QByteArray ba;
|
||||
//s >> ba;
|
||||
//ba = qUncompres(ba);
|
||||
ChunkStream cs(s);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: cs.get(m->name); break;
|
||||
case 2: cs.get(m->color_diffuse); break;
|
||||
case 3: cs.get(m->color_specular); break;
|
||||
case 4: cs.get(m->color_emission); break;
|
||||
case 5: cs.get(m->transparency); break;
|
||||
case 6: cs.get(m->reflectivity); break;
|
||||
case 7: cs.get(m->glass); break;
|
||||
case 8: cs.get(m->map_diffuse); break;
|
||||
case 9: cs.get(m->map_normal); break;
|
||||
case 10: cs.get(m->map_relief); break;
|
||||
case 11: cs.get(m->map_specular); break;
|
||||
case 12: cs.get(m->map_roughness); break;
|
||||
case 13: cs.get(m->map_emission); break;
|
||||
}
|
||||
}
|
||||
m->setTypes();
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // GLMATERIAL_H
|
||||
456
qglengine/core/glmesh.cpp
Normal file
456
qglengine/core/glmesh.cpp
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include "glmesh.h"
|
||||
#include "globject.h"
|
||||
#include <QTime>
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
static int _count = 0;
|
||||
|
||||
Mesh::Mesh(GLenum geom_type_): geom_type(geom_type_),
|
||||
buffer_geom(GL_ARRAY_BUFFER, GL_STATIC_DRAW),
|
||||
buffer_ind (GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW),
|
||||
buffer_obj (GL_ARRAY_BUFFER, GL_STREAM_DRAW),
|
||||
buffer_sel (GL_ARRAY_BUFFER, GL_STREAM_DRAW) {
|
||||
vao = 0;
|
||||
hash_ = 0;
|
||||
changed = hash_changed = objects_changed = selected_changed = true;
|
||||
//qDebug() << "Mesh, now" << ++_count;
|
||||
}
|
||||
|
||||
|
||||
Mesh::~Mesh() {
|
||||
//qDebug() << "~Mesh, now" << --_count;
|
||||
//destroy();
|
||||
}
|
||||
|
||||
|
||||
Mesh * Mesh::clone() {
|
||||
Mesh * c = new Mesh();
|
||||
c->vertices_ = vertices_ ;
|
||||
c->normals_ = normals_ ;
|
||||
c->texcoords_ = texcoords_;
|
||||
c->triangles_ = triangles_;
|
||||
c->lines_ = lines_;
|
||||
c->geom_type = geom_type;
|
||||
c->hash_ = hash_;
|
||||
c->hash_changed = hash_changed;
|
||||
//qDebug() << "clone VBO";
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::init(QOpenGLExtraFunctions * f) {
|
||||
if (!isInit()) {
|
||||
buffer_geom.init(f);
|
||||
buffer_ind .init(f);
|
||||
buffer_obj .init(f);
|
||||
buffer_sel .init(f);
|
||||
f->glGenVertexArrays(1, &vao);
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::destroy(QOpenGLExtraFunctions * f) {
|
||||
if (vao != 0) {
|
||||
f->glDeleteVertexArrays(1, &vao);
|
||||
buffer_geom.destroy(f);
|
||||
buffer_ind .destroy(f);
|
||||
buffer_obj .destroy(f);
|
||||
buffer_sel .destroy(f);
|
||||
}
|
||||
vao = 0;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::calculateNormals() {
|
||||
normals_.resize(vertices_.size());
|
||||
QVector3D dv1, dv2, n;
|
||||
foreach (const Vector3i & t, triangles_) {
|
||||
QVector3D & v0(vertices_[t.p0]);
|
||||
QVector3D & v1(vertices_[t.p1]);
|
||||
QVector3D & v2(vertices_[t.p2]);
|
||||
dv1 = v1 - v0, dv2 = v2 - v0;
|
||||
n = QVector3D::crossProduct(dv1, dv2).normalized();
|
||||
normals_[t.p0] = n;
|
||||
normals_[t.p1] = n;
|
||||
normals_[t.p2] = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mesh::calculateTangents() {
|
||||
if (vertices_.isEmpty() || texcoords_.isEmpty()) return;
|
||||
if (texcoords_.size() != vertices_.size()) return;
|
||||
tangents_ .resize(vertices_.size());
|
||||
bitangents_.resize(vertices_.size());
|
||||
//qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "...";
|
||||
QVector3D dv1, dv2;
|
||||
QVector2D dt1, dt2;
|
||||
QVector3D tan, bitan;
|
||||
foreach (const Vector3i & t, triangles_) {
|
||||
QVector3D & v0(vertices_ [t.p0]);
|
||||
QVector3D & v1(vertices_ [t.p1]);
|
||||
QVector3D & v2(vertices_ [t.p2]);
|
||||
QVector2D & t0(texcoords_[t.p0]);
|
||||
QVector2D & t1(texcoords_[t.p1]);
|
||||
QVector2D & t2(texcoords_[t.p2]);
|
||||
dv1 = v1 - v0, dv2 = v2 - v0;
|
||||
dt1 = t1 - t0, dt2 = t2 - t0;
|
||||
tan = (dv1 * dt2.y() - dv2 * dt1.y()).normalized();
|
||||
bitan = (dv2 * dt1.x() - dv1 * dt2.x()).normalized();
|
||||
tangents_ [t.p0] = tan;
|
||||
tangents_ [t.p1] = tan;
|
||||
tangents_ [t.p2] = tan;
|
||||
bitangents_[t.p0] = bitan;
|
||||
bitangents_[t.p1] = bitan;
|
||||
bitangents_[t.p2] = bitan;
|
||||
//qDebug() << " t" << t << vi << ti << dv1.toQVector3D() << "...";
|
||||
}
|
||||
//qDebug() << "calculateBinormals" << vcnt << tcnt << tangents_.size();
|
||||
}
|
||||
|
||||
|
||||
void Mesh::loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size) {
|
||||
if (!isInit()) init(f);
|
||||
if (!buf.isInit() || !data) return;
|
||||
buf.bind(f);
|
||||
buf.resize(f, size);
|
||||
buf.load(f, data, size);
|
||||
//qDebug() << "loadBuffer" << size << "bytes";
|
||||
/*void * map = buf.map(f, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
qDebug() << map;
|
||||
if (map)
|
||||
memcpy(map, objects_.constData(), osize);
|
||||
buf.unmap(f);*/
|
||||
}
|
||||
|
||||
|
||||
bool Mesh::rebuffer(QOpenGLExtraFunctions * f) {
|
||||
changed = false;
|
||||
if (vertices_.isEmpty()) return true;
|
||||
if (normals_.isEmpty())
|
||||
calculateNormals();
|
||||
calculateTangents();
|
||||
vert_count = qMin(vertices_.size(), normals_.size());
|
||||
vert_count = qMin(vert_count, tangents_.size());
|
||||
vert_count = qMin(vert_count, bitangents_.size());
|
||||
vert_count = qMin(vert_count, texcoords_.size());
|
||||
data_.resize(vert_count);
|
||||
for (int i = 0; i < vert_count; ++i) {
|
||||
Vertex & v(data_[i]);
|
||||
v.pos = vertices_ [i];
|
||||
v.normal = normals_ [i];
|
||||
v.tangent = tangents_ [i];
|
||||
v.bitangent = bitangents_[i];
|
||||
v.tex = texcoords_ [i];
|
||||
}
|
||||
int gsize = data_.size() * sizeof(Vertex);
|
||||
int tsize = triangles_.size() * sizeof(Vector3i);
|
||||
int lsize = lines_.size() * sizeof(Vector2i);
|
||||
f->glBindVertexArray(vao);
|
||||
|
||||
buffer_geom.bind(f);
|
||||
buffer_geom.resize(f, gsize);
|
||||
buffer_geom.load(f, data_.constData(), gsize);
|
||||
prepareDrawGeom(f);
|
||||
|
||||
buffer_ind.bind(f);
|
||||
if (geom_type == GL_TRIANGLES) {
|
||||
buffer_ind.resize(f, tsize);
|
||||
buffer_ind.load(f, triangles_.constData(), tsize);
|
||||
} else {
|
||||
buffer_ind.resize(f, lsize);
|
||||
buffer_ind.load(f, lines_.constData(), lsize);
|
||||
}
|
||||
|
||||
buffer_obj.bind(f);
|
||||
prepareDrawObj(f);
|
||||
|
||||
buffer_sel.bind(f);
|
||||
prepareDrawSel(f);
|
||||
|
||||
f->glBindVertexArray(0);
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
|
||||
void Mesh::prepareDrawGeom(QOpenGLExtraFunctions * f) {
|
||||
//qDebug() << "prepareDrawGeom";
|
||||
|
||||
f->glEnableVertexAttribArray(pos_loc );
|
||||
f->glEnableVertexAttribArray(normal_loc );
|
||||
f->glEnableVertexAttribArray(tangent_loc );
|
||||
f->glEnableVertexAttribArray(bitangent_loc);
|
||||
f->glEnableVertexAttribArray(tex_loc );
|
||||
|
||||
int size = sizeof(Vertex);
|
||||
f->glVertexAttribPointer(pos_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)pos_offset );
|
||||
f->glVertexAttribPointer(normal_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)normal_offset );
|
||||
f->glVertexAttribPointer(tangent_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)tangent_offset );
|
||||
f->glVertexAttribPointer(bitangent_loc, 3, GL_FLOAT, GL_FALSE, size, (const void *)bitangent_offset);
|
||||
f->glVertexAttribPointer(tex_loc , 2, GL_FLOAT, GL_FALSE, size, (const void *)tex_offset );
|
||||
}
|
||||
|
||||
|
||||
void Mesh::prepareDrawObj(QOpenGLExtraFunctions * f) {
|
||||
//qDebug() << "prepareDrawObj";
|
||||
|
||||
f->glEnableVertexAttribArray(material_loc );
|
||||
f->glEnableVertexAttribArray(object_id_loc);
|
||||
f->glEnableVertexAttribArray(color_loc );
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
f->glEnableVertexAttribArray(modelmatrix_loc + i);
|
||||
}
|
||||
|
||||
GLsizei size = sizeof(Object);
|
||||
f->glVertexAttribIPointer(material_loc , 1, GL_UNSIGNED_INT , size, (const void *)material_offset );
|
||||
f->glVertexAttribIPointer(object_id_loc, 1, GL_UNSIGNED_INT , size, (const void *)object_id_offset);
|
||||
f->glVertexAttribPointer (color_loc , 4, GL_FLOAT, GL_FALSE, size, (const void *)color_offset );
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
f->glVertexAttribPointer(modelmatrix_loc + i, 4, GL_FLOAT, GL_FALSE, size, (const void *)(modelmatrix_offset + sizeof(QVector4D)*i));
|
||||
}
|
||||
|
||||
f->glVertexAttribDivisor(material_loc , 1);
|
||||
f->glVertexAttribDivisor(object_id_loc, 1);
|
||||
f->glVertexAttribDivisor(color_loc , 1);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
f->glVertexAttribDivisor(modelmatrix_loc + i, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Mesh::prepareDrawSel(QOpenGLExtraFunctions * f) {
|
||||
//qDebug() << "prepareDrawObj";
|
||||
|
||||
f->glEnableVertexAttribArray(is_selected_loc);
|
||||
GLsizei size = 1;
|
||||
f->glVertexAttribIPointer(is_selected_loc, 1, GL_UNSIGNED_BYTE, size, (const void *)is_selected_offset);
|
||||
f->glVertexAttribDivisor(is_selected_loc, 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Mesh::draw(QOpenGLExtraFunctions * f, int count) {
|
||||
if (isEmpty()) return;
|
||||
if (!isInit()) init(f);
|
||||
if (changed) rebuffer(f);
|
||||
//qDebug() << "draw" << geom_type << vert_count << count;
|
||||
|
||||
f->glBindVertexArray(vao);
|
||||
if (geom_type == GL_TRIANGLES)
|
||||
f->glDrawElementsInstanced(geom_type, triangles_.size() * 3, GL_UNSIGNED_INT, 0, count);
|
||||
else
|
||||
f->glDrawElementsInstanced(geom_type, lines_.size() * 2, GL_UNSIGNED_INT, 0, count);
|
||||
f->glBindVertexArray(0);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::clear() {
|
||||
vertices_.clear();
|
||||
normals_.clear();
|
||||
tangents_.clear();
|
||||
bitangents_.clear();
|
||||
texcoords_.clear();
|
||||
triangles_.clear();
|
||||
lines_.clear();
|
||||
data_.clear();
|
||||
changed = hash_changed = true;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::loadObject(QOpenGLExtraFunctions * f, const Object & object) {
|
||||
loadBuffer(f, buffer_obj, &object, sizeof(Object));
|
||||
}
|
||||
|
||||
|
||||
void Mesh::loadObjects(QOpenGLExtraFunctions * f, const QVector<Object> & objects) {
|
||||
loadBuffer(f, buffer_obj, objects.constData(), objects.size() * sizeof(Object));
|
||||
}
|
||||
|
||||
|
||||
void Mesh::loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels) {
|
||||
//qDebug() << "loadSelections" << sels;
|
||||
loadBuffer(f, buffer_sel, sels.constData(), sels.size());
|
||||
}
|
||||
|
||||
|
||||
uint Mesh::hash() const {
|
||||
if (hash_changed) {
|
||||
hash_changed = false;
|
||||
hash_ = qHashBits(vertices_ .constData(), vertices_ .size() * sizeof(QVector3D));
|
||||
hash_ ^= qHashBits(normals_ .constData(), normals_ .size() * sizeof(QVector3D));
|
||||
hash_ ^= qHashBits(texcoords_.constData(), texcoords_.size() * sizeof(QVector2D));
|
||||
hash_ ^= qHashBits(triangles_.constData(), triangles_.size() * sizeof( Vector3i));
|
||||
hash_ ^= qHashBits(lines_ .constData(), lines_ .size() * sizeof( Vector2i));
|
||||
}
|
||||
return hash_;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::translatePoints(const QVector3D & dp) {
|
||||
QMatrix4x4 m;
|
||||
m.translate(dp);
|
||||
transformPoints(m);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::scalePoints(const QVector3D & dp) {
|
||||
QMatrix4x4 m;
|
||||
m.scale(dp);
|
||||
transformPoints(m);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::rotatePoints(const double & angle, const QVector3D & a) {
|
||||
QMatrix4x4 m;
|
||||
m.rotate(angle, a);
|
||||
transformPoints(m);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::transformPoints(const QMatrix4x4 & mat) {
|
||||
if (vertices_.isEmpty()) return;
|
||||
int vcnt = vertices_.size(), ncnt = normals_.size();
|
||||
for (int i = 0; i < vcnt; ++i) {
|
||||
vertices_[i] = (mat * QVector4D(vertices_[i], 1)).toVector3D();
|
||||
if (i < ncnt)
|
||||
normals_[i] = (mat * QVector4D(normals_[i], 0)).toVector3D();
|
||||
}
|
||||
changed = hash_changed = true;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::append(const Mesh * m) {
|
||||
if (!m) return;
|
||||
if (m->isEmpty()) return;
|
||||
if (normals_.isEmpty()) calculateNormals();
|
||||
int vcnt = vertices_.size();
|
||||
vertices_ .append(m->vertices_ );
|
||||
normals_ .append(m->normals_ );
|
||||
texcoords_.append(m->texcoords_);
|
||||
QVector<Vector3i> tri = m->triangles_;
|
||||
for (int i = 0; i < tri.size(); ++i)
|
||||
tri[i] += vcnt;
|
||||
triangles_.append(tri);
|
||||
QVector<Vector2i> lin = m->lines_;
|
||||
for (int i = 0; i < lin.size(); ++i)
|
||||
lin[i] += vcnt;
|
||||
lines_.append(lin);
|
||||
}
|
||||
|
||||
|
||||
bool Mesh::saveToFile(const QString & filename) {
|
||||
if (filename.isEmpty()) return false;
|
||||
QFile f(filename);
|
||||
QByteArray ba;
|
||||
if (f.open(QFile::WriteOnly)) {
|
||||
QDataStream out(&ba, QFile::WriteOnly);
|
||||
out << vertices_ << normals_ << texcoords_ << triangles_ << lines_;
|
||||
ba = qCompress(ba);
|
||||
f.resize(0);
|
||||
f.write(ba);
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Mesh::loadFromFile(const QString & filename) {
|
||||
if (filename.isEmpty()) return false;
|
||||
QFile f(filename);
|
||||
QByteArray ba;
|
||||
if (f.open(QFile::ReadOnly)) {
|
||||
ba = f.readAll();
|
||||
if (ba.isEmpty()) return false;
|
||||
ba = qUncompress(ba);
|
||||
QDataStream in(ba);
|
||||
in >> vertices_ >> normals_ >> texcoords_ >> triangles_ >> lines_;
|
||||
changed = hash_changed = true;
|
||||
f.close();
|
||||
return !isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Box3D Mesh::boundingBox() const {
|
||||
if (vertices_.isEmpty()) return Box3D();
|
||||
int vcnt = vertices_.size();
|
||||
//qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "...";
|
||||
GLfloat mix, miy, miz, max, may, maz;
|
||||
QVector3D v0(vertices_[0]);
|
||||
mix = max = v0.x();
|
||||
miy = may = v0.y();
|
||||
miz = maz = v0.z();
|
||||
Box3D bound;
|
||||
for (int i = 1; i < vcnt; ++i) {
|
||||
const QVector3D & v(vertices_[i]);
|
||||
if (mix > v.x()) mix = v.x();
|
||||
if (max < v.x()) max = v.x();
|
||||
if (miy > v.y()) miy = v.y();
|
||||
if (may < v.y()) may = v.y();
|
||||
if (miz > v.z()) miz = v.z();
|
||||
if (maz < v.z()) maz = v.z();
|
||||
}
|
||||
bound.x = mix;
|
||||
bound.y = miy;
|
||||
bound.z = miz;
|
||||
bound.length = max - mix;
|
||||
bound.width = may - miy;
|
||||
bound.height = maz - miz;
|
||||
return bound;
|
||||
}
|
||||
|
||||
|
||||
QDataStream & operator <<(QDataStream & s, const Mesh * m) {
|
||||
ChunkStream cs;
|
||||
//qDebug() << "place VBO" << m.vertices_.size() << m.normals_.size() << m.texcoords_.size() << m.colors_.size() << "...";
|
||||
cs.add(1, m->vertices_).add(2, m->normals_).add(3, m->texcoords_)
|
||||
.add(6, m->triangles_).add(7, m->lines_).add(10, int(m->geom_type));
|
||||
//qDebug() << "place VBO done" << cs.data().size() << "...";
|
||||
s << /*qCompress*/(cs.data()); return s;
|
||||
}
|
||||
|
||||
|
||||
QDataStream & operator >>(QDataStream & s, Mesh *& m) {
|
||||
m = new Mesh();
|
||||
//QByteArray ba;
|
||||
//s >> ba;
|
||||
//ba = qUncompress(ba);
|
||||
ChunkStream cs(s);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1 : cs.get(m->vertices_ ); break;
|
||||
case 2 : cs.get(m->normals_ ); break;
|
||||
case 3 : cs.get(m->texcoords_); break;
|
||||
case 6 : cs.get(m->triangles_); break;
|
||||
case 7 : cs.get(m->lines_ ); break;
|
||||
case 10: m->geom_type = cs.getData<int>(); break;
|
||||
}
|
||||
}
|
||||
m->changed = true;
|
||||
return s;
|
||||
}
|
||||
106
qglengine/core/glmesh.h
Normal file
106
qglengine/core/glmesh.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLMESH_H
|
||||
#define GLMESH_H
|
||||
|
||||
#include <chunkstream.h>
|
||||
#include "glbuffer.h"
|
||||
#include "glshaders_types.h"
|
||||
|
||||
|
||||
class Mesh
|
||||
{
|
||||
friend class ObjectBase;
|
||||
friend class Scene;
|
||||
friend class Renderer;
|
||||
friend QDataStream & operator <<(QDataStream & s, const Mesh * m);
|
||||
friend QDataStream & operator >>(QDataStream & s, Mesh *& m);
|
||||
public:
|
||||
Mesh(GLenum geom_type_ = GL_TRIANGLES);
|
||||
~Mesh();
|
||||
|
||||
Mesh * clone();
|
||||
|
||||
//GLVBO & operator =(const GLVBO & o) {return *this;}
|
||||
|
||||
void init (QOpenGLExtraFunctions * f);
|
||||
void destroy (QOpenGLExtraFunctions * f);
|
||||
bool rebuffer(QOpenGLExtraFunctions * f);
|
||||
void draw (QOpenGLExtraFunctions * f, int count);
|
||||
void clear();
|
||||
void loadObject (QOpenGLExtraFunctions * f, const QGLEngineShaders::Object & object);
|
||||
void loadObjects (QOpenGLExtraFunctions * f, const QVector<QGLEngineShaders::Object> & objects);
|
||||
void loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels);
|
||||
|
||||
int verticesCount() const {return vertices_.size();}
|
||||
int trianglesCount() const {return triangles_.size();}
|
||||
int linesCount() const {return lines_.size();}
|
||||
bool isInit() const {return vao != 0;}
|
||||
bool isEmpty() const {return vertices_.isEmpty();}
|
||||
uint hash() const;
|
||||
|
||||
QVector<QVector3D> & vertices () {changed = hash_changed = true; return vertices_;}
|
||||
QVector<QVector3D> & normals () {changed = hash_changed = true; return normals_;}
|
||||
QVector<QVector2D> & texcoords() {changed = hash_changed = true; return texcoords_;}
|
||||
QVector< Vector3i> & indicesTriangles() {changed = hash_changed = true; return triangles_;}
|
||||
QVector< Vector2i> & indicesLines () {changed = hash_changed = true; return lines_;}
|
||||
|
||||
void translatePoints(const QVector3D & dp);
|
||||
void translatePoints(const double & x, const double & y, const double & z) {translatePoints(QVector3D(x, y, z));}
|
||||
void scalePoints (const QVector3D & dp);
|
||||
void scalePoints (const double & s) {scalePoints(QVector3D(s, s, s));}
|
||||
void rotatePoints (const double & angle, const QVector3D & a);
|
||||
void rotatePoints (const double & angle, const double & x, const double & y, const double & z) {rotatePoints(angle, QVector3D(x, y, z));}
|
||||
void transformPoints(const QMatrix4x4 & mat);
|
||||
void append(const Mesh * m);
|
||||
|
||||
bool saveToFile(const QString & filename);
|
||||
bool loadFromFile(const QString & filename);
|
||||
|
||||
Box3D boundingBox() const;
|
||||
|
||||
static void prepareDrawGeom(QOpenGLExtraFunctions * f);
|
||||
static void prepareDrawObj (QOpenGLExtraFunctions * f);
|
||||
static void prepareDrawSel (QOpenGLExtraFunctions * f);
|
||||
|
||||
private:
|
||||
void calculateNormals();
|
||||
void calculateTangents();
|
||||
void loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size);
|
||||
|
||||
QVector<QVector3D> vertices_, normals_, tangents_, bitangents_;
|
||||
QVector<QVector2D> texcoords_;
|
||||
QVector< Vector3i> triangles_;
|
||||
QVector< Vector2i> lines_;
|
||||
|
||||
QVector<QGLEngineShaders::Vertex> data_;
|
||||
GLenum vao, geom_type;
|
||||
Buffer buffer_geom, buffer_ind, buffer_obj, buffer_sel;
|
||||
mutable uint hash_;
|
||||
mutable bool hash_changed;
|
||||
int vert_count;
|
||||
bool changed, objects_changed, selected_changed;
|
||||
|
||||
};
|
||||
|
||||
|
||||
QDataStream & operator <<(QDataStream & s, const Mesh * m);
|
||||
QDataStream & operator >>(QDataStream & s, Mesh *& m);
|
||||
|
||||
#endif // GLMESH_H
|
||||
407
qglengine/core/glprimitives.cpp
Normal file
407
qglengine/core/glprimitives.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "glprimitives.h"
|
||||
#include "glmesh.h"
|
||||
|
||||
|
||||
|
||||
|
||||
Mesh * Primitive::plane(float width, float length) {
|
||||
Mesh * ret = new Mesh();
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector3i> & i(ret->indicesTriangles ());
|
||||
float hw = width / 2.f, hl = length / 2.f;
|
||||
for (int j = 0; j < 4; ++j) n << QVector3D(0., 0., 1.);
|
||||
t << QVector2D(0., 0.) << QVector2D(0., 1.) << QVector2D(1., 1.) << QVector2D(1., 0.);
|
||||
v << QVector3D(-hw, -hl, 0.) << QVector3D(-hw, hl, 0.) << QVector3D(hw, hl, 0.) << QVector3D(hw, -hl, 0.);
|
||||
i << Vector3i(0, 2, 1) << Vector3i(0, 3, 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Mesh * Primitive::cube(float width, float length, float height) {
|
||||
Mesh * ret = new Mesh();
|
||||
QVector3D scale(width, length, height);
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector3i> & i(ret->indicesTriangles ());
|
||||
float hs = 0.5f;
|
||||
int si = 0;
|
||||
QMatrix4x4 mat;
|
||||
|
||||
si = v.size();
|
||||
for (int j = 0; j < 4; ++j) n << QVector3D(0., -1., 0.);
|
||||
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
|
||||
v << QVector3D(-hs, -hs, -hs) << QVector3D(hs, -hs, -hs) << QVector3D(hs, -hs, hs) << QVector3D(-hs, -hs, hs);
|
||||
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
|
||||
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
si = v.size();
|
||||
mat.rotate(90., 0., 0., 1.);
|
||||
QVector3D cn = mat.map(n[0]);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
n << cn;
|
||||
v << mat.map(QVector4D(v[j])).toVector3D();
|
||||
}
|
||||
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
|
||||
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
|
||||
}
|
||||
|
||||
mat.setToIdentity();
|
||||
mat.rotate(90., 1., 0.,0.);
|
||||
for (int r = 0; r < 2; ++r) {
|
||||
si = v.size();
|
||||
mat.rotate(180., 1., 0.,0.);
|
||||
QVector3D cn = mat.map(n[0]);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
n << cn;
|
||||
v << mat.map(QVector4D(v[j])).toVector3D();
|
||||
}
|
||||
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
|
||||
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
|
||||
}
|
||||
|
||||
for (int i = 0; i < v.size(); ++i)
|
||||
v[i] *= scale;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float width, float length, float height) {
|
||||
Mesh * ret = new Mesh();
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector3i> & ind(ret->indicesTriangles());
|
||||
double hh = height / 2.f;
|
||||
int hseg = segments_h + 1, wlseg = segments_wl + 1;
|
||||
double crw, crl, a, ch, twl;
|
||||
|
||||
QVector3D cp;
|
||||
for (int i = 0; i <= hseg; i++) {
|
||||
ch = -cos((double)i / hseg * M_PI);
|
||||
cp.setZ(ch * hh);
|
||||
twl = sqrt(1. - ch * ch) / 2.;
|
||||
crw = twl * width;
|
||||
crl = twl * length;
|
||||
int cvcnt = wlseg * 2;
|
||||
for (int j = 0; j < cvcnt; j++) {
|
||||
a = (double)j / (cvcnt - 1) * M_2PI;
|
||||
cp.setX(crl * cos(a));
|
||||
cp.setY(crw * sin(a));
|
||||
v << cp; t << QVector2D((double)j / (cvcnt - 1), ch/2.f + 0.5f);
|
||||
int si = v.size() - 1;
|
||||
if (j > 0 && i > 0) {
|
||||
ind << Vector3i(si - cvcnt - 1, si, si - 1);
|
||||
ind << Vector3i(si - cvcnt, si, si - cvcnt - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n.resize(v.size());
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
n[i] = v[i].normalized();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Mesh * Primitive::disc(int segments, float width, float length, bool up, float end_angle) {
|
||||
Mesh * ret = new Mesh();
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector3i> & ind(ret->indicesTriangles());
|
||||
|
||||
segments = qMax(segments + 1, 4);
|
||||
QVector3D cp;
|
||||
v << QVector3D();
|
||||
t << QVector2D(0.5f, 0.5f);
|
||||
end_angle *= deg2rad;
|
||||
for (int i = 0; i < segments; i++) {
|
||||
double a = (double)i / (segments - 1) * end_angle;
|
||||
cp.setX(length / 2. * cos(a));
|
||||
cp.setY(width / 2. * sin(a));
|
||||
v << cp;
|
||||
t << QVector2D(cp.x() / width + 0.5f, cp.y() / length + 0.5f);
|
||||
int si = v.size() - 1;
|
||||
if (i > 0) {
|
||||
if (up)
|
||||
ind << Vector3i(si - 1, si, 0);
|
||||
else
|
||||
ind << Vector3i(si, si - 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
n.resize(v.size());
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
n[i] = QVector3D(0, 0, up ? 1 : -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QVector3D coneNormal(double rx, double ry, double height, double ang) {
|
||||
QVector3D norm;
|
||||
norm.setX(rx * cos(ang));
|
||||
norm.setY(ry * sin(ang));
|
||||
norm.setZ(0.);
|
||||
double rl = norm.length();
|
||||
double ca = atan2(rl, height);
|
||||
norm *= cos(ca);
|
||||
norm.setZ(norm.length() * tan(ca));
|
||||
return norm.normalized();
|
||||
}
|
||||
Mesh * Primitive::cone(int segments, float width, float length, float height) {
|
||||
Mesh * ret = new Mesh();
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector3i> & ind(ret->indicesTriangles());
|
||||
|
||||
int seg = qMax(segments + 1, 4);
|
||||
double rx = width / 2., ry = length / 2.;
|
||||
QVector3D cp;
|
||||
for (int i = 0; i < seg; i++) {
|
||||
double a = (double)i / (seg - 1) * M_2PI;
|
||||
cp.setX(ry * cos(a));
|
||||
cp.setY(rx * sin(a));
|
||||
if (i > 0) {
|
||||
v << QVector3D(0, 0, height);
|
||||
t << QVector2D((double)(i - 1) / (seg - 1), 1.f);
|
||||
double ta = ((double)i - 0.5) / (seg - 1) * M_2PI;
|
||||
n << coneNormal(rx, ry, height, ta);
|
||||
}
|
||||
v << cp;
|
||||
t << QVector2D((double)i / (seg - 1), 0.f);
|
||||
n << coneNormal(rx, ry, height, a);
|
||||
int si = v.size() - 1;
|
||||
if (i > 0)
|
||||
ind << Vector3i(si - 1, si - 2, si);
|
||||
}
|
||||
|
||||
Mesh * cap = Primitive::disc(segments, width, length, false);
|
||||
ret->append(cap);
|
||||
delete cap;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Mesh * Primitive::cylinder(int segments, float width, float length, float height) {
|
||||
Mesh * ret = new Mesh();
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector3i> & ind(ret->indicesTriangles());
|
||||
|
||||
int seg = qMax(segments + 1, 4);
|
||||
double rx = width / 2., ry = length / 2.;
|
||||
QVector3D cp, norm;
|
||||
for (int i = 0; i < seg; i++) {
|
||||
double a = (double)i / (seg - 1) * M_2PI;
|
||||
cp.setX(ry * cos(a));
|
||||
cp.setY(rx * sin(a));
|
||||
cp.setZ(0.);
|
||||
norm = cp.normalized();
|
||||
v << cp;
|
||||
cp.setZ(height);
|
||||
v << cp;
|
||||
t << QVector2D((double)i / (seg - 1), 0.f);
|
||||
t << QVector2D((double)i / (seg - 1), 1.f);
|
||||
n << norm; n << norm;
|
||||
int si = v.size() - 1;
|
||||
if (i > 0) {
|
||||
ind << Vector3i(si - 2, si - 1, si);
|
||||
ind << Vector3i(si - 1, si - 2, si - 3);
|
||||
}
|
||||
}
|
||||
|
||||
Mesh * cap = Primitive::disc(segments, width, length, false);
|
||||
ret->append(cap);
|
||||
delete cap;
|
||||
cap = Primitive::disc(segments, width, length, true);
|
||||
cap->translatePoints(QVector3D(0., 0., height));
|
||||
ret->append(cap);
|
||||
delete cap;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Mesh * Primitive::arrow(int segments, float thick, float angle) {
|
||||
double cone_d = 3. * thick;
|
||||
double cone_h = cone_d / tan(angle * deg2rad);
|
||||
Mesh * ret = new Mesh();
|
||||
Mesh * m = Primitive::cylinder(segments, thick, thick, 1. - cone_h);
|
||||
ret->append(m);
|
||||
delete m;
|
||||
m = Primitive::cone(segments, cone_d, cone_d, cone_h);
|
||||
m->translatePoints(QVector3D(0., 0., 1. - cone_h));
|
||||
ret->append(m);
|
||||
delete m;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Mesh * Primitive::torus(int segments_main, int segments_second, float radius_main, float radius_second, float end_angle) {
|
||||
Mesh * ret = new Mesh();
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector3i> & ind(ret->indicesTriangles());
|
||||
|
||||
QVector<QVector3D> cv, cn;
|
||||
QVector<QVector2D> ct;
|
||||
segments_second = qMax(segments_second + 1, 4);
|
||||
for (int i = 0; i < segments_second; i++) {
|
||||
double x = (double)i / (segments_second - 1);
|
||||
double a = x * M_2PI;
|
||||
cv << QVector3D(radius_second * cos(a), 0., radius_second * sin(a));
|
||||
cn << cv.back().normalized();
|
||||
ct << QVector2D(0., x);
|
||||
cv.back() += QVector3D(radius_main, 0., 0.);
|
||||
}
|
||||
|
||||
segments_main = qMax(segments_main + 1, 4);
|
||||
int ccnt = cv.size(), pcnt = 0;
|
||||
for (int i = 0; i < segments_main; i++) {
|
||||
double x = (double)i / (segments_main - 1);
|
||||
QMatrix4x4 rm;
|
||||
rm.rotate(x * end_angle, 0., 0., 1.);
|
||||
for (int j = 0; j < ccnt; j++) {
|
||||
ct[j].setX(x);
|
||||
v << rm.map(cv[j]);
|
||||
n << rm.map(cn[j]);
|
||||
}
|
||||
t.append(ct);
|
||||
if (i > 0) {
|
||||
for (int j = 0; j < ccnt - 1; j++) {
|
||||
ind << Vector3i(pcnt + j, pcnt + j + 1, pcnt + j - ccnt);
|
||||
ind << Vector3i(pcnt + j + 1, pcnt + j + 1 - ccnt, pcnt + j - ccnt);
|
||||
}
|
||||
}
|
||||
pcnt = v.size();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Mesh * Primitive::cubeFrame(float width, float length, float height) {
|
||||
Mesh * ret = new Mesh(GL_LINES);
|
||||
QVector3D scale(width, length, height);
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector2i> & i(ret->indicesLines());
|
||||
float hs = 0.5f;
|
||||
v << QVector3D(-hs, -hs, -hs) << QVector3D(-hs, hs, -hs) << QVector3D( hs, hs, -hs) << QVector3D( hs, -hs, -hs);
|
||||
v << QVector3D(-hs, -hs, hs) << QVector3D(-hs, hs, hs) << QVector3D( hs, hs, hs) << QVector3D( hs, -hs, hs);
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
v[j] *= scale;
|
||||
t << QVector2D(0, 0);
|
||||
n << QVector3D(0,0,1);
|
||||
}
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
i << Vector2i(j, (j + 1) % 4);
|
||||
i << Vector2i(j, j + 4);
|
||||
i << Vector2i(j + 4, (j + 1) % 4 + 4);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Mesh * Primitive::ellipsoidFrame(int segments_wl, int segments_h, float width, float length, float height) {
|
||||
Mesh * ret = new Mesh(GL_LINES);
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector2i> & ind(ret->indicesLines());
|
||||
double hh = height / 2.f;
|
||||
int hseg = segments_h + 1, wlseg = segments_wl + 1;
|
||||
double crw, crl, a, ch, twl;
|
||||
|
||||
QVector3D cp;
|
||||
for (int i = 0; i <= hseg; i++) {
|
||||
ch = -cos((double)i / hseg * M_PI);
|
||||
cp.setZ(ch * hh);
|
||||
twl = sqrt(1. - ch * ch) / 2.;
|
||||
crw = twl * width;
|
||||
crl = twl * length;
|
||||
int cvcnt = wlseg * 2;
|
||||
for (int j = 0; j < cvcnt; j++) {
|
||||
a = (double)j / (cvcnt - 1) * M_2PI;
|
||||
cp.setX(crl * cos(a));
|
||||
cp.setY(crw * sin(a));
|
||||
v << cp; t << QVector2D((double)j / (cvcnt - 1), ch/2.f + 0.5f);
|
||||
int si = v.size() - 1;
|
||||
if (j > 0 && i > 0) {
|
||||
ind << Vector2i(si, si - 1);
|
||||
ind << Vector2i(si - cvcnt, si);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n.resize(v.size());
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
n[i] = v[i].normalized();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Mesh * Primitive::coneFrame(int segments, float width, float length, float height) {
|
||||
Mesh * ret = new Mesh(GL_LINES);
|
||||
QVector<QVector3D> & v(ret->vertices ());
|
||||
QVector<QVector3D> & n(ret->normals ());
|
||||
QVector<QVector2D> & t(ret->texcoords());
|
||||
QVector< Vector2i> & ind(ret->indicesLines());
|
||||
|
||||
int seg = qMax(segments + 1, 4);
|
||||
double rx = width / 2., ry = length / 2.;
|
||||
QVector3D cp;
|
||||
for (int i = 0; i < seg; i++) {
|
||||
double a = (double)i / (seg - 1) * M_2PI;
|
||||
cp.setX(ry * cos(a));
|
||||
cp.setY(rx * sin(a));
|
||||
if (i > 0) {
|
||||
v << QVector3D(0, 0, height);
|
||||
t << QVector2D((double)(i - 1) / (seg - 1), 1.f);
|
||||
double ta = ((double)i - 0.5) / (seg - 1) * M_2PI;
|
||||
n << coneNormal(rx, ry, height, ta);
|
||||
}
|
||||
v << cp;
|
||||
t << QVector2D((double)i / (seg - 1), 0.f);
|
||||
n << coneNormal(rx, ry, height, a);
|
||||
int si = v.size() - 1;
|
||||
if (i > 0) {
|
||||
ind << Vector2i(si - 1, si);
|
||||
ind << Vector2i(si - 2, si);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
102
qglengine/core/glprimitives.h
Normal file
102
qglengine/core/glprimitives.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLPRIMITIVE_CUBE_H
|
||||
#define GLPRIMITIVE_CUBE_H
|
||||
|
||||
#include "gltypes.h"
|
||||
|
||||
|
||||
namespace Primitive {
|
||||
|
||||
|
||||
Mesh * plane(float width = 1., float length = 1.);
|
||||
|
||||
Mesh * cube(float width = 1., float length = 1., float height = 1.);
|
||||
|
||||
Mesh * ellipsoid(int segments_wl, int segments_h, float width = 1., float length = 1., float height = 1.);
|
||||
|
||||
Mesh * disc(int segments, float width = 1., float length = 1., bool up = true, float end_angle = 360.);
|
||||
|
||||
Mesh * cone(int segments, float width = 1., float length = 1., float height = 1.);
|
||||
|
||||
Mesh * cylinder(int segments, float width = 1., float length = 1., float height = 1.);
|
||||
|
||||
Mesh * arrow(int segments = 16, float thick = 0.04, float angle = 30.); // length = 1
|
||||
|
||||
Mesh * torus(int segments_main = 30, int segments_second = 16, float radius_main = 2.5, float radius_second = 0.5, float end_angle = 360.);
|
||||
|
||||
|
||||
Mesh * cubeFrame(float width = 1., float length = 1., float height = 1.);
|
||||
|
||||
Mesh * ellipsoidFrame(int segments_wl, int segments_h, float width = 1., float length = 1., float height = 1.);
|
||||
|
||||
Mesh * coneFrame(int segments, float width = 1., float length = 1., float height = 1.);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
class GLPrimitivePoint: public GLObjectBase
|
||||
{
|
||||
public:
|
||||
GLPrimitivePoint(double size = 1., QVector3D pos = QVector3D()) {sz = 8.;}
|
||||
virtual void draw(QOpenGLShaderProgram * prog, bool simplest = false);
|
||||
private:
|
||||
double sz;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class GLPrimitiveLine: public GLObjectBase
|
||||
{
|
||||
public:
|
||||
GLPrimitiveLine(QVector3D p0_ = QVector3D(), QVector3D p1_ = QVector3D()) {p0 = p0_; p1 = p1_;}
|
||||
virtual void draw(QOpenGLShaderProgram * prog, bool simplest = false);
|
||||
QVector3D point0() const {return p0;}
|
||||
QVector3D point1() const {return p1;}
|
||||
void setPoint0(const QVector3D & p) {p0 = p;}
|
||||
void setPoint1(const QVector3D & p) {p1 = p;}
|
||||
private:
|
||||
QVector3D p0, p1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class GLPrimitiveEllipsoid: public GLObjectBase
|
||||
{
|
||||
public:
|
||||
GLPrimitiveEllipsoid(float width = 1., float length = 1., float height = 1., int seg_wl = 10, int seg_h = 10, QVector3D pos = QVector3D());
|
||||
virtual void init();
|
||||
private:
|
||||
void putTriangle(const QVector3D & v0, const QVector3D & v1, const QVector3D & v2);
|
||||
float w, l, h;
|
||||
int swl, sh;
|
||||
};
|
||||
|
||||
|
||||
class GLPrimitiveAxis: public GLObjectBase
|
||||
{
|
||||
public:
|
||||
GLPrimitiveAxis() {accept_fog = accept_light = cast_shadow = rec_shadow = select_ = false;}
|
||||
virtual void draw(QOpenGLShaderProgram * prog, bool simplest = false);
|
||||
};
|
||||
*/
|
||||
|
||||
#endif // GLPRIMITIVE_CUBE_H
|
||||
181
qglengine/core/glshaders.cpp
Normal file
181
qglengine/core/glshaders.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gltypes.h"
|
||||
#include "qglview.h"
|
||||
#include "glshaders.h"
|
||||
#include "glshaders_headers.h"
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
bool addShader(QOpenGLShaderProgram * prog, QOpenGLShader::ShaderType type, QString & content, const QString & file, const QString & defs) {
|
||||
if (type == 0 || content.isEmpty()) {
|
||||
content.clear();
|
||||
return true;
|
||||
}
|
||||
//qDebug() << "[QGLView] Shader" << file << "found" << (QOpenGLShader::ShaderTypeBit)(int)type << "section ...";
|
||||
switch (type) {
|
||||
case QOpenGLShader::Fragment:
|
||||
content.prepend(qgl_fragment_head);
|
||||
content.prepend(qgl_uniform);
|
||||
content.prepend(qgl_structs);
|
||||
break;
|
||||
case QOpenGLShader::Vertex :
|
||||
content.prepend(qgl_vertex_head );
|
||||
break;
|
||||
case QOpenGLShader::Geometry:
|
||||
content.prepend(qgl_geometry_head);
|
||||
break;
|
||||
}
|
||||
content.prepend(defs);
|
||||
content.prepend(qgl_common_head);
|
||||
bool ret = prog->addShaderFromSourceCode(type, content.toLatin1());
|
||||
if (!ret) qDebug() << "[QGLView] Shader" << file << "Compile error:\n" << prog->log();
|
||||
content.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QString prepareDefines(const QStringList & defines) {
|
||||
if (defines.isEmpty()) return QString();
|
||||
QString ret;
|
||||
foreach (QString s, defines)
|
||||
ret.append("#define " + s + "\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog, const QString & file, const QStringList & defines) {
|
||||
if (!prog)
|
||||
prog = new QOpenGLShaderProgram();
|
||||
prog->removeAllShaders();
|
||||
QFile f(file);
|
||||
if (!f.open(QIODevice::ReadOnly)) return false;
|
||||
QTextStream ts(&f);
|
||||
QString cur_shader, line, pl, defs = prepareDefines(defines);
|
||||
QOpenGLShader::ShaderType type = 0;
|
||||
while (!ts.atEnd()) {
|
||||
line = ts.readLine();
|
||||
pl = line.trimmed().remove(' ').remove('\t').mid(2).toLower();
|
||||
pl.chop(2);
|
||||
if (pl == "vertex" || pl == "vert") {
|
||||
if (!addShader(prog, type, cur_shader, file, defs)) return false;
|
||||
type = QOpenGLShader::Vertex;
|
||||
continue;
|
||||
}
|
||||
if (pl == "fragment" || pl == "frag") {
|
||||
if (!addShader(prog, type, cur_shader, file, defs)) return false;
|
||||
type = QOpenGLShader::Fragment;
|
||||
continue;
|
||||
}
|
||||
if (pl == "geometry" || pl == "geom") {
|
||||
if (!addShader(prog, type, cur_shader, file, defs)) return false;
|
||||
type = QOpenGLShader::Geometry;
|
||||
continue;
|
||||
}
|
||||
if (pl == "tessellation_control") {
|
||||
if (!addShader(prog, type, cur_shader, file, defs)) return false;
|
||||
type = QOpenGLShader::TessellationControl;
|
||||
continue;
|
||||
}
|
||||
if (pl == "tessellation_evaluation") {
|
||||
if (!addShader(prog, type, cur_shader, file, defs)) return false;
|
||||
type = QOpenGLShader::TessellationEvaluation;
|
||||
continue;
|
||||
}
|
||||
cur_shader.append("\n");
|
||||
cur_shader.append(line);
|
||||
}
|
||||
if (!addShader(prog, type, cur_shader, file, defs)) return false;
|
||||
if (!prog->link()) {
|
||||
qDebug() << "[QGLView] Shader" << file << "Link error:\n" << prog->log();
|
||||
return false;
|
||||
}
|
||||
qDebug() << "[QGLView] Shader" << file << "ok";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void QGLEngineShaders::setUniformMatrices(QOpenGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj, QMatrix4x4 prevview) {
|
||||
if (!prog) return;
|
||||
if (!prog->isLinked()) return;
|
||||
QMatrix4x4 mvpm = proj * view;
|
||||
QMatrix4x4 pmvpm = prevproj * prevview;
|
||||
QMatrix3x3 nm = view.normalMatrix();
|
||||
//nm.in;
|
||||
prog->setUniformValue("qgl_ModelViewMatrix", view);
|
||||
prog->setUniformValue("qgl_ProjectionMatrix", proj);
|
||||
prog->setUniformValue("prev_ModelViewProjectioMatrix", pmvpm);
|
||||
prog->setUniformValue("prev_ModelViewMatrix", prevview);
|
||||
prog->setUniformValue("qgl_ModelViewProjectionMatrix", mvpm);
|
||||
prog->setUniformValue("qgl_NormalMatrix", nm);
|
||||
//prog->setUniformValue("qgl_BumpMatrix", nm.);
|
||||
prog->setUniformValue("qgl_ModelViewMatrixTranspose", view.transposed());
|
||||
prog->setUniformValue("qgl_ProjectionMatrixTranspose", proj.transposed());
|
||||
prog->setUniformValue("qgl_ModelViewProjectionMatrixTranspose", mvpm.transposed());
|
||||
}
|
||||
|
||||
|
||||
void QGLEngineShaders::setUniformLights(QOpenGLShaderProgram * prog, const QVector<Light*> & lights, const QMatrix4x4 & mat, int shadow_start) {
|
||||
for (int i = 0; i < lights.size(); ++i)
|
||||
;//setUniformLight(prog, lights[i], QString("qgl_Light[%1]").arg(i), mat, shadow_start + i);
|
||||
}
|
||||
/*
|
||||
" vec3 position;\n"
|
||||
" vec3 direction;\n"
|
||||
" vec4 color;\n"
|
||||
" float intensity;\n"
|
||||
" float startAngle;\n"
|
||||
" float endAngle;\n"
|
||||
" float constantAttenuation;\n"
|
||||
" float linearAttenuation;\n"
|
||||
" float quadraticAttenuation;\n"
|
||||
" sampler2DShadow shadow;\n"
|
||||
" mat4 shadowMatrix;\n"
|
||||
*/
|
||||
void QGLEngineShaders::setUniformLight(QOpenGLShaderProgram * prog, Light * light, QString ulightn, const QMatrix4x4 & mat, int shadow) {
|
||||
if (!prog) return;
|
||||
if (!prog->isLinked()) return;
|
||||
QMatrix4x4 m = mat * light->worldTransform();
|
||||
QVector4D pos(0, 0, 0, 1.), dir(light->direction(), 1);//, dir0(light->dir0), dir1(light->dir1);
|
||||
pos = m * pos;
|
||||
dir = ((m * dir) - pos).normalized();
|
||||
float ang_start = light->angle_start / 2.f, ang_end = light->angle_end / 2.f;
|
||||
if (light->light_type == Light::Omni)
|
||||
ang_start = ang_end = 180.;
|
||||
//qDebug() << "light" << light->name() << ulightn << pos;
|
||||
prog->setUniformValue((ulightn + ".position").toLatin1().constData(), pos);
|
||||
prog->setUniformValue((ulightn + ".direction").toLatin1().constData(), dir);
|
||||
prog->setUniformValue((ulightn + ".intensity").toLatin1().constData(), GLfloat(light->intensity));
|
||||
prog->setUniformValue((ulightn + ".startAngle").toLatin1().constData(), GLfloat(ang_start));
|
||||
prog->setUniformValue((ulightn + ".startAngleCos").toLatin1().constData(), GLfloat(cosf(ang_start * deg2rad)));
|
||||
prog->setUniformValue((ulightn + ".endAngle").toLatin1().constData(), GLfloat(ang_end));
|
||||
prog->setUniformValue((ulightn + ".endAngleCos").toLatin1().constData(), GLfloat(cosf(ang_end * deg2rad)));
|
||||
//prog->setUniformValue((ulightn + ".color").toLatin1().constData(), light->color());
|
||||
prog->setUniformValue((ulightn + ".constantAttenuation").toLatin1().constData(), GLfloat(light->decay_const));
|
||||
prog->setUniformValue((ulightn + ".linearAttenuation").toLatin1().constData(), GLfloat(light->decay_linear));
|
||||
prog->setUniformValue((ulightn + ".quadraticAttenuation").toLatin1().constData(), GLfloat(light->decay_quadratic));
|
||||
prog->setUniformValue((ulightn + ".shadow").toLatin1().constData(), shadow);
|
||||
prog->setUniformValue((ulightn + ".shadowColor").toLatin1().constData(), shadow);
|
||||
prog->setUniformValue((ulightn + ".shadowMatrix").toLatin1().constData(), light->shadow_matrix);
|
||||
//qDebug() << light->shadow_matrix;
|
||||
//prog->setUniformValue((ulightn + ".shadowDir0").toLatin1().constData(), (mat * dir0));
|
||||
//prog->setUniformValue((ulightn + ".shadowDir1").toLatin1().constData(), (mat * dir1));
|
||||
//qDebug() << light->direction << light->dir0 << light->dir1;
|
||||
}
|
||||
34
qglengine/core/glshaders.h
Normal file
34
qglengine/core/glshaders.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLSHADERS_H
|
||||
#define GLSHADERS_H
|
||||
|
||||
#include "gltypes.h"
|
||||
|
||||
namespace QGLEngineShaders {
|
||||
|
||||
bool loadShadersMulti(QOpenGLShaderProgram *& prog, const QString & file, const QStringList & defines = QStringList());
|
||||
|
||||
void setUniformMatrices(QOpenGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj = QMatrix4x4(), QMatrix4x4 prevview = QMatrix4x4());
|
||||
void setUniformLights(QOpenGLShaderProgram * prog, const QVector<Light*> & lights, const QMatrix4x4 & mat, int shadow_start);
|
||||
void setUniformLight(QOpenGLShaderProgram * prog, Light * light, QString ulightn, const QMatrix4x4 & mat = QMatrix4x4(), int shadow = 0);
|
||||
|
||||
}
|
||||
|
||||
#endif // GLSHADERS_H
|
||||
133
qglengine/core/glshaders_headers.h
Normal file
133
qglengine/core/glshaders_headers.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLSHADERS_HEADERS_H
|
||||
#define GLSHADERS_HEADERS_H
|
||||
|
||||
namespace QGLEngineShaders {
|
||||
|
||||
const int max_materials = 128;
|
||||
const int max_lights = 64 ;
|
||||
|
||||
const char qgl_common_head[] =
|
||||
"#version 400 core\n"
|
||||
//"#extension GL_EXT_texture_aray: require\n"
|
||||
"";
|
||||
|
||||
const char qgl_vertex_head[] =
|
||||
"layout(location = 1 ) in vec3 qgl_Vertex ;\n"
|
||||
"layout(location = 2 ) in vec3 qgl_Normal ;\n"
|
||||
"layout(location = 3 ) in vec3 qgl_Tangent ;\n"
|
||||
"layout(location = 4 ) in vec3 qgl_Bitangent ;\n"
|
||||
"layout(location = 5 ) in vec2 qgl_Texture ;\n"
|
||||
"layout(location = 6 ) in uint qgl_Material ;\n"
|
||||
"layout(location = 7 ) in uint qgl_ObjectSelected;\n"
|
||||
"layout(location = 8 ) in uint qgl_ObjectID ;\n"
|
||||
"layout(location = 9 ) in vec4 qgl_ObjectColor ;\n"
|
||||
"layout(location = 10) in mat4 qgl_ModelMatrix ;\n"
|
||||
"out vec2 qgl_FragTexture;\n"
|
||||
"flat out uint qgl_MaterialIndex;\n"
|
||||
"uniform mat4 qgl_ViewMatrix;\n"
|
||||
"uniform mat4 qgl_ViewProjMatrix;\n"
|
||||
"mat3 qgl_getNormalMatrix() {return mat3(qgl_ViewMatrix * qgl_ModelMatrix);}\n"
|
||||
"vec4 qgl_ftransform() {return qgl_ViewProjMatrix * (qgl_ModelMatrix * vec4(qgl_Vertex, 1));}\n"
|
||||
"";
|
||||
|
||||
const char qgl_fragment_head[] =
|
||||
"in vec2 qgl_FragTexture;\n"
|
||||
"flat in uint qgl_MaterialIndex;\n"
|
||||
"out vec4 qgl_FragData[gl_MaxDrawBuffers];\n"
|
||||
"vec4 qgl_materialTexture(uint type, vec2 coord, vec4 tex_shift) {\n"
|
||||
" coord *= qgl_material[qgl_MaterialIndex].map[type].scale;\n"
|
||||
" vec4 t = texture(qgl_texture_array[qgl_material[qgl_MaterialIndex].map[type].array_index],\n"
|
||||
" vec3(coord, qgl_material[qgl_MaterialIndex].map[type].map_index));\n"
|
||||
" t += tex_shift;\n"
|
||||
" t = t * qgl_material[qgl_MaterialIndex].map[type].amount + qgl_material[qgl_MaterialIndex].map[type].offset;\n"
|
||||
" return t;\n"
|
||||
"}\n"
|
||||
"#define qgl_FragColor qgl_FragData[0]\n"
|
||||
"";
|
||||
|
||||
const char qgl_geometry_head[] =
|
||||
"";
|
||||
|
||||
const char qgl_structs[] =
|
||||
"#define QGL_MAPS_COUNT 6\n"
|
||||
"#define QGL_MAP_DIFFUSE 0\n"
|
||||
"#define QGL_MAP_NORMAL 1\n"
|
||||
"#define QGL_MAP_SPECULAR 2\n"
|
||||
"#define QGL_MAP_ROUGHNESS 3\n"
|
||||
"#define QGL_MAP_EMISSION 4\n"
|
||||
"#define QGL_MAP_RELIEF 5\n"
|
||||
"#define QGL_TEXTURE_ARRAY_EMPTY 0\n"
|
||||
"#define QGL_TEXTURE_ARRAY_MAPS 1\n"
|
||||
"struct QGLMap {\n"
|
||||
" float offset;\n"
|
||||
" float amount;\n"
|
||||
" vec2 scale;\n"
|
||||
" uint array_index;\n"
|
||||
" uint map_index;\n"
|
||||
"};\n"
|
||||
"struct QGLMaterial {\n"
|
||||
" vec4 color_diffuse;\n"
|
||||
" vec4 color_specular;\n"
|
||||
" vec4 color_emission;\n"
|
||||
" float transparency;\n"
|
||||
" float reflectivity;\n"
|
||||
" float iof;\n"
|
||||
" float dispersion;\n"
|
||||
" QGLMap map[QGL_MAPS_COUNT];\n"
|
||||
"};\n"
|
||||
"struct QGLLightParameter {\n"
|
||||
" vec4 color;\n"
|
||||
" float intensity;\n"
|
||||
" float startAngle;\n"
|
||||
" float startAngleCos;\n"
|
||||
" float endAngle;\n"
|
||||
" float endAngleCos;\n"
|
||||
" float constantAttenuation;\n"
|
||||
" float linearAttenuation;\n"
|
||||
" float quadraticAttenuation;\n"
|
||||
//" sampler2DShadow shadow;\n"
|
||||
//" sampler2D shadowColor\n"
|
||||
//" mat4 shadowMatrix;\n"
|
||||
//" vec4 shadowDir0;\n"
|
||||
//" vec4 shadowDir1;\n"
|
||||
"};\n"
|
||||
"struct QGLLightPosition {\n"
|
||||
" vec4 position;\n"
|
||||
" vec4 direction;\n"
|
||||
"};\n"
|
||||
"";
|
||||
|
||||
const char qgl_uniform[] =
|
||||
"layout (std140) uniform QGLMaterialData {\n"
|
||||
" QGLMaterial qgl_material[128];\n"
|
||||
"};\n"
|
||||
"layout (std140) uniform QGLLightParameterData {\n"
|
||||
" QGLLightParameter qgl_light_parameter[64];\n"
|
||||
"};\n"
|
||||
"layout (std140) uniform QGLLightPositionData {\n"
|
||||
" QGLLightPosition qgl_light_position[64];\n"
|
||||
"};\n"
|
||||
"uniform sampler2DArray qgl_texture_array[2];\n"
|
||||
"";
|
||||
|
||||
}
|
||||
|
||||
#endif // GLSHADERS_HEADERS_H
|
||||
41
qglengine/core/glshaders_types.cpp
Normal file
41
qglengine/core/glshaders_types.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "glshaders_types.h"
|
||||
|
||||
|
||||
QGLEngineShaders::QGLMap::QGLMap() {
|
||||
offset = 0.;
|
||||
amount = 1.;
|
||||
scale = QVector2D(1., 1.);
|
||||
array_index = map_index = 0;
|
||||
}
|
||||
|
||||
|
||||
QGLEngineShaders::QGLMaterial::QGLMaterial() {
|
||||
color_diffuse = QVector4D(.5, .5, .5, 0.);
|
||||
color_specular = QVector4D(.5, .5, .5, 0.);
|
||||
color_emission = QVector4D(0., 0., 0., 0.);
|
||||
transparency = 0.;
|
||||
reflectivity = 0.;
|
||||
iof = 0.;
|
||||
dispersion = 0.;
|
||||
map[mtNormal].map_index = emrBlue;
|
||||
map[mtRoughness].amount = 0.75;
|
||||
}
|
||||
148
qglengine/core/glshaders_types.h
Normal file
148
qglengine/core/glshaders_types.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLSHADERS_TYPES_H
|
||||
#define GLSHADERS_TYPES_H
|
||||
|
||||
#include "gltypes.h"
|
||||
|
||||
namespace QGLEngineShaders {
|
||||
|
||||
|
||||
/// VBO
|
||||
|
||||
// geometry
|
||||
const GLsizei pos_offset = 0;
|
||||
const GLsizei normal_offset = sizeof(QVector3D) + pos_offset ;
|
||||
const GLsizei tangent_offset = sizeof(QVector3D) + normal_offset ;
|
||||
const GLsizei bitangent_offset = sizeof(QVector3D) + tangent_offset ;
|
||||
const GLsizei tex_offset = sizeof(QVector3D) + bitangent_offset;
|
||||
|
||||
// object
|
||||
const GLsizei material_offset = 0;
|
||||
const GLsizei object_id_offset = sizeof(GLuint ) + material_offset ;
|
||||
const GLsizei color_offset = sizeof(GLuint ) + object_id_offset ;
|
||||
const GLsizei modelmatrix_offset = sizeof(QVector4D) + color_offset;
|
||||
|
||||
const GLsizei is_selected_offset = 0;
|
||||
|
||||
const GLuint pos_loc = 1 ; // qgl_Vertex
|
||||
const GLuint normal_loc = 2 ; // qgl_Normal
|
||||
const GLuint tangent_loc = 3 ; // qgl_Tangent
|
||||
const GLuint bitangent_loc = 4 ; // qgl_Bitangent
|
||||
const GLuint tex_loc = 5 ; // qgl_Texture
|
||||
|
||||
const GLuint material_loc = 6 ; // qgl_Material
|
||||
const GLuint object_id_loc = 8 ; // qgl_ObjectID
|
||||
const GLuint color_loc = 9 ; // qgl_ObjectColor
|
||||
const GLuint modelmatrix_loc = 10; // qgl_ModelViewProjectionMatrix
|
||||
|
||||
const GLuint is_selected_loc = 7 ; // qgl_ObjectSelected
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Vertex {
|
||||
QVector3D pos;
|
||||
QVector3D normal;
|
||||
QVector3D tangent;
|
||||
QVector3D bitangent;
|
||||
QVector2D tex;
|
||||
};
|
||||
struct Object {
|
||||
Object() {
|
||||
material = object_id = 0;
|
||||
color = QVector4D(1,1,1,1);
|
||||
QMatrix4x4().copyDataTo(modelmatrix);
|
||||
}
|
||||
GLuint material;
|
||||
GLuint object_id;
|
||||
QVector4D color;
|
||||
GLfloat modelmatrix[16];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
/// UBO
|
||||
|
||||
enum BindingPoints {
|
||||
bpMaterials,
|
||||
bpLightParameters,
|
||||
bpLightPositions,
|
||||
};
|
||||
|
||||
enum MapType {
|
||||
mtDiffuse = 0,
|
||||
mtNormal = 1,
|
||||
mtSpecular = 2,
|
||||
mtRoughness = 3,
|
||||
mtEmission = 4,
|
||||
mtRelief = 5,
|
||||
};
|
||||
enum TextureArrayRole {
|
||||
tarEmpty = 0,
|
||||
tarMaps = 1,
|
||||
};
|
||||
enum EmptyMapRole {
|
||||
emrWhite = 0,
|
||||
emrBlue = 1,
|
||||
};
|
||||
#define QGL_MAPS_COUNT 6
|
||||
#pragma pack(push, 1)
|
||||
struct QGLMap {
|
||||
QGLMap();
|
||||
GLfloat offset;
|
||||
GLfloat amount;
|
||||
QVector2D scale;
|
||||
GLuint array_index;
|
||||
GLuint map_index;
|
||||
GLfloat __res_2[2];
|
||||
};
|
||||
struct QGLMaterial {
|
||||
QGLMaterial();
|
||||
QVector4D color_diffuse;
|
||||
QVector4D color_specular;
|
||||
QVector4D color_emission;
|
||||
GLfloat transparency;
|
||||
GLfloat reflectivity;
|
||||
GLfloat iof;
|
||||
GLfloat dispersion;
|
||||
QGLMap map[QGL_MAPS_COUNT];
|
||||
};
|
||||
struct QGLLightParameter {
|
||||
QVector4D color;
|
||||
//QVector4D shadowColor;
|
||||
GLfloat intensity;
|
||||
GLfloat startAngle;
|
||||
GLfloat startAngleCos;
|
||||
GLfloat endAngle;
|
||||
GLfloat endAngleCos;
|
||||
GLfloat constantAttenuation;
|
||||
GLfloat linearAttenuation;
|
||||
GLfloat quadraticAttenuation;
|
||||
//GLfloat shadow;
|
||||
//GLfloat shadowMatrix[16];
|
||||
};
|
||||
struct QGLLightPosition {
|
||||
QVector4D position;
|
||||
QVector4D direction;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // GLSHADERS_TYPES_H
|
||||
96
qglengine/core/gltexturearray.cpp
Normal file
96
qglengine/core/gltexturearray.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include "gltexturearray.h"
|
||||
|
||||
|
||||
Texture2DArray::Texture2DArray(bool filter) {
|
||||
target_ = GL_TEXTURE_2D_ARRAY;
|
||||
texture_ = 0;
|
||||
layers_ = 0;
|
||||
filtering_ = filter;
|
||||
}
|
||||
|
||||
|
||||
Texture2DArray::~Texture2DArray() {
|
||||
}
|
||||
|
||||
|
||||
void Texture2DArray::init(QOpenGLExtraFunctions * f) {
|
||||
if (!isInit()) {
|
||||
f->glGenTextures(1, &texture_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Texture2DArray::destroy(QOpenGLExtraFunctions * f) {
|
||||
if (texture_ != 0) {
|
||||
f->glDeleteTextures(1, &texture_);
|
||||
}
|
||||
texture_ = 0;
|
||||
}
|
||||
|
||||
|
||||
void Texture2DArray::bind(QOpenGLExtraFunctions * f, int channel) {
|
||||
f->glActiveTexture(GL_TEXTURE0 + channel);
|
||||
f->glBindTexture(target_, texture_);
|
||||
}
|
||||
|
||||
|
||||
void Texture2DArray::release(QOpenGLExtraFunctions * f) {
|
||||
f->glBindTexture(target_, 0);
|
||||
}
|
||||
|
||||
|
||||
bool Texture2DArray::resize(QOpenGLExtraFunctions * f, QSize new_size, int layers_count) {
|
||||
if (new_size.isNull() || layers_count <= 0) return false;
|
||||
if ((size_ == new_size) && (layers_ >= layers_count)) return false;
|
||||
size_ = new_size;
|
||||
layers_ = layers_count;
|
||||
f->glBindTexture(target_, texture_);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
if (filtering_) {
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
|
||||
} else {
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
f->glTexImage3D(target_, 0, GL_RGBA8, size_.width(), size_.height(), layers_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Texture2DArray::load(QOpenGLExtraFunctions * f, const QImage & image, int layer) {
|
||||
if (image.isNull() || size_.isNull() || layer < 0 || layer >= layers_) return;
|
||||
QImage im = image.mirrored(false, true)
|
||||
.scaled(size_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)
|
||||
.convertToFormat(QImage::Format_RGBA8888);
|
||||
//qDebug() << "Texture2DArray::load image" << image.size() << "to layer" << layer;
|
||||
f->glTexSubImage3D(target_, 0, 0, 0, layer, size_.width(), size_.height(), 1, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
|
||||
}
|
||||
|
||||
|
||||
void Texture2DArray::mipmaps(QOpenGLExtraFunctions * f) {
|
||||
f->glBindTexture(target_, texture_);
|
||||
f->glGenerateMipmap(target_);
|
||||
}
|
||||
56
qglengine/core/gltexturearray.h
Normal file
56
qglengine/core/gltexturearray.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLTEXTUREARRAY_H
|
||||
#define GLTEXTUREARRAY_H
|
||||
|
||||
#include "gltypes.h"
|
||||
|
||||
|
||||
class Texture2DArray
|
||||
{
|
||||
friend class ObjectBase;
|
||||
public:
|
||||
Texture2DArray(bool filter);
|
||||
~Texture2DArray();
|
||||
|
||||
void init (QOpenGLExtraFunctions * f);
|
||||
void destroy (QOpenGLExtraFunctions * f);
|
||||
|
||||
void bind (QOpenGLExtraFunctions * f, int channel = 0);
|
||||
void release (QOpenGLExtraFunctions * f);
|
||||
|
||||
// returns true if size changed
|
||||
bool resize (QOpenGLExtraFunctions * f, QSize new_size, int layers_count);
|
||||
void load (QOpenGLExtraFunctions * f, const QImage & image, int layer);
|
||||
void mipmaps (QOpenGLExtraFunctions * f);
|
||||
|
||||
GLuint ID() const {return texture_;}
|
||||
bool isInit() const {return texture_ != 0;}
|
||||
|
||||
private:
|
||||
GLenum target_;
|
||||
GLuint texture_;
|
||||
QSize size_;
|
||||
int layers_;
|
||||
bool filtering_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // GLTEXTUREARRAY_H
|
||||
373
qglengine/core/gltypes.cpp
Normal file
373
qglengine/core/gltypes.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "glcamera.h"
|
||||
#include "qglview.h"
|
||||
#include "gltexture_manager.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
//__GLWidget__ * currentQGLView;
|
||||
//QMutex globMutex;
|
||||
|
||||
|
||||
QString readCharsUntilNull(QDataStream & s) {
|
||||
QString str;
|
||||
char ch;
|
||||
s.readRawData(&ch, 1);
|
||||
while (ch != '\0') {
|
||||
str += ch;
|
||||
s.readRawData(&ch, 1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
QString findFile(const QString & file, const QStringList & pathes) {
|
||||
QFileInfo fi(QString(file).replace("\\", "/"));
|
||||
//qDebug() << "search" << file << "in" << pathes;
|
||||
if (fi.exists()) return fi.absoluteFilePath();
|
||||
QString fn = fi.fileName();
|
||||
if (fn.contains("/")) fn = fn.mid(fn.lastIndexOf("/"));
|
||||
foreach (QString p, pathes) {
|
||||
QFileInfoList fil = QDir(p).entryInfoList(QStringList(fn), QDir::Files | QDir::NoDotAndDotDot);
|
||||
//qDebug() << "findFile" << fn << "in" << p << "->" << fil.size();
|
||||
if (!fil.isEmpty())
|
||||
return fil[0].absoluteFilePath();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
void glDrawQuad(QOpenGLShaderProgram * prog, QVector4D * corner_dirs, GLfloat x, GLfloat y, GLfloat w, GLfloat h) {
|
||||
//glResetAllTransforms();
|
||||
glSetPolygonMode(GL_FILL);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
int loc = prog ? prog->attributeLocation("qgl_Color") : -1,
|
||||
locv = prog ? prog->attributeLocation("qgl_Vertex") : -1,
|
||||
loct = prog ? prog->attributeLocation("qgl_Texture") : -1,
|
||||
locc = prog ? prog->attributeLocation("view_corner") : -1;
|
||||
//if (prog) {qDebug() << locv << loct << locc;}
|
||||
QOpenGLFunctions * glFuncs = QOpenGLContext::currentContext()->functions();
|
||||
if (prog) {
|
||||
static const GLfloat cols [] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
|
||||
static const GLfloat verts[] = {x, y, x+w, y, x, y+h, x+w, y+h};
|
||||
static const GLfloat texs [] = {0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f};
|
||||
GLfloat vcs[] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
||||
if (corner_dirs) {
|
||||
vcs[0] = corner_dirs[0].x(); vcs[1] = corner_dirs[0].y(); vcs[2] = corner_dirs[0].z();
|
||||
vcs[3] = corner_dirs[1].x(); vcs[4] = corner_dirs[1].y(); vcs[5] = corner_dirs[1].z();
|
||||
vcs[6] = corner_dirs[2].x(); vcs[7] = corner_dirs[2].y(); vcs[8] = corner_dirs[2].z();
|
||||
vcs[9] = corner_dirs[3].x(); vcs[10] = corner_dirs[3].y(); vcs[11] = corner_dirs[3].z();
|
||||
}
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glFuncs->glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glFuncs->glEnableVertexAttribArray(loc);
|
||||
glFuncs->glVertexAttribPointer(loc, 3, GL_FLOAT, 0, 0, cols);
|
||||
glFuncs->glEnableVertexAttribArray(locv);
|
||||
glFuncs->glVertexAttribPointer(locv, 2, GL_FLOAT, 0, 0, verts);
|
||||
glFuncs->glEnableVertexAttribArray(loct);
|
||||
glFuncs->glVertexAttribPointer(loct, 2, GL_FLOAT, 0, 0, texs);
|
||||
glFuncs->glEnableVertexAttribArray(locc);
|
||||
glFuncs->glVertexAttribPointer(locc, 3, GL_FLOAT, 0, 0, vcs);
|
||||
glFuncs->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glFuncs->glDisableVertexAttribArray(loc);
|
||||
glFuncs->glDisableVertexAttribArray(locv);
|
||||
glFuncs->glDisableVertexAttribArray(loct);
|
||||
glFuncs->glDisableVertexAttribArray(locc);
|
||||
} else {
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
glColor4f(1.f, 1.f, 1.f, 1.f);
|
||||
glTexCoord2f(0.f, 0.f); glVertex2f(x, y);
|
||||
glTexCoord2f(1.f, 0.f); glVertex2f(x+w, y);
|
||||
glTexCoord2f(0.f, 1.f); glVertex2f(x, y+h);
|
||||
glTexCoord2f(1.f, 1.f); glVertex2f(x+w, y+h);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QMatrix4x4 getGLMatrix(GLenum matrix) {
|
||||
GLfloat gm[16];
|
||||
glGetFloatv(matrix, gm);
|
||||
float qm[16];
|
||||
for (int i = 0; i < 16; ++i)
|
||||
qm[i] = gm[i];
|
||||
return QMatrix4x4(qm).transposed();
|
||||
}
|
||||
|
||||
|
||||
void setGLMatrix(QMatrix4x4 matrix) {
|
||||
GLfloat gm[16];
|
||||
float qm[16];
|
||||
matrix.transposed().copyDataTo(qm);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
gm[i] = qm[i];
|
||||
glLoadMatrixf(gm);
|
||||
}
|
||||
|
||||
|
||||
void qglMultMatrix(const QMatrix4x4 & m) {
|
||||
GLfloat gm[16];
|
||||
float qm[16];
|
||||
m.transposed().copyDataTo(qm);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
gm[i] = qm[i];
|
||||
glMultMatrixf(gm);
|
||||
}
|
||||
|
||||
|
||||
void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, int width, int height, const GLenum & format, const GLenum & target) {
|
||||
//glClearError();
|
||||
if (tex == 0) {
|
||||
f->glGenTextures(1, &tex);
|
||||
f->glBindTexture(target, tex);
|
||||
}
|
||||
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_COMPONENT16 || format == GL_DEPTH_COMPONENT24 || format == GL_DEPTH_COMPONENT32)
|
||||
f->glTexImage2D(target, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr);
|
||||
else {
|
||||
int type = GL_UNSIGNED_BYTE;
|
||||
int fmt = GL_RGBA;
|
||||
if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGBA32F || format == GL_RGBA16F)
|
||||
type = GL_FLOAT;
|
||||
if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGB8 || format == GL_RGB)
|
||||
fmt = GL_RGB;
|
||||
f->glTexImage2D(target, 0, format, width, height, 0, fmt, type, nullptr);
|
||||
//glGenerateMipmap(target);
|
||||
//qDebug() << "glTexImage2D" << width << height << QString::number(t, 16);
|
||||
}
|
||||
//qDebug() << QString::number(glGetError(), 16);
|
||||
}
|
||||
|
||||
|
||||
void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, const QImage & image, const GLenum & format, const GLenum & target) {
|
||||
if (tex == 0) {
|
||||
f->glGenTextures(1, &tex);
|
||||
}
|
||||
f->glBindTexture(target, tex);
|
||||
QImage im = image.mirrored(false, true).convertToFormat(QImage::Format_RGBA8888);
|
||||
//const QImage & cim(im);
|
||||
f->glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
f->glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
f->glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
|
||||
if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_3D) {
|
||||
f->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
f->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
f->glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
|
||||
} else {
|
||||
f->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
f->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
glClearError();
|
||||
f->glTexImage2D(target, 0, format, im.width(), im.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
|
||||
if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_3D) {
|
||||
f->glGenerateMipmap(target);
|
||||
}
|
||||
//qDebug() << target << format << tex << im.width() << im.height() << im.bits() << QString::number(glGetError(), 16);
|
||||
}
|
||||
|
||||
|
||||
QMatrix4x4 glMatrixPerspective(float angle, float aspect, float near_, float far_) {
|
||||
QMatrix4x4 ret;
|
||||
float t = 1.f / (tanf(angle * deg2rad / 2.f)), e = 2.4e-7f;
|
||||
if (aspect >= 1.) {
|
||||
ret(0, 0) = t / aspect;
|
||||
ret(1, 1) = t;
|
||||
} else {
|
||||
ret(0, 0) = t;
|
||||
ret(1, 1) = t * aspect;
|
||||
}
|
||||
ret(2, 2) = e - 1.f;//far_ / (far_ - near_) - 1.;
|
||||
ret(2, 3) = (e - 2.f) * near_;//2. * far_ * near_ / (far_ - near_);
|
||||
ret(3, 2) = -1.f;
|
||||
ret(3, 3) = 0.f;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QImage rotateQImageLeft(const QImage & im) {
|
||||
QImage ri(im.height(), im.width(), im.format());
|
||||
QPainter p(&ri);
|
||||
p.rotate(90);
|
||||
p.drawImage(0, -im.height(), im);
|
||||
p.end();
|
||||
return ri;
|
||||
}
|
||||
|
||||
|
||||
QImage rotateQImageRight(const QImage & im) {
|
||||
QImage ri(im.height(), im.width(), im.format());
|
||||
QPainter p(&ri);
|
||||
p.rotate(-90);
|
||||
p.drawImage(-im.width(), 0, im);
|
||||
p.end();
|
||||
return ri;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QColor colorFromString(const QString & str) {
|
||||
QString s = str.trimmed();
|
||||
int i = s.indexOf("\t");
|
||||
float r, g, b;
|
||||
r = s.left(i).toFloat(); s = s.right(s.length() - i - 1); i = s.indexOf("\t");
|
||||
g = s.left(i).toFloat(); s = s.right(s.length() - i - 1);
|
||||
b = s.toFloat();
|
||||
return QColor(r * 255.f, g * 255.f, b * 255.f);
|
||||
}
|
||||
|
||||
|
||||
QVector3D orthToVector(const QVector3D & v, const float & scale) {
|
||||
if (v.isNull()) return QVector3D();
|
||||
QVector3D rv, fn, sn;
|
||||
if (v.x() != 0.f) rv.setZ(1.);
|
||||
else if (v.y() != 0.f) rv.setX(1.);
|
||||
else rv.setY(1.);
|
||||
fn = QVector3D::crossProduct(v, rv).normalized();
|
||||
sn = QVector3D::crossProduct(v, fn).normalized();
|
||||
return fn * urand(scale) + sn * urand(scale);
|
||||
}
|
||||
|
||||
|
||||
QVector3D rotateVector(const QVector3D & v, const QVector3D & a) {
|
||||
QMatrix4x4 m;
|
||||
m.rotate(a.z(), 0., 0., 1.);
|
||||
m.rotate(a.y(), 0., 1., 0.);
|
||||
m.rotate(a.x(), 1., 0., 0.);
|
||||
return m * v;
|
||||
}
|
||||
|
||||
|
||||
void setVectorLength(QVector3D & v, const float & l) {
|
||||
float vl = v.length();
|
||||
if (vl == 0.f) return;
|
||||
float c = l / vl;
|
||||
v *= c;
|
||||
}
|
||||
|
||||
|
||||
void lengthenVector(QVector3D & v, const float & l) {
|
||||
float vl = v.length();
|
||||
if (l == 0.f || vl == 0.f) return;
|
||||
float c = 1.f + l / vl;
|
||||
v *= c;
|
||||
}
|
||||
|
||||
|
||||
Vector2i::Vector2i(const QString & str) {
|
||||
QString s = str.trimmed();
|
||||
int i = s.indexOf("\t");
|
||||
p0 = s.left(i).toInt(); s = s.right(s.length() - i - 1);
|
||||
p1 = s.toInt();
|
||||
}
|
||||
|
||||
|
||||
Vector3i::Vector3i(const QString & str) {
|
||||
QString s = str.trimmed();
|
||||
int i = s.indexOf("\t");
|
||||
p0 = s.left(i).toInt(); s = s.right(s.length() - i - 1); i = s.indexOf("\t");
|
||||
p1 = s.left(i).toInt(); s = s.right(s.length() - i - 1);
|
||||
p2 = s.toInt();
|
||||
}
|
||||
|
||||
|
||||
void glEnableDepth() {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
//glDepthFunc(GL_GREATER);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
|
||||
void glDisableDepth() {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
}
|
||||
|
||||
|
||||
void glClearFramebuffer(const QColor & color, bool depth) {
|
||||
glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
|
||||
//glClearDepth(0.);
|
||||
if (depth)
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
else
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Box3D::Box3D(const QVector<QVector3D> & points) {
|
||||
x = y = z = width = length = height = angle_z = angle_xy = angle_roll = 0.f;
|
||||
if (points.isEmpty()) return;
|
||||
float ix, iy, iz, ax, ay, az;
|
||||
ix = ax = points[0].x();
|
||||
iy = ay = points[0].y();
|
||||
iz = az = points[0].z();
|
||||
for (int i = 1; i < points.size(); ++i) {
|
||||
ix = qMin<float>(ix, points[i].x()); ax = qMax<float>(ax, points[i].x());
|
||||
iy = qMin<float>(iy, points[i].y()); ay = qMax<float>(ay, points[i].y());
|
||||
iz = qMin<float>(iz, points[i].z()); az = qMax<float>(az, points[i].z());
|
||||
}
|
||||
x = ix;
|
||||
y = iy;
|
||||
z = iz;
|
||||
length = ax - ix;
|
||||
width = ay - iy;
|
||||
height = az - iz;
|
||||
}
|
||||
|
||||
|
||||
QVector<QVector3D> Box3D::corners() const {
|
||||
QVector<QVector3D> ret;
|
||||
ret << QVector3D(x, y, z) << QVector3D(x, y + width, z) << QVector3D(x, y, z + height) << QVector3D(x, y + width, z + height)
|
||||
<< QVector3D(x + length, y, z) << QVector3D(x + length, y + width, z)
|
||||
<< QVector3D(x + length, y, z + height) << QVector3D(x + length, y + width, z + height);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Box3D & Box3D::operator |=(const Box3D & o) {
|
||||
if (o.isEmpty()) return *this;
|
||||
if (isEmpty()) *this = o;
|
||||
else {
|
||||
GLfloat mx = x + length, my = y + width, mz = z + height;
|
||||
GLfloat omx = o.x + o.length, omy = o.y + o.width, omz = o.z + o.height;
|
||||
x = qMin(x, o.x); y = qMin(y, o.y); z = qMin(z, o.z);
|
||||
mx = qMax(mx, omx); my = qMax(my, omy); mz = qMax(mz, omz);
|
||||
length = mx - x; width = my - y; height = mz - z;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
QVector3D vectorFromString(const QString & str) {
|
||||
QTextStream s(const_cast<QString*>(&str), QIODevice::ReadOnly);
|
||||
QVector3D ret;
|
||||
float f(0.f);
|
||||
s >> f; ret.setX(f);
|
||||
s >> f; ret.setY(f);
|
||||
s >> f; ret.setZ(f);
|
||||
return ret;
|
||||
}
|
||||
291
qglengine/core/gltypes.h
Normal file
291
qglengine/core/gltypes.h
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLTYPES_H
|
||||
#define GLTYPES_H
|
||||
|
||||
#if WIN32 || WIN64 || _WIN32 || _WIN64 || __WIN32__ || __WIN64__
|
||||
# define WINDOWS
|
||||
#endif
|
||||
#if __QNX__ || __QNXNTO__
|
||||
# define QNX
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
# define MAC
|
||||
#endif
|
||||
#ifndef WINDOWS
|
||||
# ifndef QNX
|
||||
# ifndef MAC
|
||||
# define LINUX
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if __GNUC__
|
||||
# define CC_GCC
|
||||
#elif _MSC_VER
|
||||
# define CC_VC
|
||||
#endif
|
||||
|
||||
|
||||
#include <QObject>
|
||||
//#ifndef WINDOWS
|
||||
//# ifdef MAC
|
||||
//# include <OpenGL/gl.h>
|
||||
//# include <OpenGL/glu.h>
|
||||
//# include <GLUT/glut.h>
|
||||
//# else
|
||||
//# include <GL/gl.h>
|
||||
//# include <GL/glext.h>
|
||||
//# include <GL/glu.h>
|
||||
//# endif
|
||||
//#endif
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <QOpenGLShader>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <qopenglext.h>
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
#include <QMatrix4x4>
|
||||
#include <QDebug>
|
||||
#include <QDataStream>
|
||||
#include <QColor>
|
||||
#include <QVector2D>
|
||||
#include <QVector3D>
|
||||
#include <QImage>
|
||||
#include <QMutex>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#ifndef QNX
|
||||
# include <cmath>
|
||||
# include <complex>
|
||||
#else
|
||||
# include <math.h>
|
||||
# include <complex.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
|
||||
//#ifdef WINDOWS
|
||||
//# define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
|
||||
//# define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
|
||||
//#endif
|
||||
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef M_2PI
|
||||
# define M_2PI 6.28318530717958647692
|
||||
#endif
|
||||
#ifndef M_PI_3
|
||||
# define M_PI_3 1.04719755119659774615
|
||||
#endif
|
||||
|
||||
#ifndef GL_RGBA16F
|
||||
# define GL_RGBA16F GL_RGBA16F_ARB
|
||||
#endif
|
||||
|
||||
using std::complex;
|
||||
|
||||
#ifndef PIP_VERSION
|
||||
typedef long long llong;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short int ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned long long ullong;
|
||||
typedef long double ldouble;
|
||||
|
||||
const float deg2rad = atanf(1.f) / 45.f;
|
||||
const float rad2deg = 45.f / atanf(1.f);
|
||||
|
||||
# ifdef WINDOWS
|
||||
inline int random() {return rand();}
|
||||
# endif
|
||||
#else
|
||||
#define random randomi
|
||||
#endif
|
||||
|
||||
#ifdef CC_VC
|
||||
inline float round(const float & v) {return floor(v + 0.5);}
|
||||
#endif
|
||||
inline float randomu() {return float(random()) / RAND_MAX;}
|
||||
|
||||
inline const QSizeF operator *(const QSizeF & f, const QSizeF & s) {return QSizeF(f.width() * s.width(), f.height() * s.height());}
|
||||
#ifndef PIP_VERSION
|
||||
template<typename Type> inline void piSwap(Type & f, Type & s) {Type t = f; f = s; s = t;}
|
||||
template<typename Type> inline Type piMin(const Type & f, const Type & s) {return (f > s) ? s : f;}
|
||||
template<typename Type> inline Type piMin(const Type & f, const Type & s, const Type & t) {return (f < s && f < t) ? f : ((s < t) ? s : t);}
|
||||
template<typename Type> inline Type piMax(const Type & f, const Type & s) {return (f < s) ? s : f;}
|
||||
template<typename Type> inline Type piMax(const Type & f, const Type & s, const Type & t) {return (f > s && f > t) ? f : ((s > t) ? s : t);}
|
||||
template<typename Type> inline Type piClamp(const Type & v, const Type & min, const Type & max) {return (v > max ? max : (v < min ? min : v));}
|
||||
inline ushort letobe_s(ushort v) {return (v << 8) | (v >> 8);}
|
||||
inline uint letobe_i(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
|
||||
#endif
|
||||
// return [-1, 1]
|
||||
inline float urand(const float & scale = 1.) {return ((float)rand() / RAND_MAX - .5f) * (scale + scale);}
|
||||
// return [0, 1]
|
||||
inline float uprand(const float & scale = 1.) {return ((float)rand() / RAND_MAX) * scale;}
|
||||
QString readCharsUntilNull(QDataStream & s);
|
||||
QString findFile(const QString & file, const QStringList & pathes);
|
||||
inline QColor operator *(const QColor & c, float v) {return QColor(piClamp<int>(c.red() * v, 0, 255), piClamp<int>(c.green() * v, 0, 255), piClamp<int>(c.blue() * v, 0, 255), piClamp<int>(c.alpha() * v, 0, 255));}
|
||||
inline QColor operator /(const QColor & c, float v) {return QColor(piClamp<int>(c.red() / v, 0, 255), piClamp<int>(c.green() / v, 0, 255), piClamp<int>(c.blue() / v, 0, 255), piClamp<int>(c.alpha() / v, 0, 255));}
|
||||
|
||||
|
||||
inline void qglColor(const QColor & c) {glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());}
|
||||
inline void glClearError() {int c = 100; while (glGetError() != GL_NO_ERROR && --c > 0) glGetError();}
|
||||
inline void glSetCapEnabled(GLenum cap, bool on = true) {if (on) glEnable(cap); else glDisable(cap);}
|
||||
inline void glSetPolygonMode(GLenum mode) {glPolygonMode(GL_FRONT_AND_BACK, mode);}
|
||||
inline void deleteGLTexture(QOpenGLExtraFunctions * f, GLuint & tex) {if (tex != 0) f->glDeleteTextures(1, &tex); tex = 0;}
|
||||
void glEnableDepth();
|
||||
void glDisableDepth();
|
||||
void glClearFramebuffer(const QColor & color = Qt::black, bool depth = true);
|
||||
void glDrawQuad(QOpenGLShaderProgram * prog = nullptr, QVector4D * corner_dirs = nullptr, GLfloat x = -1.f, GLfloat y = -1.f, GLfloat w = 2.f, GLfloat h = 2.f);
|
||||
void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, int width, int height, const GLenum & format = GL_RGBA, const GLenum & target = GL_TEXTURE_2D);
|
||||
void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, const QImage & image, const GLenum & format = GL_RGBA, const GLenum & target = GL_TEXTURE_2D);
|
||||
QMatrix4x4 glMatrixPerspective(float angle, float aspect, float near_, float far_);
|
||||
QImage rotateQImageLeft(const QImage & im);
|
||||
QImage rotateQImageRight(const QImage & im);
|
||||
inline QImage rotateQImage180(const QImage & im) {return im.mirrored(true, true);}
|
||||
|
||||
class QGLView;
|
||||
class MouseController;
|
||||
class ObjectBase;
|
||||
class AimedObject;
|
||||
class Light;
|
||||
class Camera;
|
||||
class Texture;
|
||||
class CubeTexture;
|
||||
class Map;
|
||||
class Material;
|
||||
class TextureManager;
|
||||
class Texture2DArray;
|
||||
class Mesh;
|
||||
class Scene;
|
||||
class RendererBase;
|
||||
class Renderer;
|
||||
class RendererMaterial;
|
||||
class RendererService;
|
||||
class RendererSelection;
|
||||
|
||||
|
||||
struct Box3D {
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
GLfloat z;
|
||||
GLfloat width;
|
||||
GLfloat length;
|
||||
GLfloat height;
|
||||
GLfloat angle_z;
|
||||
GLfloat angle_xy;
|
||||
GLfloat angle_roll;
|
||||
Box3D() {x = y = z = width = length = height = angle_z = angle_xy = angle_roll = 0.f;}
|
||||
Box3D(const QVector3D & center, GLfloat hwid, GLfloat hlen, GLfloat hhei) {x = center.x() - hwid; y = center.y() - hlen; z = center.z() - hhei; width = 2 * hwid; length = 2 * hlen; height = 2 * hhei; angle_z = angle_xy = angle_roll = 0.f;}
|
||||
Box3D(const QVector<QVector3D> & points);
|
||||
bool isEmpty() const {return (qAbs(width) < 1E-6f) && (qAbs(length) < 1E-6f) && (qAbs(height) < 1E-6f);}
|
||||
QVector3D randomPoint() const {return QVector3D(uprand(length) + x, uprand(width) + y, uprand(height) + z);}
|
||||
QVector3D pos() const {return QVector3D(x, y, z);}
|
||||
QVector3D size() const {return QVector3D(length, width, height);}
|
||||
QVector3D center() const {return QVector3D(length / 2.f + x, width / 2.f + y, height / 2.f + z);}
|
||||
QVector3D angles() const {return QVector3D(angle_xy, angle_roll, angle_z);}
|
||||
QVector<QVector3D> corners() const;
|
||||
void setPos(const QVector3D & p) {x = p.x(); y = p.y(); z = p.z();}
|
||||
void setAngles(const QVector3D & a) {angle_xy = a.x(); angle_roll = a.y(); angle_z = a.z();}
|
||||
void setSize(const QVector3D & s) {length = s.x(); width = s.y(); height = s.z();}
|
||||
Box3D & moveTo(const QVector3D & v) {x = v.x(); y = v.y(); z = v.z(); return *this;}
|
||||
Box3D & move(const QVector3D & v) {x += v.x(); y += v.y(); z += v.z(); return *this;}
|
||||
Box3D movedTo(const QVector3D & v) const {Box3D t(*this); t.x = v.x(); t.y = v.y(); t.z = v.z(); return t;}
|
||||
Box3D moved(const QVector3D & v) const {Box3D t(*this); t.x += v.x(); t.y += v.y(); t.z += v.z(); return t;}
|
||||
Box3D & operator |=(const Box3D & o);
|
||||
};
|
||||
|
||||
inline QDebug operator <<(QDebug d, const Box3D & v) {d << "Box3D {start (" << v.x << "," << v.y << "," << v.z << "), size (" << v.length << "," << v.width << "," << v.height << ")}"; return d;}
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Vector2i {
|
||||
Vector2i(int p0_ = 0, int p1_ = 0) {p0 = p0_; p1 = p1_;}
|
||||
Vector2i(const QString & str);
|
||||
Vector2i movedX(const int & o) {return Vector2i(p0 + o, p1);}
|
||||
Vector2i movedY(const int & o) {return Vector2i(p0, p1 + o);}
|
||||
Vector2i moved(const int & x, const int & y) {return Vector2i(p0 + x, p1 + y);}
|
||||
GLint p0;
|
||||
GLint p1;
|
||||
bool operator ==(const Vector2i & o) const {return p0 == o.p0 && p1 == o.p1;}
|
||||
bool operator !=(const Vector2i & o) const {return p0 != o.p0 || p1 != o.p1;}
|
||||
void operator +=(int v) {p0 += v; p1 += v;}
|
||||
QVector2D toQVector2D() const {return QVector2D(p0, p1);}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
inline Vector2i operator +(const Vector2i & f, const Vector2i & s) {return Vector2i(f.p0 + s.p0, f.p1 + s.p1);}
|
||||
inline Vector2i operator -(const Vector2i & f, const Vector2i & s) {return Vector2i(f.p0 - s.p0, f.p1 - s.p1);}
|
||||
inline Vector2i operator /(const Vector2i & f, const int & s) {return Vector2i(f.p0 / s, f.p1 / s);}
|
||||
inline uint qHash(const Vector2i & v) {return v.p0 ^ ((v.p1 << 8) | (v.p1 >> 24));}
|
||||
inline QDebug operator <<(QDebug d, const Vector2i & v) {d.nospace() << "{" << v.p0 << ", " << v.p1 << "}"; return d.space();}
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const Vector2i & v) {s << v.p0 << v.p1; return s;}
|
||||
inline QDataStream & operator >>(QDataStream & s, Vector2i & v) {s >> v.p0 >> v.p1; return s;}
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Vector3i {
|
||||
Vector3i(int p0_ = 0, int p1_ = 0, int p2_ = 0) {p0 = p0_; p1 = p1_; p2 = p2_;}
|
||||
Vector3i(const QString & str);
|
||||
Vector3i movedX(const int & o) {return Vector3i(p0 + o, p1, p2);}
|
||||
Vector3i movedY(const int & o) {return Vector3i(p0, p1 + o, p2);}
|
||||
Vector3i movedZ(const int & o) {return Vector3i(p0, p1, p2 + o);}
|
||||
Vector3i moved(const int & x, const int & y, const int & z) {return Vector3i(p0 + x, p1 + y, p2 + z);}
|
||||
GLint p0;
|
||||
GLint p1;
|
||||
GLint p2;
|
||||
bool operator ==(const Vector3i & o) const {return p0 == o.p0 && p1 == o.p1 && p2 == o.p2;}
|
||||
bool operator !=(const Vector3i & o) const {return p0 != o.p0 || p1 != o.p1 || p2 != o.p2;}
|
||||
void operator +=(int v) {p0 += v; p1 += v; p2 += v;}
|
||||
QVector3D toQVector3D() const {return QVector3D(p0, p1, p2);}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
inline Vector3i operator +(const Vector3i & f, const Vector3i & s) {return Vector3i(f.p0 + s.p0, f.p1 + s.p1, f.p2 + s.p2);}
|
||||
inline Vector3i operator -(const Vector3i & f, const Vector3i & s) {return Vector3i(f.p0 - s.p0, f.p1 - s.p1, f.p2 - s.p2);}
|
||||
inline Vector3i operator /(const Vector3i & f, const int & s) {return Vector3i(f.p0 / s, f.p1 / s, f.p2 / s);}
|
||||
inline uint qHash(const Vector3i & v) {return v.p0 ^ ((v.p1 << 8) | (v.p1 >> 24)) ^ ((v.p2 << 16) | (v.p2 >> 16));}
|
||||
inline QDebug operator <<(QDebug d, const Vector3i & v) {d.nospace() << "{" << v.p0 << ", " << v.p1 << ", " << v.p2 << "}"; return d.space();}
|
||||
|
||||
inline QDataStream & operator <<(QDataStream & s, const Vector3i & v) {s << v.p0 << v.p1 << v.p2; return s;}
|
||||
inline QDataStream & operator >>(QDataStream & s, Vector3i & v) {s >> v.p0 >> v.p1 >> v.p2; return s;}
|
||||
|
||||
|
||||
QVector3D vectorFromString(const QString & str);
|
||||
QColor colorFromString(const QString & str);
|
||||
inline QVector4D QColor2QVector(const QColor & c) {return QVector4D(c.redF(), c.greenF(), c.blueF(), c.alphaF());}
|
||||
inline float cosABV(const QVector3D & v0, const QVector3D & v1) {
|
||||
float l = v0.length() * v1.length();
|
||||
if (l == 0.f) return 0.;
|
||||
return (QVector3D::dotProduct(v0, v1)) / l;
|
||||
}
|
||||
inline QVector3D projection(const QVector3D & v, const QVector3D & to) {return to.normalized() * v.length() * cosABV(v, to);}
|
||||
QVector3D orthToVector(const QVector3D & v, const float & scale = 1.);
|
||||
QVector3D rotateVector(const QVector3D & v, const QVector3D & a);
|
||||
void setVectorLength(QVector3D & v, const float & l);
|
||||
void lengthenVector(QVector3D & v, const float & l);
|
||||
inline float squareLength(const QVector3D & from, const QVector3D & to) {return (to.x() - from.x())*(to.x() - from.x()) + (to.y() - from.y())*(to.y() - from.y()) + (to.z() - from.z())*(to.z() - from.z());}
|
||||
inline QVector3D directionFromAngles(const QVector3D & a) {return rotateVector(QVector3D(1., 0., 0.), a);}
|
||||
inline float frac(const float & x, const float & b) {return x - int(x / b) * b;}
|
||||
|
||||
|
||||
#endif // GLTYPES_H
|
||||
Reference in New Issue
Block a user