Compare commits

...

48 Commits

Author SHA1 Message Date
2e6df6c08b shadows flag in Renderer 2023-03-14 16:33:35 +03:00
9e7afb5fb5 many small fixes, RU lang 2023-03-14 17:39:44 +03:00
34976b8865 shader 2023-03-09 16:38:18 +03:00
3ee778cb92 add install version file 2023-03-07 16:22:29 +03:00
64eee9e607 relief map support, small refactoring, shadow bias now based on geometry normal 2023-03-02 11:46:52 +03:00
adf8c4d7f0 res 2023-02-23 11:08:39 +03:00
0fab015e25 res 2023-02-23 11:04:29 +03:00
51562dec9d soft shadows fixes 2023-02-23 11:03:20 +03:00
52e9b19f37 res 2023-02-22 15:50:18 +03:00
7455a7341c soft shadows optimization 2023-02-22 15:48:50 +03:00
91bc31e7db soft shadows done 2023-02-18 19:12:16 +03:00
eb5f50fc9d shadows done 2023-02-17 14:51:27 +03:00
3c9386de63 first works of omni shadows 2023-02-16 16:57:29 +03:00
69caa98d04 bugs 2023-02-14 15:06:48 +03:00
12695983d2 spot light map 2023-02-14 10:43:51 +03:00
36540468dc nvidia fix, soft shadows 2023-02-13 18:35:25 +03:00
c8dcd5e9c0 full support of ObjectBase:: isReceiveShadows, isCastShadows, isAcceptLight and isAcceptFog 2023-02-12 22:49:38 +03:00
e3389bcc20 cone shadows done 2023-02-12 21:27:04 +03:00
728c4a85ed before shadow2DArray try 2023-02-10 13:23:10 +03:00
6ddb3488e5 ui fixes 2023-02-10 12:51:39 +03:00
175cbe7064 qrc 2023-02-10 12:42:54 +03:00
50c5e5ae18 Merge branch 'master' of https://git.shs.tools/SHS/qglengine
# Conflicts:
#	src/qglview_test/qglview_window.ui
2023-02-09 19:37:29 +03:00
c3f91d78f0 ui fix 2023-02-09 19:36:45 +03:00
3cf466e5d3 shadows basically works 2023-02-09 17:21:59 +03:00
65dd078f07 start moving to PIValueTree 2023-02-07 23:25:49 +03:00
3ed7976257 fix 2023-02-07 18:19:36 +03:00
4a1d58ef4c fix test 2023-02-07 18:18:44 +03:00
4e62165c80 important fix, texture manager 2023-02-07 18:11:06 +03:00
9cc870c996 fix highdpi mouse pos 2023-02-07 11:14:46 +03:00
a2695ae481 Merge branch 'master' of https://git.shs.tools/SHS/qglengine 2023-02-07 10:11:27 +03:00
2b0a5f82b5 fix selection for highdpi 2023-02-07 10:11:00 +03:00
98ccefd057 refactor texture loading, maps invert channels works 2023-02-07 08:36:59 +03:00
71d391c91b small fix 2023-02-06 20:23:31 +03:00
4e02e154c6 devicePixelRatio() support 2023-02-06 19:50:27 +03:00
7c6ca07323 add textureTransform to ObjectBase
before textures load refactoring
2023-02-05 21:23:41 +03:00
7d30802cbd source-tree refactoring 2023-02-03 21:22:25 +03:00
b20068165f .editorconfig 2022-12-16 16:45:17 +03:00
cb944b62e4 code format 2022-12-14 14:14:44 +03:00
1dfca0aeab add .clang-format file 2022-12-12 12:42:15 +03:00
953cece292 missing include 2022-12-12 10:19:54 +03:00
Бычков Андрей
0f993e6c1c get image function 2022-10-18 18:07:32 +03:00
Бычков Андрей
1afa4ea368 small fix 2022-10-13 18:23:08 +03:00
Бычков Андрей
6150882794 много исправлений 2022-10-13 17:00:24 +03:00
ce3df7d051 context reinit support 2022-10-13 08:57:27 +03:00
Бычков Андрей
3b0d1ea0e2 default unlimit fps, vsync flag 2022-10-12 14:35:01 +03:00
c865f9fc94 incorrent test includes 2022-08-10 13:21:04 +03:00
f6f0dd151c Merge pull request 'cmake refactoring' (#1) from cmake_refactor into master
Reviewed-on: https://git.shs.tools/SHS/qglengine/pulls/1
2022-08-08 16:42:41 +03:00
52056a44bb cmake refactoring 2022-08-08 15:48:06 +03:00
228 changed files with 15373 additions and 10045 deletions

223
.clang-format Normal file
View File

@@ -0,0 +1,223 @@
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignArrayOfStructures: Left
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: false
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: Always
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: CurrentLine
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
- piForeach
- piForeachC
- piForeachR
- piForeachRC
- piForeachCR
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: false
IndentPPDirectives: AfterHash
IndentExternBlock: NoIndent
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertTrailingCommas: Wrapped
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
MacroBlockBegin: "PRIVATE_DEFINITION_START|STATIC_INITIALIZER_BEGIN"
MacroBlockEnd: "PRIVATE_DEFINITION_END|STATIC_INITIALIZER_END"
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Middle
PPIndentWidth: 2
ReferenceAlignment: Middle
ReflowComments: true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatementsExceptControlMacros
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: false
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: false
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Both
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: After
Standard: c++11
StatementAttributeLikeMacros:
- Q_EMIT
- PIMETA
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
- PRIVATE_DECLARATION
- NO_COPY_CLASS
- FOREVER_WAIT
- WAIT_FOREVER
TabWidth: 4
UseCRLF: false
UseTab: AlignWithSpaces
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

6
.editorconfig Normal file
View File

@@ -0,0 +1,6 @@
root = true
[*.{h,c,cpp}]
charset = utf-8
indent_style = tab
tab_width = 4

View File

@@ -6,7 +6,11 @@ endif()
if (POLICY CMP0054) if (POLICY CMP0054)
cmake_policy(SET CMP0054 NEW) cmake_policy(SET CMP0054 NEW)
endif() endif()
project(qglengine) project(QGLEngine)
if (NOT DEFINED SHSTKPROJECT)
include(SHSTKQtMacros)
endif()
find_package(PIP REQUIRED)
find_package(QAD REQUIRED) find_package(QAD REQUIRED)
shstk_qt_founded(QtVersions) shstk_qt_founded(QtVersions)
set(_qgl_ok 0) set(_qgl_ok 0)
@@ -19,61 +23,26 @@ endif()
if (NOT _qgl_ok) if (NOT _qgl_ok)
message(WARNING "Building ${PROJECT_NAME} available only on Qt5/6!") message(WARNING "Building ${PROJECT_NAME} available only on Qt5/6!")
else() else()
qad_find_qt(Core Gui OpenGL OpenGLWidgets Xml)
find_package(OpenGL REQUIRED)
include(SHSTKQtMacros) include(SHSTKQtMacros)
set(qglengine_MAJOR 1) set(QGLEngine_MAJOR 1)
set(qglengine_MINOR 0) set(QGLEngine_MINOR 0)
set(qglengine_REVISION 0) set(QGLEngine_REVISION 0)
set(qglengine_SUFFIX "rc") set(QGLEngine_SUFFIX "rc")
set(qglengine_COMPANY SHS) set(QGLEngine_COMPANY SHS)
set(qglengine_DOMAIN org.SHS) set(QGLEngine_DOMAIN org.SHS)
if ("x${CMAKE_MODULE_PATH}" STREQUAL "x") if ("x${CMAKE_MODULE_PATH}" STREQUAL "x")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
endif() endif()
shstk_begin_project(qglengine QGLENGINE) shstk_begin_project(QGLEngine)
set(_qglengine_root_build "${CMAKE_CURRENT_BINARY_DIR}")
qad_sources(SRC) add_subdirectory(src)
qad_sources(FSRC DIR "formats")
list(APPEND SRC ${FSRC})
qad_sources(FSRC DIR "core")
list(APPEND SRC ${FSRC})
qad_wrap(${SRC} HDRS out_HDR CPPS out_CPP QMS out_QM)
file(GLOB PHS "*_p.h" "formats/*_p.h" "core/*_p.h")
list(REMOVE_ITEM out_HDR "${PHS}")
import_version(qglengine_core qglengine)
set_deploy_property(qglengine_core ${qglengine_LIB_TYPE}
LABEL "QGLEngine core library"
FULLNAME "${qglengine_DOMAIN}.qglengine_core"
COMPANY "${qglengine_COMPANY}"
INFO "QGLEngine core library")
make_rc(qglengine_core _RC)
qad_add_library(qglengine_core ${qglengine_LIB_TYPE} out_CPP ${_RC})
qad_generate_export_header(qglengine_core)
list(APPEND out_HDR "${CMAKE_CURRENT_BINARY_DIR}/qglengine_core_export.h")
list(APPEND out_HDR "${qglengine_VERSION_FILE}")
qad_target_include_directories(qglengine_core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/core")
qad_target_link_libraries(qglengine_core QAD::Widgets assimp ${OPENGL_LIBRARIES})
message(STATUS "Building QGLEngine version ${qglengine_VERSION} (${qglengine_LIB_TYPE_MSG}) for ${QtVersions}")
list(APPEND QT_MULTILIB_LIST qglengine_core)
add_subdirectory(widgets)
shstk_copy_to_parent() shstk_copy_to_parent()
shstk_qad_install("qglengine" FALSE "qglengine_core" "${out_HDR}" "out_QM")
if (NOT DEFINED ANDROID_PLATFORM)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin")
#add_subdirectory(plugin)
endif()
endif()
qad_sources(test_SRC DIR "qglview_test") shstk_install(qglengine FALSE "" "${QGLEngine_VERSION_FILE}")
qad_wrap(${test_SRC} CPPS test_CPP)
qad_add_executable(qglengine_test test_CPP)
qad_target_link_libraries(qglengine_test qglengine_core qglengine_widgets)
qad_target_include_directories(qglengine_test PRIVATE ${QAD_INCLUDES} "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/core" "${CMAKE_CURRENT_SOURCE_DIR}/widgets")
file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in") file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in")
install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules) install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules)

View File

@@ -11,22 +11,21 @@ These targets include directories and dependencies
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
cmake_policy(SET CMP0020 NEW) # Automatically link Qt executables to qtmain target on Windows cmake_policy(SET CMP0020 NEW) # Automatically link Qt executables to qtmain target on Windows
find_package(PIP REQUIRED)
find_package(QAD REQUIRED) find_package(QAD REQUIRED)
include(QtWraps) include(QtWraps)
include(SHSTKMacros) include(SHSTKMacros)
shstk_is_parent_exists(hasParent PARENT_DIRECTORY) shstk_is_parent_exists(hasParent PARENT_DIRECTORY)
shstk_set_find_dirs(qglengine QGLEngine) shstk_set_find_dirs(QGLEngine)
set(_SEARCH_DIR ${qglengine_LIBDIR})
if (NOT BUILDING_qglengine) if (NOT BUILDING_QGLEngine)
list(APPEND _SEARCH_DIR $ENV{SMSDK_DIR}/lib) shstk_find_header(QGLEngine "qglengine_version.h" ${QGLEngine_INCDIR})
shstk_find_header(qglengine QGLENGINE "qglengine_version.h" "")
endif() endif()
if(QGLENGINE_FIND_VERSION VERSION_GREATER QGLENGINE_VERSION) if(QGLEngine_FIND_VERSION VERSION_GREATER QGLEngine_VERSION)
message(FATAL_ERROR "QGLENGINE version ${QGLENGINE_VERSION} is available, but ${QGLENGINE_FIND_VERSION} requested!") message(FATAL_ERROR "QGLEngine version ${QGLEngine_VERSION} is available, but ${QGLEngine_FIND_VERSION} requested!")
endif() endif()
set(__libs "core;widgets") set(__libs "core;widgets")
@@ -40,15 +39,15 @@ foreach (_l ${__libs})
set(__libs_${_l} "") set(__libs_${_l} "")
endforeach() endforeach()
set(__deps_core "QAD::Widgets") set(__deps_core "QAD::Widgets;QAD::PIQtUtils")
set(__deps_widgets "QGLEngine::Core") set(__deps_widgets "QGLEngine::Core")
#message("find QGLEngine ${BUILDING_qglengine}") #message("find QGLEngine ${BUILDING_QGLEngine}")
if (BUILDING_qglengine) if (BUILDING_QGLEngine)
if (NOT SET_TARGETS_qglengine) if (NOT SET_TARGETS_QGLEngine)
set(SET_TARGETS_qglengine ON CACHE BOOL "") set(SET_TARGETS_QGLEngine ON CACHE BOOL "")
#message("create aliases") #message("create aliases")
foreach(_l ${__libs}) foreach(_l ${__libs})
foreach(_v ${_QT_VERSIONS_}) foreach(_v ${_QT_VERSIONS_})
@@ -71,7 +70,7 @@ else()
foreach(_l ${__libs}) foreach(_l ${__libs})
foreach(_v ${_QT_VERSIONS_}) foreach(_v ${_QT_VERSIONS_})
set(_m ${__module_${_l}}) set(_m ${__module_${_l}})
find_library(QGLENGINE_LIBRARY_${_l}${_v} qglengine_${_l}${_v} HINTS ${_SEARCH_DIR}) find_library(QGLENGINE_LIBRARY_${_l}${_v} qglengine_${_l}${_v} HINTS ${QGLEngine_LIBDIR})
#message("found ${_l}${_v} = ${QGLENGINE_LIBRARY_${_l}${_v}} (${qglengine_INCLUDES})") #message("found ${_l}${_v} = ${QGLENGINE_LIBRARY_${_l}${_v}} (${qglengine_INCLUDES})")
if((NOT TARGET QGLEngine::${_m}${_v}) AND QGLENGINE_LIBRARY_${_l}${_v}) if((NOT TARGET QGLEngine::${_m}${_v}) AND QGLENGINE_LIBRARY_${_l}${_v})
#message("imported QGLEngine::${_m}${_v} = ${QGLENGINE_LIBRARY_${_l}${_v}}") #message("imported QGLEngine::${_m}${_v} = ${QGLENGINE_LIBRARY_${_l}${_v}}")
@@ -87,7 +86,7 @@ else()
endforeach() endforeach()
set_target_properties(QGLEngine::${_m}${_v} PROPERTIES set_target_properties(QGLEngine::${_m}${_v} PROPERTIES
IMPORTED_LOCATION "${QGLENGINE_LIBRARY_${_l}${_v}}" IMPORTED_LOCATION "${QGLENGINE_LIBRARY_${_l}${_v}}"
INTERFACE_INCLUDE_DIRECTORIES "${qglengine_INCLUDES}" INTERFACE_INCLUDE_DIRECTORIES "${QGLEngine_INCLUDES}"
INTERFACE_LINK_LIBRARIES "${_deps}") INTERFACE_LINK_LIBRARIES "${_deps}")
endif() endif()
endforeach() endforeach()

View File

@@ -1,58 +0,0 @@
/*
QGL Buffer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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_;}
GLenum target() const {return target_;}
void setTarget(GLenum t) {target_ = t;}
bool isInit() const {return buffer_ != 0;}
private:
GLenum target_, usage_;
GLuint buffer_;
int prev_size;
};
#endif // GLBUFFER_H

View File

@@ -1,54 +0,0 @@
/*
QGL CubeTexture
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLCUBEMAP_H
#define GLCUBEMAP_H
#include "glshaders_types.h"
#include "chunkstream.h"
QVector<QVector3D> loadFileHDR(const QString & path, QSize * size = 0);
class CubeTexture {
public:
CubeTexture(QOpenGLExtraFunctions * f_, int _size, const GLenum & _format = GL_RGB16F);
bool init();
void destroy();
void bind(int channel = 0);
void release();
void resize(int _size) {size = _size; changed_ = true;}
void loadHDR(const QVector<QVector3D> & data, QSize sz);
void setFileHDR(const QString & path);
QString fileHDR() const {return hdr_path;}
GLenum format() const {return format_;}
void setFormat(GLenum f) {format_ = f; changed_ = true;}
GLuint id() const {return id_;}
bool isInit() const {return id_ != 0;}
void load();
private:
QOpenGLExtraFunctions * f;
bool changed_;
int size;
GLenum format_;
GLuint id_;
QString hdr_path;
};
#endif // GLCUBEMAP_H

View File

@@ -1,86 +0,0 @@
/*
QGL Framebuffer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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
{
friend class FramebufferMipmap;
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];}
GLuint depthTexture() const {return tex_d;}
GLenum target() const {return target_;}
bool isInit() const {return fbo != 0;}
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, GLenum pixel_format = GL_UNSIGNED_BYTE);
void queryImage(int index);
uint getPoint() const;
QVector<uint> getPointsByte() const;
QVector<QVector4D> getPointsFloat() 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) const;
void resize(int width, int height, bool force = false);
void bind();
void release();
void setReadBuffer(int index) {glReadBuffer(GL_COLOR_ATTACHMENT0 + index);}
void setWriteBuffer(int index);
void setWriteBuffers(const int * indeces, int count);
void setWriteBuffers(const QVector<int> & indeces) {setWriteBuffers(indeces.constData(), indeces.size());}
void setWriteBuffers();
void unsetWriteBuffers();
void enablePixelBuffer();
void setColorTextureFiltering(int index, GLenum filter);
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

View File

@@ -1,50 +0,0 @@
/*
QGL FramebufferMipmap
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QOpenGLExtraFunctions>
#include "glframebuffer_mipmap.h"
#include <QTime>
FramebufferMipmap::FramebufferMipmap(const Framebuffer & fb, int index_from_, int levels): src_fb(fb) {
index_from = index_from_;
for (int i = 0; i < levels; ++i)
fbo << new Framebuffer(fb.f, 1, false, fb.color_formats[index_from]);
}
FramebufferMipmap::~FramebufferMipmap() {
}
void FramebufferMipmap::resize() {
QSize sz = src_fb.size();
for (int i = 0; i < fbo.size(); ++i) {
sz /= 2;
fbo[i]->resize(sz.width(), sz.height());
}
}
void FramebufferMipmap::create() {
if (fbo.isEmpty()) return;
src_fb.blit(index_from, fbo[0]->id(), 0, src_fb.rect(), fbo[0]->rect(), GL_COLOR_BUFFER_BIT, GL_LINEAR);
for (int i = 0; i < fbo.size() - 1; ++i)
fbo[i]->blit(0, fbo[i + 1]->id(), 0, fbo[i]->rect(), fbo[i + 1]->rect(), GL_COLOR_BUFFER_BIT, GL_LINEAR);
}

View File

@@ -1,50 +0,0 @@
/*
QGL FramebufferMipmap
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLFRAMEBUFFER_MIPMAP_H
#define GLFRAMEBUFFER_MIPMAP_H
#include "glframebuffer.h"
class FramebufferMipmap
{
public:
FramebufferMipmap(const Framebuffer & fb, int index_from_, int levels = 2);
virtual ~FramebufferMipmap();
int levelsCount() const {return fbo.size();}
int lastLevel() const {return fbo.size() - 1;}
Framebuffer & plane(int level) {return *fbo[level];}
Framebuffer & lastPlane() {return *fbo[lastLevel()];}
int width (int level) const {return fbo[level]->wid;}
int height(int level) const {return fbo[level]->hei;}
QSize size(int level) const {return fbo[level]->size();}
QRect rect(int level) const {return fbo[level]->rect();}
void resize();
void create();
private:
int index_from;
const Framebuffer & src_fb;
QVector<Framebuffer*> fbo;
};
#endif // GLFRAMEBUFFER_MIPMAP_H

View File

@@ -1,151 +0,0 @@
/*
QGL Material
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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;
Map::Map() {
bitmap_id = 0;
color_amount = 1.f;
color_offset = 0.f;
bitmap_scale = QPointF(1., 1.);
use_bitmap = false;
_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() && use_bitmap) {
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) {
setTypes();
name = _name;
color_diffuse = Qt::white;
color_emission = Qt::black;
glass = false;
transparency = reflectivity = 0.f;
map_roughness.color_amount = 0.75f;
map_metalness.color_amount = 0.25f;
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_metalness._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 mtMetalness: return map_metalness._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_metalness.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_metalness._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_metalness._type = mtMetalness;
map_roughness._type = mtRoughness;
map_emission ._type = mtEmission ;
map_relief ._type = mtRelief ;
}
void Material::detectMaps() {
map_diffuse .use_bitmap = !map_diffuse .bitmap_path.isEmpty();
map_normal .use_bitmap = !map_normal .bitmap_path.isEmpty();
map_metalness.use_bitmap = !map_metalness.bitmap_path.isEmpty();
map_roughness.use_bitmap = !map_roughness.bitmap_path.isEmpty();
map_emission .use_bitmap = !map_emission .bitmap_path.isEmpty();
map_relief .use_bitmap = !map_relief .bitmap_path.isEmpty();
}

View File

@@ -1,120 +0,0 @@
/*
QGL Material
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 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 use_bitmap;
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();
void detectMaps();
QString name;
QColor color_diffuse;
QColor color_emission;
bool glass;
float transparency;
float reflectivity;
float iof;
float dispersion;
Map map_diffuse ;
Map map_normal ;
Map map_metalness;
Map map_roughness;
Map map_emission ;
Map map_relief ;
bool _changed;
int _index;
};
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)
.add(7, m.use_bitmap);
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)
.get(7, m.use_bitmap);
return s;
}
inline QDataStream & operator <<(QDataStream & s, const Material * m) {
ChunkStream cs;
cs.add(1, m->name).add(2, m->color_diffuse).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_metalness).add(12, m->map_roughness).add(13, m->map_emission);
s << (cs.data()); return s;
}
inline QDataStream & operator >>(QDataStream & s, Material *& m) {
m = new Material();
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 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_metalness); break;
case 12: cs.get(m->map_roughness); break;
case 13: cs.get(m->map_emission); break;
}
}
m->setTypes();
return s;
}
#endif // GLMATERIAL_H

View File

@@ -1,104 +0,0 @@
/*
QGL Mesh
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 "glvertexobject.h"
class Mesh
{
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();
void init (QOpenGLExtraFunctions * f);
void destroy (QOpenGLExtraFunctions * f);
bool rebuffer(QOpenGLExtraFunctions * f);
void draw (QOpenGLExtraFunctions * f, int count, int type = 0);
void clear();
void loadObject (QOpenGLExtraFunctions * f, const QGLEngineShaders::Object & object, int type = 0);
void loadObjects (QOpenGLExtraFunctions * f, const QVector<QGLEngineShaders::Object> & objects, int type = 0);
void loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels, int type = 0);
int verticesCount() const {return vertices_.size();}
int trianglesCount() const {return triangles_.size();}
int linesCount() const {return lines_.size();}
bool isInit() const {return buffer_geom.isInit();}
bool isEmpty() const {return vertices_.isEmpty();}
uint hash() const;
bool isObjectsChanged (int type = 0) const;
bool isSelectionChanged (int type = 0) const;
void setObjectsChanged (int type = 0, bool yes = true);
void setSelectionChanged(int type = 0, bool yes = true);
void setAllObjectsChanged (bool yes = true);
void setAllSelectionChanged(bool yes = true);
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 flipNormals();
void append(const Mesh * m);
bool saveToFile(const QString & filename);
bool loadFromFile(const QString & filename);
Box3D boundingBox() const;
private:
void calculateNormals();
void calculateTangents();
VertexObject * vaoByType(int type);
QVector<QVector3D> vertices_, normals_, tangents_, bitangents_;
QVector<QVector2D> texcoords_;
QVector< Vector3i> triangles_;
QVector< Vector2i> lines_;
QVector<QGLEngineShaders::Vertex> data_;
GLenum geom_type;
Buffer buffer_geom, buffer_ind;
QMap<int, VertexObject * > vao_map;
mutable uint hash_;
mutable bool hash_changed;
int vert_count;
bool changed;
};
QDataStream & operator <<(QDataStream & s, const Mesh * m);
QDataStream & operator >>(QDataStream & s, Mesh *& m);
#endif // GLMESH_H

View File

@@ -1,55 +0,0 @@
/*
QGL Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 radius = 1., float end_angle = 360.);
Mesh * disc(int segments, float radius = 1., float end_angle = 360.);
Mesh * cone(int segments, float radius = 1., float height = 1.);
Mesh * cylinder(int segments, float radius = 1., float height = 1., float end_angle = 360.);
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 * lineFrame(QVector3D p0, QVector3D p1);
Mesh * cubeFrame(float width = 1., float length = 1., float height = 1.);
Mesh * ellipsoidFrame(int segments_wl, int segments_h, float radius = 1.);
Mesh * coneFrame(int segments, float radius = 1., float height = 1.);
}
#endif // GLPRIMITIVE_CUBE_H

View File

@@ -1,31 +0,0 @@
/*
QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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, bool add_qgl = true, const QStringList & defines = QStringList());
bool loadShaders(QOpenGLShaderProgram *& prog, const QStringList & files, bool add_qgl = true, const QStringList & defines = QStringList());
}
#endif // GLSHADERS_H

View File

@@ -1,121 +0,0 @@
/*
QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 = 256 ;
const char qgl_common_head[] =
"#version 400 core\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 inverse(mat3(qgl_ViewMatrix * qgl_ModelMatrix));}\n"
"mat3 qgl_getTangentMatrix() {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.rgb = t.rgb * 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_METALNESS 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_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"
" vec4 decay_intensity;\n"
" vec4 angles;\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[256];\n"
"};\n"
"layout (std140) uniform QGLLightPositionData {\n"
" QGLLightPosition qgl_light_position[256];\n"
"};\n"
"uniform sampler2DArray qgl_texture_array[2];\n"
"";
}
#endif // GLSHADERS_HEADERS_H

View File

@@ -1,97 +0,0 @@
/*
QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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(1., 1., 1., 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;
map[mtMetalness].amount = 0.25;
}
void QGLEngineShaders::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 QGLEngineShaders::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 QGLEngineShaders::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);
}

View File

@@ -1,142 +0,0 @@
/*
QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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,
mtMetalness = 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_emission;
GLfloat transparency;
GLfloat reflectivity;
GLfloat iof;
GLfloat dispersion;
QGLMap map[QGL_MAPS_COUNT];
};
struct QGLLightParameter {
QVector4D color;
QVector4D decay_intensity; // [^0, ^1, ^2, intensity]
QVector4D angles; // [start, cos(start), end, cos(end)]
};
struct QGLLightPosition {
QVector4D position;
QVector4D direction;
};
#pragma pack(pop)
void prepareDrawGeom(QOpenGLExtraFunctions * f);
void prepareDrawObj (QOpenGLExtraFunctions * f);
void prepareDrawSel (QOpenGLExtraFunctions * f);
}
#endif // GLSHADERS_TYPES_H

View File

@@ -1,54 +0,0 @@
/*
QGL Texture2DArray
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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
{
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

View File

@@ -1,304 +0,0 @@
/*
QGLView Types
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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>
#include "qglengine_version.h"
#include "qglengine_core_export.h"
//#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 T> inline void piSwap(T & f, T & s) {T 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_);
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 Framebuffer;
class FramebufferMipmap;
class VertexObject;
class Mesh;
class Scene;
class RendererBase;
class Renderer;
class RendererMaterial;
class RendererService;
class RendererSelection;
enum RenderPass {
rpSolid,
rpTransparent,
};
typedef QList<ObjectBase*> ObjectBaseList;
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 void normalizeAngleRad(float & a) {while (a < 0.) a += M_2PI; while (a >= M_2PI) a -= M_2PI;}
inline void normalizeAngleDeg360(float & a) {while (a < 0.) a += 360. ; while (a >= 360. ) a -= 360. ;}
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

View File

@@ -1,62 +0,0 @@
/*
QGL VertexObject
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLVERTEXOBJECT_H
#define GLVERTEXOBJECT_H
#include "glbuffer.h"
#include "glshaders_types.h"
class VertexObject
{
public:
VertexObject();
~VertexObject();
void init (QOpenGLExtraFunctions * f);
void destroy (QOpenGLExtraFunctions * f);
void bind (QOpenGLExtraFunctions * f);
void release (QOpenGLExtraFunctions * f);
void bindBuffers (QOpenGLExtraFunctions * f, Buffer & geom, Buffer & elem, bool force = false);
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);
void draw(QOpenGLExtraFunctions * f, GLenum geom_type, int vert_cout, int obj_count);
GLuint ID() const {return vao_;}
bool isInit() const {return vao_ != 0;}
bool isObjectsChanged() const {return objects_changed;}
bool isSelectionChanged() const {return selected_changed;}
void setObjectsChanged(bool yes = true) {objects_changed = yes;}
void setSelectionChanged(bool yes = true) {selected_changed = yes;}
private:
void loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size);
GLuint vao_;
Buffer buffer_obj, buffer_sel;
bool buffers_binded, objects_changed, selected_changed;
};
#endif // GLVERTEXOBJECT_H

View File

@@ -1,126 +0,0 @@
/*
QGL HDR
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hdr_p.h"
#include <qmath.h>
#include <QByteArray>
#define RGBE_DATA_RED 2
#define RGBE_DATA_GREEN 1
#define RGBE_DATA_BLUE 0
/* number of floats per pixel */
#define RGBE_DATA_SIZE 3
void rgbe2float(float *red, float *green, float *blue, uchar rgbe[4]) {
float f;
if (rgbe[3]) {
f = static_cast<float>(ldexp(1.0,rgbe[3]-(int)(128+8)));
*red = rgbe[0] * f;
*green = rgbe[1] * f;
*blue = rgbe[2] * f;
}
else
*red = *green = *blue = 0.0;
}
/* simple read routine. will not correctly handle run length encoding */
bool RGBE_ReadPixels(QDataStream * fp, float * data, int numpixels) {
uchar rgbe[4];
while(numpixels-- > 0) {
if (fp->readRawData((char*)rgbe, sizeof(rgbe)) < 1)
return false;
rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE],rgbe);
data += RGBE_DATA_SIZE;
}
return true;
}
bool RGBE_ReadPixels_RLE(QDataStream * fp, float * data, int scanline_width, int num_scanlines) {
uchar rgbe[4], *ptr, *ptr_end;
int i, count;
uchar buf[2];
QByteArray scanline_buffer;
if ((scanline_width < 8)||(scanline_width > 0x7fff))
/* run length encoding is not allowed so read flat*/
return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines);
scanline_buffer.resize(4*scanline_width);
/* read in each successive scanline */
while(num_scanlines > 0) {
if (fp->readRawData((char*)rgbe,sizeof(rgbe)) < 1) {
return false;
}
if ((rgbe[0] != 2)||(rgbe[1] != 2)||(rgbe[2] & 0x80)) {
/* this file is not run length encoded */
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],&data[RGBE_DATA_BLUE],rgbe);
data += RGBE_DATA_SIZE;
return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines-1);
}
if ((((int)rgbe[2])<<8 | rgbe[3]) != scanline_width) {
return false;
}
ptr = (uchar*)scanline_buffer.data();
/* read each of the four channels for the scanline into the buffer */
for(i=0;i<4;i++) {
ptr_end = (uchar*)scanline_buffer.data() + ((i+1)*scanline_width);
while(ptr < ptr_end) {
if (fp->readRawData((char*)buf,sizeof(buf[0])*2) < 1) {
return false;
}
if (buf[0] > 128) {
/* a run of the same value */
count = buf[0]-128;
if ((count == 0)||(count > ptr_end - ptr)) {
return false;
}
while(count-- > 0)
*ptr++ = buf[1];
}
else {
/* a non-run */
count = buf[0];
if ((count == 0)||(count > ptr_end - ptr)) {
return false;
}
*ptr++ = buf[1];
if (--count > 0) {
if (fp->readRawData((char*)ptr,sizeof(*ptr)*count) < 1) {
return false;
}
ptr += count;
}
}
}
}
/* now convert data from buffer into floats */
for(i=0;i<scanline_width;i++) {
rgbe[0] = scanline_buffer[i];
rgbe[1] = scanline_buffer[i+scanline_width];
rgbe[2] = scanline_buffer[i+2*scanline_width];
rgbe[3] = scanline_buffer[i+3*scanline_width];
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],
&data[RGBE_DATA_BLUE],rgbe);
data += RGBE_DATA_SIZE;
}
num_scanlines--;
}
return true;
}

View File

@@ -1,26 +0,0 @@
/*
QGL HDR
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HDR_P_H
#define HDR_P_H
#include <QDataStream>
bool RGBE_ReadPixels_RLE(QDataStream * fp, float * data, int scanline_width, int num_scanlines);
#endif // HDR_P_H

View File

@@ -1,27 +0,0 @@
/*
QGL Loader Assimp
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOADER_ASSIMP_H
#define LOADER_ASSIMP_H
#include "gltypes.h"
Scene * loadScene(const QString & filepath);
QStringList supportedFormats();
#endif // LOADER_ASSIMP_H

View File

@@ -1,28 +0,0 @@
/*
QGL Loader QGL
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOADER_QGL_H
#define LOADER_QGL_H
#include "gltypes.h"
#include <QFileInfo>
Scene * loadFromQGLFile(const QString & filepath);
bool saveToQGLFile(const QString & filepath, const Scene * scene);
#endif // LOADER_QGL_H

View File

@@ -1,91 +0,0 @@
/*
QGL Camera
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gltypes.h"
#include "qglview.h"
Camera::Camera() {
type_ = glCamera;
fov_ = 60.;
roll_ = 0.;
depth_start = 0.1f;
mirror_x = mirror_y = false;
}
QMatrix4x4 Camera::offsetMatrix() const {
QMatrix4x4 ret;
ret.translate(parent_ ? -offset_ : -aim());
return ret;
}
void Camera::assign(const Camera & c) {
trans = c.trans;
aim_dist = c.aim_dist;
fov_ = c.fov_;
mirror_x = c.mirror_x;
mirror_y = c.mirror_y;
depth_start = c.depth_start;
buildTransform();
}
ObjectBase * Camera::clone(bool withChildren) {
Camera * o = new Camera(*this);
o->is_init = false;
o->name_ = name_;
o->scene_ = nullptr;
o->children_.clear();
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
o->trans = trans;
o->aim_dist = aim_dist;
o->fov_ = fov_;
o->roll_ = roll_;
o->mirror_x = mirror_x;
o->mirror_y = mirror_y;
o->depth_start = depth_start;
o->meta = meta;
return o;
}
QMatrix4x4 Camera::viewMatrix() const {
QMatrix4x4 ret;
//qDebug() << pos() << aim();
ret.translate(0., 0., -distance());
ret.rotate(-roll_, 0., 0., 1.);
ret *= trans.matrixRotateScale().inverted();
if (parent_) {
QMatrix4x4 pmat = parent_->worldTransform();
offset_ = pmat.column(3).toVector3D();
pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.;
pmat.translate(aim());
ret *= pmat.inverted();
}
return ret;
}
QMatrix4x4 Camera::projectionMatrix(double aspect) const {
return glMatrixPerspective(fov_, aspect, depth_start);
}

View File

@@ -1,65 +0,0 @@
/*
QGL Camera
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLCAMERA_H
#define GLCAMERA_H
#include "globject.h"
class Camera: public AimedObject
{
friend QDataStream & operator <<(QDataStream & s, const ObjectBase * p);
friend QDataStream & operator >>(QDataStream & s, ObjectBase *& p);
public:
Camera();
void setFOV(const float & f) {fov_ = f;}
void setAngles(const QVector3D & a) {setRotation(a);}
void setAngleZ(const float & a) {setRotationZ(a);}
void setAngleXY(const float & a) {setRotationX(a);}
void setAngleRoll(const float & a) {roll_ = a;}
void setDepthStart(const float & d) {depth_start = d;}
void setMirrorX(bool yes) {mirror_x = yes;}
void setMirrorY(bool yes) {mirror_y = yes;}
float FOV() const {return fov_;}
float angleZ() const {return rotationZ();}
float angleXY() const {return rotationX();}
float angleRoll() const {return roll_;}
float depthStart() const {return depth_start;}
bool isMirrorX() const {return mirror_x;}
bool isMirrorY() const {return mirror_y;}
void assign(const Camera & c);
virtual ObjectBase * clone(bool withChildren = true);
QMatrix4x4 viewMatrix() const;
QMatrix4x4 projectionMatrix(double aspect) const;
QMatrix4x4 offsetMatrix() const;
QMatrix4x4 fullViewMatrix() const {return viewMatrix() * offsetMatrix();}
private:
mutable QVector3D offset_;
GLfloat fov_, roll_;
GLfloat depth_start;
bool mirror_x;
bool mirror_y;
};
#endif // GLCAMERA_H

View File

@@ -1,717 +0,0 @@
/*
QGL ObjectBase & Light
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "globject.h"
#include "glcamera.h"
#include "glscene.h"
#include "glmesh.h"
#include <chunkstream.h>
//static int _count = 0;
ObjectBase::ObjectBase(Mesh * geom, Material * mat) {
type_ = glMesh;
render_mode = View;
prev_pass = rpSolid;
parent_ = nullptr;
color_ = Qt::white;
is_root = is_init = selected_ = false;
visible_ = accept_fog = accept_light = cast_shadow = rec_shadow = select_ = true;
line_width = -1.;
id_ = 0;
blend_src = GL_SRC_ALPHA;
blend_dest = GL_ONE_MINUS_SRC_ALPHA;
type_ = glMesh;
raw_matrix = selected_aim = false;
mat_.setToIdentity();
scene_ = nullptr;
mesh_ = geom;
material_ = mat;
//qDebug() << "ObjectBase, now" << ++_count;
}
ObjectBase::~ObjectBase() {
//qDebug() << "~ObjectBase, now" << --_count;
if (parent_) parent_->children_.removeAll(this);
if (scene_) {
scene_->__objectDeleted(this);
scene_->setTreeChanged();
scene_->setTreeStructChanged();
}
foreach (ObjectBase * c, children_) {
c->parent_ = nullptr;
delete c;
}
}
ObjectBase * ObjectBase::clone(bool withChildren) {
ObjectBase * o = new ObjectBase();
o->prev_pass = prev_pass;
o->is_init = false;
o->accept_light = accept_light;
o->accept_fog = accept_fog;
o->visible_ = visible_;
o->color_ = color_;
o->type_ = type_;
o->raw_matrix = raw_matrix;
o->mat_ = mat_;
o->trans = trans;
o->itransform_ = itransform_;
o->bound = bound;
o->name_ = name_;// + "_copy";
o->blend_src = blend_src;
o->blend_dest = blend_dest;
o->pos_h = pos_h;
o->material_ = material_;
o->mesh_ = mesh_;
o->meta = meta;
o->scene_ = nullptr;
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
return o;
}
void ObjectBase::destroy() {
if (mesh_) delete mesh_;
}
void ObjectBase::init() {
calculateBoundingBox();
//material_.reflection.create();
//qDebug() << "init" << vbo.buffer_;
is_init = true;
}
RenderPass ObjectBase::pass() const {
RenderPass ret = rpSolid;
if (material_)
if (material_->hasTransparency())
ret = rpTransparent;
return ret;
}
void ObjectBase::setScene(Scene * v) {
scene_ = v;
foreach (ObjectBase * c, children_)
c->setScene(v);
}
void ObjectBase::addChild(ObjectBase * o) {
if (o == this) return;
if (o->parent_)
o->parent_->children_.removeAll(o);
children_ << o;
o->parent_ = this;
o->setScene(scene_);
o->buildTransform();
/*if (scene_) {
ObjectBaseList cl = o->children(true);
cl << o;
//foreach (ObjectBase * i, cl) {
// emit view_->objectAdded(i);
//}
}*/
setSceneTreeChanged();
}
void ObjectBase::removeChild(ObjectBase * o) {
if (o == this) return;
children_.removeAll(o);
o->parent_ = nullptr;
o->buildTransform();
setSceneTreeChanged();
}
void ObjectBase::removeChild(int index) {
children_[index]->parent_ = nullptr;
children_[index]->buildTransform();
children_.removeAt(index);
setSceneTreeChanged();
}
void ObjectBase::clearChildren(bool deleteAll) {
foreach (ObjectBase * i, children_) {
i->scene_ = nullptr;
i->parent_ = nullptr;
i->clearChildren(deleteAll);
if (deleteAll) {
delete i;
} else {
i->buildTransform();
}
}
children_.clear();
setSceneTreeChanged();
}
ObjectBase * ObjectBase::child(int index) {
if (index < 0 || index >= children_.size()) return nullptr;
return children_[index];
}
ObjectBase * ObjectBase::child(const QString & name) {
foreach (ObjectBase * i, children_)
if (i->name_ == name) return i;
return nullptr;
}
const ObjectBase * ObjectBase::child(int index) const {
if (index < 0 || index >= children_.size()) return nullptr;
return children_[index];
}
const ObjectBase * ObjectBase::child(const QString & name) const {
foreach (ObjectBase * i, children_)
if (i->name_ == name) return i;
return nullptr;
}
ObjectBaseList ObjectBase::children(bool all_) {
if (!all_) return children_;
ObjectBaseList cl;
addChildren(cl, this);
return cl;
}
bool ObjectBase::isVisible(bool check_parents) const {
if (!check_parents) return visible_;
if (!visible_) return false;
ObjectBase * p = parent_;
while (p) {
if (!p->visible_) return false;
p = p->parent_;
}
return true;
}
void ObjectBase::setVisible(bool v) {
visible_ = v;
setSceneTreeChanged();
}
void ObjectBase::rotateZ(GLfloat a) {
raw_matrix = false;
trans.setRotationZ(trans.rotationZ() + a);
//angles_.setZ(angles_.z() + a);
//while (angles_.z() < -360.f) angles_.setZ(angles_.z() + 360.f);
//while (angles_.z() > 360.f) angles_.setZ(angles_.z() - 360.f);
buildTransform();
}
void ObjectBase::setRotationZ(GLfloat a) {
raw_matrix = false;
trans.setRotationZ(a);
//angles_.setZ(a);
//while (angles_.z() < -360.f) angles_.setZ(angles_.z() + 360.f);
//while (angles_.z() > 360.f) angles_.setZ(angles_.z() - 360.f);
buildTransform();
}
void ObjectBase::setTransform(const Transform & t) {
trans = t;
buildTransform();
}
void ObjectBase::addChildren(ObjectBaseList & list, ObjectBase * where) {
foreach (ObjectBase * i, where->children_) {
list << i;
addChildren(list, i);
}
}
void ObjectBase::calculateBoundingBox() {
bound = Box3D();
if (mesh_) {
bound = mesh_->boundingBox();
QVector<QVector3D> c = bound.corners(), tc;
foreach (QVector3D p, c)
tc << (itransform_ * QVector4D(p, 1)).toVector3D();
bound = Box3D(tc);
}
foreach (ObjectBase * i, children_) {
i->calculateBoundingBox();
bound |= i->boundingBox();
}
}
void ObjectBase::updateTransform() {
buildTransform(true);
}
void ObjectBase::setProperty(const QString & pn, const QVariant & v) {
meta[pn] = v;
}
QVariant ObjectBase::property(const QString & pn, bool * exists) const {
if (exists) *exists = meta.contains(pn);
return meta.value(pn);
}
bool ObjectBase::hasProperty(const QString & pn) const {
return meta.contains(pn);
}
void ObjectBase::removeProperty(const QString & pn) {
meta.remove(pn);
}
void ObjectBase::setMatrix(const QMatrix4x4 & t) {
//raw_matrix = true;
//mat_ = t;
//pos_ = mat_.column(3).toVector3D();
//mat_.setColumn(3, QVector4D(0., 0., 0., 1.));
raw_matrix = false;
trans.setMatrix(t);
buildTransform();
}
QMatrix4x4 ObjectBase::matrix() const {
return trans.matrix();
}
QVector3D ObjectBase::inParentSpace(const QVector3D & v) const {
if (!parent_) return v;
return (parent_->matrix() * QVector4D(v, 1)).toVector3D();
}
void ObjectBase::transferTransformToChildren(bool only_scale) {
QMatrix4x4 m = trans.matrix();
if (only_scale) m = trans.matrixScale();
foreach (ObjectBase * i, children_)
i->trans.setMatrix(m * i->trans.matrix());
if (only_scale) resetScale();
else setMatrix(QMatrix4x4());
}
void ObjectBase::cleanTree() {
for (int i = 0; i < children_.size(); ++i) {
ObjectBase * o = children_[i];
if (!o->hasChildren() && !o->mesh() && (o->type() == glMesh)) {
delete o;
--i;
}
o->cleanTree();
}
}
bool ObjectBase::isSelected(bool check_parents) const {
if (!check_parents) return selected_;
if (selected_) return true;
ObjectBase * p = parent_;
while (p) {
if (p->selected_) return true;
p = p->parent_;
}
return false;
}
void ObjectBase::setSelected(bool yes) {
//qDebug() << "select" << name() << view_;
if (select_)
selected_ = yes;
if (!selected_)
selected_aim = false;
}
ObjectBase * ObjectBase::selectedParent() const {
ObjectBase * p = parent_;
while (p) {
if (p->selected_) return p;
p = p->parent_;
}
return 0;
}
void ObjectBase::setMaterial(Material * m, bool with_children) {
material_ = m;
if (with_children)
foreach (ObjectBase * i, children_) i->setMaterial(m, true);
setObjectsChanged();
if (scene_) scene_->mat_changed = scene_->tree_changed = true;
}
void ObjectBase::setColor(QColor c, bool with_children) {
color_ = c;
if (with_children)
foreach (ObjectBase * i, children_) i->setColor(c, true);
setObjectsChanged();
}
void ObjectBase::setMesh(Mesh * v) {
if (scene_)
v = scene_->attachMesh(v);
mesh_ = v;
setSceneTreeChanged();
setObjectsChanged();
}
void ObjectBase::buildTransform(bool force) {
if (force) trans.setDirty();
itransform_.setToIdentity();
ObjectBase * p = parent_;
if (p)
itransform_ = p->itransform_;
//if (raw_matrix) {
// itransform_.translate(pos_);
// itransform_ *= mat_;
// //qDebug() << "raw_matrix" << itransform_;
//} else
localTransform(itransform_);
//qDebug() << name_ << itransform_;
foreach (ObjectBase * i, children_)
i->buildTransform(force);
setObjectsChanged();
}
void ObjectBase::initInternal() {
init();
foreach (ObjectBase * i, children_) i->initInternal();
}
void ObjectBase::localTransform(QMatrix4x4 & m) {
m *= trans.matrix();
}
void ObjectBase::setSceneTreeChanged() {
if (scene_) {
scene_->setTreeChanged();
scene_->setTreeStructChanged();
}
setObjectsChanged();
}
void ObjectBase::setObjectsChanged() {
int p = pass();
if (mesh_) {
mesh_->setObjectsChanged (p, true);
mesh_->setSelectionChanged(p, true);
if (prev_pass != p) {
mesh_->setObjectsChanged (prev_pass, true);
mesh_->setSelectionChanged(prev_pass, true);
}
}
prev_pass = p;
}
QMatrix4x4 ObjectBase::worldMatrix(QMatrix4x4 parent) const {
QMatrix4x4 mat;
//mat.translate(pos_);
//if (raw_matrix) {
// mat *= mat_;
//} else {
// if (angles_.z() != 0.f) mat.rotate(angles_.z(), 0., 0., 1.);
// if (angles_.y() != 0.f) mat.rotate(angles_.y(), 0., 1., 0.);
// if (angles_.x() != 0.f) mat.rotate(angles_.x(), 1., 0., 0.);
// mat.scale(scale_);
//}
mat = trans.matrix();
return parent * mat;
}
AimedObject::AimedObject() {
aim_dist = 1.;
}
QVector3D AimedObject::worldAim() const {
QVector3D ret = worldPos() + worldDirection() * aim_dist;
return ret;
}
void AimedObject::setAim(const QVector3D & p) {
QVector3D dir = p - pos();
trans.setRotation(Transform::fromDirection(dir, trans.rotationY()));
aim_dist = dir.length();
buildTransform();
//if (!p.isNull())
//qDebug() << "setAim" << p << aim() << worldAim();
}
QVector3D AimedObject::direction() const {
return trans.direction();
}
void AimedObject::setDirection(const QVector3D & d) {
//double len = qMax(aim_.length(), 0.001f);
//aim_ = d.normalized() * len;
buildTransform();
}
void AimedObject::flyCloser(double s) {
double tl = 1. / (1. + s);
move(direction() * aim_dist * (1. - tl));
aim_dist *= tl;
}
void AimedObject::flyFarer(double s) {
double tl = 1. * (1. + s);
move(direction() * aim_dist * (1. - tl));
aim_dist *= tl;
}
void AimedObject::flyToDistance(double d) {
move(direction() * (aim_dist - d));
aim_dist = d;
//qDebug() << d << (aim() - pos()).length() << aim();
}
void AimedObject::moveForward(const float & x, bool withZ) {
QVector3D dv = itransform_.mapVector(QVector3D(0, 0, -x));
if (!withZ) dv[2] = 0.;
move(dv);
}
void AimedObject::moveLeft(const float & x, bool withZ) {
QVector3D dv = itransform_.mapVector(QVector3D(-x, 0, 0));
if (!withZ) dv[2] = 0.;
move(dv);
}
void AimedObject::moveUp(const float & x, bool onlyZ) {
QVector3D dv = itransform_.mapVector(QVector3D(0, x, 0));
if (onlyZ) dv[0] = dv[1] = 0.;
move(dv);
}
void AimedObject::orbitZ(const float & a) {
QVector3D pa = aim();
rotateZ(-a);
move(pa - aim());
}
void AimedObject::orbitXY(const float & a) {
QVector3D pa = aim();
rotateX(-a);
move(pa - aim());
}
void AimedObject::transformChanged() {
}
Light::Light(): AimedObject(), shadow_map(0, true, GL_R16F) {
type_ = glLight;
light_type = Omni;
intensity = 1.;
angle_start = angle_end = 180.;
decay_linear = decay_quadratic = decay_start = 0.;
decay_const = decay_end = 1.;
setDirection(0, 0, -1.);
}
Light::Light(const QVector3D & p, const QColor & c, float i): AimedObject(), shadow_map(0, true, GL_R16F) {
type_ = glLight;
light_type = Omni;
intensity = i;
color_ = c;
angle_start = angle_end = 180.;
decay_linear = decay_quadratic = decay_start = 0.;
decay_const = decay_end = 1.;
setPos(p);
setDirection(0, 0, -1.);
}
ObjectBase * Light::clone(bool withChildren) {
Light * o = new Light(*this);
//GLObjectBase::clone(withChildren);
o->is_init = false;
o->name_ = name_;// + "_copy";
o->scene_ = nullptr;
o->children_.clear();
if (withChildren) {
for (int i = 0; i < children_.size(); ++i)
o->addChild(children_[i]->clone(withChildren));
}
o->color_ = color_;
o->light_type = light_type;
o->trans = trans;
o->aim_dist = aim_dist;
o->angle_start = angle_start;
o->angle_end = angle_end;
o->intensity = intensity;
o->decay_const = decay_const;
o->decay_linear = decay_linear;
o->decay_quadratic = decay_quadratic;
o->meta = meta;
return o;
}
void Light::apply() {
if (scene_) scene_->setLightsChanged();
}
QDataStream & operator <<(QDataStream & s, const ObjectBase * p) {
ChunkStream cs;
//qDebug() << "place" << p->name() << "...";
cs.add(1, int(p->type_)).add(2, p->accept_light).add(3, p->accept_fog).add(4, p->visible_)
.add(5, p->cast_shadow).add(6, p->rec_shadow).add(7, p->raw_matrix).add(8, p->line_width)
.add(9, int(p->render_mode)).add(14, p->mat_).add(16, p->children_.size())
.add(17, p->name_).add(18, p->meta).add(19, p->color_).add(20, p->trans);
//qDebug() << "place self done";
if (p->type_ == ObjectBase::glLight) {
//qDebug() << "place light ...";
const Light * l = (const Light*)p;
cs.add(101, l->angle_start).add(102, l->angle_end).add(103, l->intensity)
.add(104, l->decay_const).add(105, l->decay_linear).add(106, l->decay_quadratic)
.add(107, l->decay_start).add(108, l->decay_end).add(109, int(l->light_type))
.add(111, l->distance());
}
if (p->type_ == ObjectBase::glCamera) {
//qDebug() << "place camera ...";
const Camera * c = (const Camera*)p;
cs.add(200, c->aim()).add(201, c->fov_).add(202, c->depth_start)
.add(206, c->mirror_x).add(207, c->mirror_y).add(208, c->distance())
.add(209, c->roll_);
}
//qDebug() << "place" << p->name() << cs.data().size() << s.device()->size();
s << cs.data();
foreach (const ObjectBase * c, p->children_)
s << c;
return s;
}
QDataStream & operator >>(QDataStream & s, ObjectBase *& p) {
ChunkStream cs(s);
p = nullptr;
int ccnt = 0;
Light * l = nullptr;
Camera * c = nullptr;
//qDebug() << "read obj ...";
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: {
ObjectBase::Type type = (ObjectBase::Type)cs.getData<int>();
switch (type) {
case ObjectBase::glMesh: p = new ObjectBase(); break;
case ObjectBase::glLight: p = new Light(); l = (Light*)p; break;
case ObjectBase::glCamera: p = new Camera(); c = (Camera*)p; break;
default : break;
}
if (p) p->type_ = type;
} break;
case 2: if (p) p->accept_light = cs.getData<bool>(); break;
case 3: if (p) p->accept_fog = cs.getData<bool>(); break;
case 4: if (p) p->visible_ = cs.getData<bool>(); break;
case 5: if (p) p->cast_shadow = cs.getData<bool>(); break;
case 6: if (p) p->rec_shadow = cs.getData<bool>(); break;
case 7: if (p) p->raw_matrix = cs.getData<bool>(); break;
case 8: if (p) p->line_width = cs.getData<float>(); break;
case 9: if (p) p->render_mode = (ObjectBase::RenderMode)cs.getData<int>(); break;
case 14: if (p) p->mat_ = cs.getData<QMatrix4x4>(); break;
case 16: if (p) ccnt = cs.getData<int>(); break;
case 17: if (p) p->name_ = cs.getData<QString>(); break;
case 18: if (p) p->meta = cs.getData<QVariantMap>(); break;
case 19: if (p) p->color_ = cs.getData<QColor>(); break;
case 20: if (p) p->trans = cs.getData<Transform>(); break;
case 100: if (l) l->setAim(cs.getData<QVector3D>()); break;
case 101: if (l) l->angle_start = cs.getData<GLfloat>(); break;
case 102: if (l) l->angle_end = cs.getData<GLfloat>(); break;
case 103: if (l) l->intensity = cs.getData<GLfloat>(); break;
case 104: if (l) l->decay_const = cs.getData<GLfloat>(); break;
case 105: if (l) l->decay_linear = cs.getData<GLfloat>(); break;
case 106: if (l) l->decay_quadratic = cs.getData<GLfloat>(); break;
case 107: if (l) l->decay_start = cs.getData<GLfloat>(); break;
case 108: if (l) l->decay_end = cs.getData<GLfloat>(); break;
case 109: if (l) l->light_type = (Light::Type)cs.getData<int>(); break;
case 111: if (l) l->setDistance(cs.getData<double>()); break;
case 200: if (c) c->setAim(cs.getData<QVector3D>()); break;
case 201: if (c) c->setFOV(cs.getData<GLfloat>()); break;
case 202: if (c) c->setDepthStart(cs.getData<GLfloat>()); break;
case 206: if (c) c->mirror_x = cs.getData<bool>(); break;
case 207: if (c) c->mirror_y = cs.getData<bool>(); break;
case 208: if (c) c->setDistance(cs.getData<double>()); break;
case 209: if (c) c->roll_ = cs.getData<GLfloat>(); break;
}
}
//qDebug() << p->name() << ccnt;
for (int i = 0; i < ccnt; ++i) {
ObjectBase * c = nullptr;
s >> c;
if (!c) continue;
c->parent_ = p;
p->children_ << c;
}
p->buildTransform();
return s;
}

View File

@@ -1,303 +0,0 @@
/*
QGL ObjectBase & Light
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLOBJECT_H
#define GLOBJECT_H
#include "glframebuffer.h"
#include "glmaterial.h"
#include "gltypes.h"
#include "gltransform.h"
class ObjectBase
{
friend class Scene;
friend class RendererSelection;
friend QDataStream & operator <<(QDataStream & s, const ObjectBase * p);
friend QDataStream & operator >>(QDataStream & s, ObjectBase *& p);
friend QDataStream & operator >>(QDataStream & s, Scene *& p);
public:
enum Type {glMesh, glLight, glCamera, glParticlesSystem};
enum RenderMode {View = 0, Point = GL_POINT, Line = GL_LINE, Fill = GL_FILL};
explicit ObjectBase(Mesh * geom = 0, Material * mat = 0);
virtual ~ObjectBase();
virtual ObjectBase * clone(bool withChildren = true);
void destroy();
QString name() const {return name_;}
void setName(const QString & name) {name_ = name;}
virtual void init();
virtual void update() {}
bool isInit() const {return is_init;}
Type type() const {return type_;}
RenderPass pass() const;
uint id() const {return id_;}
RenderMode renderMode() const {return render_mode;}
void setRenderMode(RenderMode mode) {render_mode = mode;}
float lineWidth() const {return line_width;}
void setLineWidth(const float & width) {line_width = width;}
ObjectBase * parent() {return parent_;}
void setParent(ObjectBase * o) {parent_ = o;}
bool hasParent() const {return parent_ != nullptr;}
bool hasChildren() const {return !children_.isEmpty();}
void setScene(Scene * v);
void addChild(ObjectBase * o);
void removeChild(ObjectBase * o);
void removeChild(int index);
void clearChildren(bool deleteAll = false);
int childCount() const {return children_.size();}
ObjectBase * child(int index);
ObjectBase * child(const QString & name);
const ObjectBase * child(int index) const;
const ObjectBase * child(const QString & name) const;
ObjectBaseList children(bool all_ = false);
bool isVisible(bool check_parents = false) const;
bool isHidden(bool check_parents = false) const {return !isVisible(check_parents);}
void setVisible(bool v);
void setHidden(bool v) {setVisible(!v);}
void show() {setVisible(true);}
void hide() {setVisible(false);}
bool isReceiveShadows() const {return rec_shadow;}
bool isCastShadows() const {return cast_shadow;}
void setReceiveShadows(bool on) {rec_shadow = on;}
void setCastShadows(bool on) {cast_shadow = on;}
void move(const QVector3D & dv) {trans.setTranslation(pos() + dv); buildTransform();}
void moveTo(const QVector3D & dv) {trans.setTranslation(dv); buildTransform();}
void move(GLfloat dx, GLfloat dy, GLfloat dz = 0.) {move(QVector3D(dx, dy, dz)); buildTransform();}
void moveTo(GLfloat dx, GLfloat dy, GLfloat dz = 0.) {moveTo(QVector3D(dx, dy, dz)); buildTransform();}
void moveX(GLfloat o) {trans.setTranslationX(posX() + o); buildTransform();}
void moveY(GLfloat o) {trans.setTranslationY(posY() + o); buildTransform();}
void moveZ(GLfloat o) {trans.setTranslationZ(posZ() + o); buildTransform();}
void setPosX(GLfloat o) {trans.setTranslationX(o); buildTransform();}
void setPosY(GLfloat o) {trans.setTranslationY(o); buildTransform();}
void setPosZ(GLfloat o) {trans.setTranslationZ(o); buildTransform();}
void setPos(GLfloat x, GLfloat y, GLfloat z) {trans.setTranslation(QVector3D(x, y, z)); buildTransform();}
void setPos(const QVector3D & p) {trans.setTranslation(p); buildTransform();}
void resetPos() {trans.setTranslation(QVector3D()); buildTransform();}
QVector3D pos() const {return trans.translation();}
float posX() const {return trans.translation().x();}
float posY() const {return trans.translation().y();}
float posZ() const {return trans.translation().z();}
QVector3D worldPos() const {return (itransform_ * QVector4D(0, 0, 0, 1.)).toVector3D();}
QMatrix4x4 worldTransform() const {return itransform_;}
QVector3D rotation() const {return trans.rotation();}
float rotationX() const {return rotation().x();}
float rotationY() const {return rotation().y();}
float rotationZ() const {return rotation().z();}
void rotateX(GLfloat a) {raw_matrix = false; trans.setRotationX(trans.rotationX() + a); buildTransform();}
void rotateY(GLfloat a) {raw_matrix = false; trans.setRotationY(trans.rotationY() + a); buildTransform();}
void rotateZ(GLfloat a);
void setRotationX(GLfloat a) {raw_matrix = false; trans.setRotationX(a); buildTransform();}
void setRotationY(GLfloat a) {raw_matrix = false; trans.setRotationY(a); buildTransform();}
void setRotationZ(GLfloat a);
void setRotation(const QVector3D & a) {raw_matrix = false; trans.setRotation(a); buildTransform();}
void resetRotation() {raw_matrix = false; trans.setRotation(QVector3D()); buildTransform();}
QVector3D scale() {return trans.scale3D();}
float scaleX() {return trans.scale3D().x();}
float scaleY() {return trans.scale3D().y();}
float scaleZ() {return trans.scale3D().z();}
void scale(const QVector3D & sv) {raw_matrix = false; trans.setScale(trans.scale3D() * sv); buildTransform();}
void scale(GLfloat sx, GLfloat sy, GLfloat sz) {raw_matrix = false; scale(QVector3D(sx, sy, sz)); buildTransform();}
void scale(GLfloat sx, GLfloat sy) {raw_matrix = false; scale(QVector3D(sx, sy, sy)); buildTransform();}
void scale(GLfloat sx) {raw_matrix = false; scale(QVector3D(sx, sx, sx)); buildTransform();}
void scaleX(GLfloat a) {raw_matrix = false; trans.setScaleX(trans.scale3D().x() + a); buildTransform();}
void scaleY(GLfloat a) {raw_matrix = false; trans.setScaleY(trans.scale3D().y() + a); buildTransform();}
void scaleZ(GLfloat a) {raw_matrix = false; trans.setScaleZ(trans.scale3D().z() + a); buildTransform();}
void setScale(const QVector3D & a) {raw_matrix = false; trans.setScale(a); buildTransform();}
void setScale(GLfloat a) {raw_matrix = false; trans.setScale(a); buildTransform();}
void setScaleX(GLfloat a) {raw_matrix = false; trans.setScaleX(a); buildTransform();}
void setScaleY(GLfloat a) {raw_matrix = false; trans.setScaleY(a); buildTransform();}
void setScaleZ(GLfloat a) {raw_matrix = false; trans.setScaleZ(a); buildTransform();}
void resetScale() {raw_matrix = false; trans.setScale(1.f); buildTransform();}
Transform transform() {return trans;}
void setTransform(const Transform & t);
void setMatrix(const QMatrix4x4 & t);
QMatrix4x4 matrix() const;
bool isRawMatrix() {return raw_matrix;}
QVector3D inParentSpace(const QVector3D & v) const;
void transferTransformToChildren(bool only_scale = false);
void cleanTree();
bool isAcceptLight() const {return accept_light;}
void setAcceptLight(bool yes) {accept_light = yes;}
bool isAcceptFog() const {return accept_fog;}
void setAcceptFog(bool yes) {accept_fog = yes;}
bool isSelected(bool check_parents = false) const;
void setSelected(bool yes);
void select() {setSelected(true);}
void deselect() {setSelected(false);}
ObjectBase * selectedParent() const;
void setAimSelected(bool yes) {selected_aim = yes;}
bool isAimSelected() const {return selected_aim;}
bool isSelectable() const {return select_;}
void setSelectable(bool yes) {select_ = yes;}
GLenum srcAlpha() const {return blend_src;}
GLenum destAlpha() const {return blend_dest;}
void setSrcAlpha(GLenum mode) {blend_src = mode;}
void setDestAlpha(GLenum mode) {blend_dest = mode;}
void setMaterial(Material * m, bool with_children = false);
Material * material() {return material_;}
void setColor(QColor c, bool with_children = false);
QColor color() {return color_;}
const Box3D & boundingBox() const {return bound;}
void setMesh(Mesh * v);
Mesh * mesh() {return mesh_;}
void calculateBoundingBox();
void updateTransform();
void setProperty(const QString & pn, const QVariant & v);
QVariant property(const QString & pn, bool * exists = 0) const;
bool hasProperty(const QString & pn) const;
void removeProperty(const QString & pn);
QVector3D pos_h;
protected:
virtual void transformChanged() {}
void addChildren(ObjectBaseList & list, ObjectBase * where);
void buildTransform(bool force = false);
void initInternal();
void setSceneTreeChanged();
void setObjectsChanged();
void localTransform(QMatrix4x4 & m);
QMatrix4x4 worldMatrix(QMatrix4x4 parent) const;
int prev_pass; // Pass
bool is_init, accept_light, accept_fog, visible_, cast_shadow, rec_shadow, select_, selected_, raw_matrix;
bool is_root, selected_aim;
float line_width;
QColor color_;
uint id_;
Type type_;
RenderMode render_mode;
Box3D bound;
Transform trans;
ObjectBaseList children_;
QMatrix4x4 itransform_, mat_;
QString name_;
GLenum blend_src, blend_dest;
ObjectBase * parent_;
Scene * scene_;
Material * material_;
Mesh * mesh_;
QVariantMap meta;
};
inline bool operator <(const ObjectBase & f, const ObjectBase & s) {return f.pos_h.z() < s.pos_h.z();}
class AimedObject: public ObjectBase {
friend class QGLView;
friend class GLRendererBase;
friend class Light;
friend class Camera;
public:
AimedObject();
~AimedObject() {}
QVector3D aim() const {return pos() + (direction() * aim_dist);}
QVector3D worldAim() const;
void setAim(const QVector3D & p);
QVector3D direction() const;
QVector3D worldDirection() const {return (itransform_ * QVector4D(QVector3D(0,0,-1), 0.)).toVector3D().normalized();}
void setDirection(const QVector3D & d);
void setDirection(double x, double y, double z) {setDirection(QVector3D(x, y, z));}
double distance() const {return aim_dist;}
void setDistance(double d) {aim_dist = d;}
void flyCloser(double s);
void flyFarer(double s);
void flyToDistance(double d);
void moveForward(const float & x, bool withZ = true);
void moveBackward(const float & x, bool withZ = true) {moveForward(-x, withZ);}
void moveLeft(const float & x, bool withZ = true);
void moveRight(const float & x, bool withZ = true) {moveLeft(-x, withZ);}
void moveUp(const float & x, bool onlyZ = false);
void moveDown(const float & x, bool onlyZ = false) {moveUp(-x, onlyZ);}
void rotateRoll(const float & a) {rotateY(a);}
void orbitZ(const float & a);
void orbitXY(const float & a);
protected:
void transformChanged() override;
double aim_dist;
};
class Light: public AimedObject {
friend class QGLView;
friend class RendererBase;
public:
enum Type {Omni, Cone, Directional};
Light();
Light(const QVector3D & p, const QColor & c = Qt::white, float i = 1.);
virtual ObjectBase * clone(bool withChildren = true);
virtual void init() {shadow_map.resize(512, 512); is_init = true;}
void apply();
float angle_start;
float angle_end;
float intensity;
float decay_const;
float decay_linear;
float decay_quadratic;
float decay_start;
float decay_end;
Type light_type;
Framebuffer shadow_map;
QMatrix4x4 shadow_matrix;
};
template <class T>
inline T globject_cast(ObjectBase * object) {return reinterpret_cast<T>(object);}
template <class T>
inline T globject_cast(const ObjectBase * object) {return reinterpret_cast<T>(object);}
QDataStream & operator <<(QDataStream & s, const ObjectBase * p);
QDataStream & operator >>(QDataStream & s, ObjectBase *& p);
inline ObjectBaseList lights2objectList(const QList<Light*> & v) {ObjectBaseList ret; foreach (Light*i, v) ret << (ObjectBase*)i; return ret;}
inline ObjectBaseList cameras2objectList(const QList<Camera*> & v) {ObjectBaseList ret; foreach (Camera*i, v) ret << (ObjectBase*)i; return ret;}
#endif // GLOBJECT_H

View File

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

View File

@@ -1,63 +0,0 @@
/*
QGL TextureManager
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLTEXTUREMANAGER_H
#define GLTEXTUREMANAGER_H
#include <QOpenGLExtraFunctions>
#include <QDir>
#include <QMap>
#include <QFileInfo>
#include <QImage>
class TextureManager {
public:
TextureManager(QOpenGLExtraFunctions * f_): f(f_) {}
virtual ~TextureManager() {}
static void addSearchPath(const QString & path) {if (!search_pathes.contains(path)) search_pathes << path;}
static void clearSearchPathes() {search_pathes.clear();}
static QStringList searchPathes() {return search_pathes;}
static QString findFile(const QString & path);
GLuint loadTexture(const QString & path, bool ownership = true, bool bump = false);
GLuint loadTexture(const QImage & image, bool ownership = true, bool bump = false);
QImage loadTextureImage(const QString & path, bool bump = false);
void reloadTexture(GLuint tid, const QString & path);
void reloadTexture(GLuint tid, const QImage & image);
int textureID (const QString & path, bool bump = false) {return tex_ids[bump ? 1 : 0][path];}
QImage textureImage(const QString & path, bool bump = false) {return tex_im [bump ? 1 : 0][path];}
void addTexture(const QString & path) {tex_pathes << path;}
bool loadTextures();
void deleteTextures();
void deleteTexture(const QString & name);
void clearImageCache();
protected:
static void convertToNormal(QImage & im);
static QStringList search_pathes;
QMap<QString, GLuint> tex_ids[2];
QMap<QString, QImage> tex_im [2];
QStringList tex_pathes;
QOpenGLExtraFunctions * f;
};
#endif // GLTEXTUREMANAGER_H

View File

@@ -1,102 +0,0 @@
/*
QGL GLWidget
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QWidget>
class QGLView;
class ObjectBase;
class Scene;
class GLWidget : public QWidget
{
Q_OBJECT
Q_PROPERTY (QColor backColor READ backColor WRITE setBackColor)
Q_PROPERTY (qreal lineWidth READ lineWidth WRITE setLineWidth)
Q_PROPERTY (qreal FOV READ FOV WRITE setFOV)
Q_PROPERTY (qreal depthStart READ depthStart WRITE setDepthStart)
Q_PROPERTY (QColor ambientColor READ ambientColor WRITE setAmbientColor)
Q_PROPERTY (bool grabMouse READ isGrabMouseEnabled WRITE setGrabMouseEnabled)
Q_PROPERTY (bool mouseRotate READ isMouseRotateEnabled WRITE setMouseRotateEnabled)
Q_PROPERTY (bool mouseSelection READ isMouseSelectionEnabled WRITE setMouseSelectionEnabled)
Q_PROPERTY (bool cameraOrbit READ isCameraOrbit WRITE setCameraOrbit)
Q_PROPERTY (bool hoverHalo READ isHoverHaloEnabled WRITE setHoverHaloEnabled)
Q_PROPERTY (QColor hoverHaloColor READ hoverHaloColor WRITE setHoverHaloColor)
Q_PROPERTY (qreal hoverHaloFillAlpha READ hoverHaloFillAlpha WRITE setHoverHaloFillAlpha)
Q_PROPERTY (bool selectionHalo READ isSelectionHaloEnabled WRITE setSelectionHaloEnabled)
Q_PROPERTY (QColor selectionHaloColor READ selectionHaloColor WRITE setSelectionHaloColor)
Q_PROPERTY (qreal selectionHaloFillAlpha READ selectionHaloFillAlpha WRITE setSelectionHaloFillAlpha)
public:
explicit GLWidget(QWidget *parent = nullptr);
QGLView * view() {return view_;}
QColor backColor() const;
qreal lineWidth() const;
qreal FOV() const;
qreal depthStart() const;
QColor ambientColor() const;
bool isLightEnabled() const;
bool isGrabMouseEnabled() const;
bool isMouseRotateEnabled() const;
bool isMouseSelectionEnabled() const;
bool isCameraOrbit() const;
bool isHoverHaloEnabled() const;
QColor hoverHaloColor() const;
qreal hoverHaloFillAlpha() const;
bool isSelectionHaloEnabled() const;
QColor selectionHaloColor() const;
qreal selectionHaloFillAlpha() const;
Scene * scene();
void addObject(ObjectBase * o);
QByteArray saveCamera();
void restoreCamera(const QByteArray & ba);
public slots:
void stop();
void start(float freq = 60.0);
void setBackColor(const QColor & c);
void setLineWidth(const qreal & arg);
void setFOV(const qreal & arg);
void setDepthStart(const qreal & arg);
void setAmbientColor(const QColor & arg);
void setLightEnabled(const bool & arg);
void setGrabMouseEnabled(const bool & arg);
void setMouseRotateEnabled(const bool & arg);
void setMouseSelectionEnabled(const bool & arg);
void setCameraOrbit(const bool & arg);
void setHoverHaloEnabled(const bool & arg);
void setHoverHaloColor(const QColor & arg);
void setHoverHaloFillAlpha(const qreal & arg);
void setSelectionHaloEnabled(const bool & arg);
void setSelectionHaloColor(const QColor & arg);
void setSelectionHaloFillAlpha(const qreal & arg);
private slots:
void viewDoubleClicked();
private:
QWidget * container;
QGLView * view_;
QLayout * lay;
};
#endif // GLWIDGET_H

View File

@@ -1,84 +0,0 @@
/*
QGL MouseController
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOUSE_CONTROLLER_H
#define MOUSE_CONTROLLER_H
#include "glprimitives.h"
#include "glcamera.h"
#include "renderer_service.h"
#include <QMouseEvent>
#include <QTime>
class MouseController: public QObject
{
friend class QGLView;
friend class RendererSelection;
Q_OBJECT
public:
MouseController(QGLView * view_);
virtual ~MouseController();
bool isGrabMouseEnabled() const {return grabMouse_;}
bool isMouseRotateEnabled() const {return mouseRotate_;}
bool isMouseSelectionEnabled() const {return mouseSelect_;}
bool isCameraOrbit() const {return cameraOrbit_;}
Qt::MouseButton selectionButton() const {return sel_button;}
Qt::KeyboardModifier selectionModifier() const {return sel_mod;}
void setSelectionButton(Qt::MouseButton v) {sel_button = v;}
void setSelectionModifier(Qt::KeyboardModifier v) {sel_mod = v;}
protected:
void resize();
void mousePressEvent(QMouseEvent * e);
void mouseMoveEvent(QMouseEvent * e);
void mouseReleaseEvent(QMouseEvent * e);
void wheelEvent(QWheelEvent * e);
void leaveEvent(QEvent * );
void mouseDoubleClickEvent(QMouseEvent * e);
private:
QGLView * view;
QPoint lastPos, downPos;
QSet<int> keys_;
QVector<ObjectBase * > hov_objects, hov_aims;
Qt::MouseButton sel_button;
Qt::KeyboardModifier sel_mod;
RendererService::HandleAction cur_action;
QFlags<RendererService::HandleMesh> cur_handle;
float app_scale;
bool grabMouse_, mouse_first, mouseRotate_, mouseSelect_, customMouseMove_, canSelect_;
bool cameraOrbit_, selecting_, mouse_sec;
private slots:
public slots:
void setGrabMouseEnabled(const bool & arg) {grabMouse_ = arg; mouse_first = true;}
void setMouseRotateEnabled(const bool & arg) {mouseRotate_ = arg;}
void setMouseSelectionEnabled(const bool & arg) {mouseSelect_ = arg;}
void setCustomMouseMove(const bool & arg) {customMouseMove_ = arg;}
void setCameraOrbit(const bool & arg) {cameraOrbit_ = arg;}
signals:
};
#endif // QGLVIEW_H

View File

@@ -1,112 +0,0 @@
/*
QGL OpenGLWindow
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "openglwindow.h"
#include <QCoreApplication>
#include <QOpenGLContext>
#include <QOpenGLPaintDevice>
#include <QPainter>
OpenGLWindow::OpenGLWindow(QWindow *parent)
: QWindow(parent)
, m_context(nullptr)
, m_device(nullptr)
{
setFlags(flags() | Qt::FramelessWindowHint);
setSurfaceType(QWindow::OpenGLSurface);
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
// qDebug() << format;
#ifdef QT_OPENGL_ES_2
format.setRenderableType(QSurfaceFormat::OpenGLES);
#else
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
format.setVersion(4, 0);
format.setProfile(QSurfaceFormat::CoreProfile);
}
#endif
format.setDepthBufferSize(24);
format.setSamples(8);
setFormat(format);
QSurfaceFormat::setDefaultFormat(format);
}
OpenGLWindow::~OpenGLWindow() {
delete m_device;
}
void OpenGLWindow::render(QPainter *painter) {
}
void OpenGLWindow::initialize() {
}
void OpenGLWindow::render() {
// if (!m_device) m_device = new QOpenGLPaintDevice;
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// m_device->setSize(size() * devicePixelRatio());
// m_device->setDevicePixelRatio(devicePixelRatio());
// QPainter painter(m_device);
// render(&painter);
}
void OpenGLWindow::renderLater() {
requestUpdate();
}
bool OpenGLWindow::event(QEvent *event) {
switch (event->type()) {
case QEvent::UpdateRequest:
renderNow();
return true;
default:
return QWindow::event(event);
}
}
void OpenGLWindow::exposeEvent(QExposeEvent *event) {
if (isExposed()) renderNow();
}
void OpenGLWindow::renderNow() {
if (!isExposed())
return;
bool needsInitialize = false;
if (!m_context) {
m_context = new QOpenGLContext(this);
m_context->setFormat(requestedFormat());
m_context->create();
needsInitialize = true;
}
m_context->makeCurrent(this);
if (needsInitialize) {
initializeOpenGLFunctions();
initialize();
}
render();
m_context->swapBuffers(this);
}

View File

@@ -1,51 +0,0 @@
/*
QGL OpenGLWindow
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QWindow>
#include <QOpenGLExtraFunctions>
class QPainter;
class QOpenGLContext;
class QOpenGLPaintDevice;
class OpenGLWindow: public QWindow, public QOpenGLExtraFunctions
{
Q_OBJECT
public:
explicit OpenGLWindow(QWindow *parent = nullptr);
~OpenGLWindow();
virtual void render(QPainter *painter);
virtual void render();
virtual void initialize();
QOpenGLContext * context() {return m_context;}
public slots:
void renderLater();
void renderNow();
protected:
bool event(QEvent *event) override;
void exposeEvent(QExposeEvent *event) override;
private:
QOpenGLContext *m_context;
QOpenGLPaintDevice *m_device;
};

View File

@@ -1,288 +0,0 @@
/*
QGLView
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qglview.h"
#include "glmesh.h"
#include "gltexture_manager.h"
#include <chunkstream.h>
#include <qad_types.h>
#include <QApplication>
#include <QOpenGLTexture>
#include <QKeyEvent>
using namespace QGLEngineShaders;
QGLView::QGLView(): OpenGLWindow(), renderer_(this), mouse(this) {
setIcon(QIcon(":/icons/qglview.png"));
deleting_ = false;
timer = 0;
need_init_ = is_first_draw = true;
backColor_ = Qt::darkGray;
hoverHaloColor_ = QColor(195, 140, 255);
selectionHaloColor_ = QColor(175, 255, 140);
ambientColor_ = QColor(10, 10, 10);
lineWidth_ = 1.;
max_anisotropic = 1;
max_texture_chanels = 8;
lightEnabled_ = true;
shaders_supported = false;
fps_cnt = 0;
fps_tm = fps_ = 0.;
fogColor_ = Qt::darkGray;
fogDensity_ = 0.;
fogDecay_ = 10.;
hoverHaloFill_ = selectionHaloFill_ = 0.15f;
//lmode = Simple;
setFeature(qglFXAA, false);
setFeature(qglAnisotropicLevel, 8);
setFeature(qglEyeAccomodationEnabled, false);
setFeature(qglEyeAccomodationTime, 16.);
setFeature(qglEyeAccomodationMaxSpeed, 0.2);
setFeature(qglBloomEnabled, false);
setFeature(qglBloomThreshold, 0.9);
setFeature(qglBloomFactor, 1.);
setFeature(qglBloomRadius, 8);
setFeature(qglMotionBlurEnabled, false);
setFeature(qglMotionBlurFactor, 1.);
setFeature(qglMotionBlurSteps, 8);
setFeature(qglShadowsEnabled, false);
setFeature(qglShadowsMapSize, 512);
setFeature(qglShadowsSoftEnabled, true);
setFeature(qglReflectionsEnabled, false);
setFeature(qglReflectionsBlur, true);
setFeature(qglSSAOEnabled, false);
setFeature(qglSSAORadius, 5);
setFeature(qglDepthOfFieldEnabled, false);
setFeature(qglDepthOfFieldAutoFocusEnabled, true);
setFeature(qglDepthOfFieldAutoFocusSpeed, 0.1);
setFeature(qglDepthOfFieldFocus, 1.);
setFeature(qglDepthOfFieldDiaphragm, 8.);
hoverHalo_ = selectionHalo_ = true;
fogEnabled_ = is_init = shaders_bind = changed_ = false;
rmode = ObjectBase::Fill;
scene_ = new Scene();
connect(scene_, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
connect(scene_, SIGNAL(__destroyed()), this, SLOT(__destroyed()));
connect(scene_, SIGNAL(__objectDeleted(ObjectBase*)), this, SLOT(__objectDeleted(ObjectBase*)));
default_camera = new Camera();
default_camera->setPos(QVector3D(2, 2, 2));
default_camera->setAim(QVector3D());
camera_ = default_camera;
// qDebug() << camera_->aim();
default_camera->setName("Camera");
emit cameraPosChanged(default_camera->pos());
ktm_.restart();
Mesh * m = Primitive::cube(10, 10, 10);
m->flipNormals();
ObjectBase * o = new ObjectBase(m);
o->setColor(Qt::cyan);
scene()->addObject(o);
delete m;
}
QGLView::~QGLView() {
deleting_ = true;
stop();
scene_->clear();
delete scene_;
delete default_camera;
}
void QGLView::stop() {
if (timer) killTimer(timer);
}
void QGLView::start(float freq) {
timer = startTimer(freq <= 0.f ? 0 : int(1000.f / freq));
}
QList<Light * > QGLView::selectedLights() const {
QList<Light * > ret;
ObjectBaseList sol = scene_->selectedObjects();
foreach (ObjectBase * o, sol)
if (o->type() == ObjectBase::glLight)
ret << (Light*)o;
return ret;
}
QList<Camera * > QGLView::selectedCameras() const {
QList<Camera * > ret;
ObjectBaseList sol = scene_->selectedObjects();
foreach (ObjectBase * o, sol)
if (o->type() == ObjectBase::glCamera)
ret << (Camera*)o;
return ret;
}
void QGLView::resizeEvent(QResizeEvent * e) {
renderLater();
mouse.resize();
}
void QGLView::timerEvent(QTimerEvent *) {
renderNow();
Qt::KeyboardModifiers km = QApplication::keyboardModifiers();
foreach (int i, keys_)
emit keyEvent((Qt::Key)i, km);
}
void QGLView::render() {
resizeGL(width(), height());
emit glBeginPaint();
renderer_.mouse_pos = mapFromGlobal(QCursor::pos());
renderer_.renderScene();
emit glEndPaint();
fps_tm += time.elapsed();
time.restart();
fps_cnt++;
if (fps_tm < 1000.) return;
fps_ = fps_cnt / fps_tm * 1000.;
fps_tm = 0.;
fps_cnt = 0;
}
void QGLView::initialize() {
checkCaps();
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_MULTISAMPLE);
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_CUBE_MAP);
glEnable(GL_TEXTURE_MAX_ANISOTROPY_EXT);
glEnable(GL_CULL_FACE);
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
glCullFace(GL_BACK);
renderer_.reloadShaders();
renderer_.init(width(), height());
is_init = true;
need_init_ = false;
emit glInitializeDone();
}
void QGLView::checkCaps() {
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropic);
shaders_supported = QOpenGLShaderProgram::hasOpenGLShaderPrograms();
}
void QGLView::__destroyed() {
renderer_.rend_mat.mat_thumbnails.clear();
mouse.hov_objects.clear();
}
void QGLView::__objectDeleted(ObjectBase * o) {
if (o == camera_)
setDefaultCamera();
}
void QGLView::resizeGL(int width, int height) {
if (!is_init) return;
if (width <= 0 || height <= 0) return;
if (prev_size == QSize(width, height)) return;
prev_size = QSize(width, height);
aspect = float(width) / float(height);
renderer_.resize(width, height);
//qDebug() << "resize" << width << height;
iaspect = (aspect == 0.f) ? 0. : 1 / aspect;
glViewport(0, 0, width, height);
emit glResize(width, height);
}
void QGLView::keyPressEvent(QKeyEvent * e) {
emit glKeyPressEvent(e);
if (e->key() > 0) keys_.insert(e->key());
if (e->key() == Qt::Key_F11) {
emit doubleClick();
}
}
void QGLView::keyReleaseEvent(QKeyEvent * e) {
emit glKeyReleaseEvent(e);
keys_.remove(e->key());
}
void QGLView::focusOutEvent(QFocusEvent *) {
keys_.clear();
}
void QGLView::focusOn(const Box3D & bb) {
if (bb.isEmpty() || !camera()) return;
double size = qMax(qMax(bb.width, bb.length), bb.height);
camera()->setAim(bb.center());
camera()->flyToDistance(size * 1.25);
}
QByteArray QGLView::saveCamera() {
ChunkStream cs;
const Camera * c = camera();
cs.add(1, c->pos()).add(2, c->aim()).add(3, c->rotation()).add(4, c->FOV());
return cs.data();
}
void QGLView::restoreCamera(const QByteArray & ba) {
if (ba.isEmpty()) return;
Camera * c = camera();
QVector3D pos(c->pos()), aim(c->aim()), ang(c->rotation());
float fov(c->FOV());
ChunkStream cs(ba);
cs.readAll();
cs.get(1, pos).get(2, aim).get(3, ang).get(4, fov);
camera()->setPos(pos);
camera()->setAim(aim);
camera()->setAngles(ang);
camera()->setFOV(fov);
}
QByteArray QGLView::saveFeatures() {
QByteArray ba;
QDataStream ds(&ba, QIODevice::WriteOnly);
ds << features_;
return ba;
}
void QGLView::restoreFeatures(const QByteArray & ba) {
QHash<int, QVariant> f;
QDataStream ds(ba);
ds >> f;
features_ = f;
}

281
qglview.h
View File

@@ -1,281 +0,0 @@
/*
QGLView
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QGLVIEW_H
#define QGLVIEW_H
#include "openglwindow.h"
#include "glframebuffer.h"
#include "glprimitives.h"
#include "glcamera.h"
#include "glscene.h"
#include "renderer.h"
#include "mouse_controller.h"
#include <QElapsedTimer>
#include <QMenu>
class QGLView: public OpenGLWindow
{
friend class RendererSelection;
Q_OBJECT
Q_PROPERTY (QColor backColor READ backColor WRITE setBackColor)
Q_PROPERTY (float lineWidth READ lineWidth WRITE setLineWidth)
Q_PROPERTY (float FOV READ FOV WRITE setFOV)
Q_PROPERTY (float depthStart READ depthStart WRITE setDepthStart)
Q_PROPERTY (float gamma READ gamma WRITE setGamma)
Q_PROPERTY (bool autoExposure READ autoExposure WRITE setAutoExposure)
Q_PROPERTY (QColor ambientColor READ ambientColor WRITE setAmbientColor)
Q_PROPERTY (QColor fogColor READ fogColor WRITE setFogColor)
Q_PROPERTY (bool fogEnabled READ isFogEnabled WRITE setFogEnabled)
Q_PROPERTY (float fogDensity READ fogDensity WRITE setFogDensity)
Q_PROPERTY (float fogDecay READ fogDecay WRITE setFogDecay)
Q_PROPERTY (int renderMode READ renderMode WRITE setRenderMode)
Q_PROPERTY (bool grabMouse READ isGrabMouseEnabled WRITE setGrabMouseEnabled)
Q_PROPERTY (bool mouseRotate READ isMouseRotateEnabled WRITE setMouseRotateEnabled)
Q_PROPERTY (bool mouseSelection READ isMouseSelectionEnabled WRITE setMouseSelectionEnabled)
Q_PROPERTY (bool cameraOrbit READ isCameraOrbit WRITE setCameraOrbit)
Q_PROPERTY (bool hoverHalo READ isHoverHaloEnabled WRITE setHoverHaloEnabled)
Q_PROPERTY (QColor hoverHaloColor READ hoverHaloColor WRITE setHoverHaloColor)
Q_PROPERTY (float hoverHaloFillAlpha READ hoverHaloFillAlpha WRITE setHoverHaloFillAlpha)
Q_PROPERTY (bool selectionHalo READ isSelectionHaloEnabled WRITE setSelectionHaloEnabled)
Q_PROPERTY (QColor selectionHaloColor READ selectionHaloColor WRITE setSelectionHaloColor)
Q_PROPERTY (float selectionHaloFillAlpha READ selectionHaloFillAlpha WRITE setSelectionHaloFillAlpha)
Q_PROPERTY (Qt::MouseButton selectionButton READ selectionButton WRITE setSelectionButton)
Q_PROPERTY (Qt::KeyboardModifier selectionModifier READ selectionModifier WRITE setSelectionModifier)
Q_PROPERTY (Scene::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
public:
QGLView();
virtual ~QGLView();
enum CameraLightMode {
clmOff,
clmAuto,
clmOn,
};
enum Feature {
qglFXAA,
qglAnisotropicLevel,
qglEyeAccomodationEnabled,
qglEyeAccomodationTime,
qglEyeAccomodationMaxSpeed,
qglBloomEnabled,
qglBloomThreshold,
qglBloomFactor,
qglBloomRadius,
qglMotionBlurEnabled,
qglMotionBlurFactor,
qglMotionBlurSteps,
qglShadowsEnabled,
qglShadowsMapSize,
qglShadowsSoftEnabled,
qglReflectionsEnabled,
qglReflectionsBlur,
qglSSAOEnabled,
qglSSAORadius,
qglDepthOfFieldEnabled,
qglDepthOfFieldAutoFocusEnabled,
qglDepthOfFieldAutoFocusSpeed,
qglDepthOfFieldFocus,
qglDepthOfFieldDiaphragm
};
Q_ENUM(CameraLightMode)
void stop();
void start(float freq = 60.);
QColor backColor() const {return backColor_;}
float lineWidth() const {return lineWidth_;}
float FOV() const {return camera()->FOV();}
float depthStart() const {return camera()->depthStart();}
float currentFPS() const {return fps_;}
float gamma() const {return renderer_.gamma_;}
bool autoExposure() const {return renderer_.tone_proc.enabled;}
int maxAnisotropicLevel() const {return max_anisotropic;}
QString environmentMapFile() const {return renderer_.tex_env.fileHDR();}
QColor ambientColor() const {return ambientColor_;}
QColor fogColor() const {return fogColor_;}
float fogDensity() const {return fogDensity_;}
float fogDecay() const {return fogDecay_;}
bool isFogEnabled() const {return fogEnabled_;}
bool isLightEnabled() const {return lightEnabled_;}
bool isGrabMouseEnabled() const {return mouse.isGrabMouseEnabled();}
bool isMouseRotateEnabled() const {return mouse.isMouseRotateEnabled();}
bool isMouseSelectionEnabled() const {return mouse.isMouseSelectionEnabled();}
bool isCameraOrbit() const {return mouse.isCameraOrbit();}
bool isHoverHaloEnabled() const {return hoverHalo_;}
QColor hoverHaloColor() const {return hoverHaloColor_;}
float hoverHaloFillAlpha() const {return hoverHaloFill_;}
bool isSelectionHaloEnabled() const {return selectionHalo_;}
QColor selectionHaloColor() const {return selectionHaloColor_;}
float selectionHaloFillAlpha() const {return selectionHaloFill_;}
QVariant feature(Feature f) const {return features_.value(int(f));}
QVariant setFeature(Feature f, const QVariant & value) {QVariant ret = features_.value(int(f)); features_[int(f)] = value; return ret;}
bool isFeatureEnabled(Feature f) const {return features_[int(f)].toBool();}
int renderMode() const {return (int)rmode;}
void setRenderMode(int mode) {rmode = (ObjectBase::RenderMode)mode;}
bool isServiceMode() const {return renderer_.edit_mode;}
void setServiceMode(bool yes) {renderer_.edit_mode = yes;}
Scene::SelectionMode selectionMode() const {return scene_->selectionMode();}
Qt::MouseButton selectionButton() const {return mouse.selectionButton();}
Qt::KeyboardModifier selectionModifier() const {return mouse.selectionModifier();}
void setSelectionMode(Scene::SelectionMode m) {scene_->setSelectionMode(m);}
void setSelectionButton(Qt::MouseButton v) {mouse.setSelectionButton(v);}
void setSelectionModifier(Qt::KeyboardModifier v) {mouse.setSelectionModifier(v);}
void selectObject(ObjectBase * o, bool add_to_selection = false) {scene_->selectObject(o, add_to_selection);}
void clearSelection() {scene_->clearSelection();}
ObjectBaseList selectedObjects(bool top_only = false) const {return scene_->selectedObjects(top_only);}
QList<Light * > selectedLights() const;
QList<Camera * > selectedCameras() const;
ObjectBase * selectedObject() const {return scene_->selectedObject();}
TextureManager * textureManager() {return renderer_.textures_manager;}
void reloadTextures() {renderer_.markReloadTextures();}
Scene * scene() {return scene_;}
void focusOn(const Box3D & bb);
void setCameraLightMode(CameraLightMode m) {renderer_.setCameraLightMode(m);}
CameraLightMode cameraLightMode() const {return (CameraLightMode)renderer_.cameraLightMode();}
Camera * camera() {return camera_;}
const Camera * camera() const {return camera_;}
void setCamera(Camera * camera) {camera_ = camera;}
void setDefaultCamera() {camera_ = default_camera;}
QByteArray saveCamera();
void restoreCamera(const QByteArray & ba);
QByteArray saveFeatures();
void restoreFeatures(const QByteArray & ba);
QImage materialThumbnail(Material * m) {return renderer_.materialThumbnail(m);}
void setCurrentAction(RendererService::HandleAction ha) {renderer_.rend_service.setCurrentAction(ha);}
void setContextActions(QList<QAction*> al) {context_menu.clear(); context_menu.addActions(al);}
void popupMenu(const QPoint &pos, QAction *at = nullptr) {context_menu.popup(pos, at);}
GLfloat aspect, iaspect;
Renderer renderer_;
protected:
void render();
void resizeEvent(QResizeEvent * e);
void timerEvent(QTimerEvent * );
void initialize();
void resizeGL(int width, int height);
void mousePressEvent(QMouseEvent * e) {mouse.mousePressEvent(e);}
void mouseMoveEvent(QMouseEvent * e) {mouse.mouseMoveEvent(e);}
void mouseReleaseEvent(QMouseEvent * e) {mouse.mouseReleaseEvent(e);}
void wheelEvent(QWheelEvent * e) {mouse.wheelEvent(e);}
void mouseDoubleClickEvent(QMouseEvent * e) {mouse.mouseDoubleClickEvent(e);}
void leaveEvent(QEvent * );
void keyPressEvent(QKeyEvent * e);
void keyReleaseEvent(QKeyEvent * e);
void focusOutEvent(QFocusEvent *);
void checkCaps();
private:
void processKeys();
bool setupViewport();
Scene * scene_;
Camera * camera_, * default_camera;
MouseController mouse;
QMenu context_menu;
QSet<int> keys_;
QColor backColor_, fogColor_, ambientColor_, hoverHaloColor_, selectionHaloColor_;
QElapsedTimer time, ktm_;
GLint max_anisotropic, max_texture_chanels;
ObjectBase::RenderMode rmode;
QHash<int, QVariant> features_;
QSize prev_size;
float lineWidth_;
float fps_, fps_tm, fogDensity_, fogDecay_;
float hoverHaloFill_, selectionHaloFill_, m_motionBlurFactor;
int timer, fps_cnt, sh_id_loc, deleting_;
bool is_first_draw, is_init, fogEnabled_, lightEnabled_;
bool shaders_supported, changed_, need_init_;
bool hoverHalo_, selectionHalo_, shaders_bind;
private slots:
void __destroyed();
void __objectDeleted(ObjectBase * o);
public slots:
void setBackColor(const QColor & arg) {backColor_ = arg;}
void setLineWidth(const float & arg) {lineWidth_ = arg;}
void setFOV(const float & arg) {camera()->setFOV(arg);}
void setDepthStart(const float & arg) {camera()->setDepthStart(arg);}
void setGamma(const float & arg) {renderer_.gamma_ = arg;}
void setAutoExposure(bool arg) {renderer_.tone_proc.enabled = arg;}
void setAmbientColor(const QColor & arg) {ambientColor_ = arg;}
void setEnvironmentMapFile(QString file) {renderer_.tex_env.setFileHDR(file); renderer_.recreateMaterialThumbnails(true);}
void setFogColor(const QColor & arg) {fogColor_ = arg;}
void setFogDensity(const float & arg) {fogDensity_ = arg;}
void setFogDecay(const float & arg) {fogDecay_ = arg;}
void setFogEnabled(const bool & arg) {fogEnabled_ = arg;}
void setLightEnabled(const bool & arg) {lightEnabled_ = arg;}
void setGrabMouseEnabled(const bool & arg) {mouse.setGrabMouseEnabled(arg);}
void setMouseRotateEnabled(const bool & arg) {mouse.setMouseRotateEnabled(arg);}
void setMouseSelectionEnabled(const bool & arg) {mouse.setMouseSelectionEnabled(arg);}
void setCustomMouseMove(const bool & arg) {mouse.setCustomMouseMove(arg);}
void setCameraOrbit(const bool & arg) {mouse.setCameraOrbit(arg);}
void setHoverHaloEnabled(const bool & arg) {hoverHalo_ = arg;}
void setHoverHaloColor(const QColor & arg) {hoverHaloColor_ = arg;}
void setHoverHaloFillAlpha(const float & arg) {hoverHaloFill_ = arg;}
void setSelectionHaloEnabled(const bool & arg) {selectionHalo_ = arg;}
void setSelectionHaloColor(const QColor & arg) {selectionHaloColor_ = arg;}
void setSelectionHaloFillAlpha(const float & arg) {selectionHaloFill_ = arg;}
void reloadShaders() {renderer_.reloadShaders();}
signals:
void glBeginPaint();
void glEndPaint();
void glKeyPressEvent(QKeyEvent * e);
void glKeyReleaseEvent(QKeyEvent * e);
void glMousePressEvent(QMouseEvent * e);
void glMouseMoveEvent(QMouseEvent * e);
void glMouseReleaseEvent(QMouseEvent * e);
void glWheelEvent(QWheelEvent * e);
void glResize(int, int);
void glInitializeDone();
void cameraPosChanged(QVector3D pos);
void keyEvent(Qt::Key key, Qt::KeyboardModifiers mod);
void customMouseMoveEvent(QPoint curpos, QPoint lastpos, Qt::MouseButtons buttons);
void hoverChanged(ObjectBase * cur, ObjectBase * prev);
void selectionChanged();
void objectsPositionChanged();
void materialsChanged();
void materialThumbnailCreated(Material*);
void doubleClick();
};
#endif // QGLVIEW_H

View File

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

View File

@@ -1,34 +0,0 @@
/*
QGLViewWindow
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QApplication>
#include <QDebug>
#include <QDir>
#include "qglview_window.h"
int main(int argc, char ** argv) {
QApplication a(argc, argv);
a.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
QGLViewWindow w;
w.show();
QStringList al(a.arguments());
al.pop_front();
foreach (QString s, al)
w.loadFile(s);
return a.exec();
}

View File

@@ -1,251 +0,0 @@
/*
QGLViewWindow
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qglview_window.h"
#include "renderer.h"
#include "glwidget.h"
#include "gltexture_manager.h"
#include <QGraphicsRectItem>
#include <QImageReader>
#include <QMessageBox>
#include "qad_types.h"
QGLViewWindow::QGLViewWindow(QWidget * parent): QMainWindow(parent), Ui::QGLViewWindow() {
setupUi(this);
session.setFile("session_qglview_test.conf");
session.addEntry(this);
extensions = "All(" + supportedFormats().join(" ") + " *.qgl)";
extensions += ";;QGLEngine(*.qgl)";
//view->view()->camera()->setPos(QVector3D(2, 2, 2));
//view->view()->camera()->setAim(QVector3D());
//view->view()->camera()->flyToDistance(2.);
// view->setFrameShape(QFrame::NoFrame);
view->view()->setMouseRotateEnabled(true);
view->view()->setMouseSelectionEnabled(true);
view->view()->setSelectionHaloEnabled(true);
view->view()->setHoverHaloEnabled(true);
view->view()->setBackColor(Qt::lightGray);
view->view()->setDepthStart(0.1);
view->view()->setSelectionMode(Scene::smMultiSelection);
groupShadows->setChecked(view->view()->isFeatureEnabled(QGLView::qglShadowsEnabled));
groupEyeAccomodation->setChecked(view->view()->isFeatureEnabled(QGLView::qglEyeAccomodationEnabled));
groupBloom->setChecked(view->view()->isFeatureEnabled(QGLView::qglBloomEnabled));
groupMotionBlur->setChecked(view->view()->isFeatureEnabled(QGLView::qglMotionBlurEnabled));
groupReflections->setChecked(view->view()->isFeatureEnabled(QGLView::qglReflectionsEnabled));
checkSoftShadows->setChecked(view->view()->isFeatureEnabled(QGLView::qglShadowsSoftEnabled));
groupSSAO->setChecked(view->view()->isFeatureEnabled(QGLView::qglSSAOEnabled));
spinAccom->setValue(view->view()->feature(QGLView::qglEyeAccomodationTime).toDouble());
spinAccomMS->setValue(view->view()->feature(QGLView::qglEyeAccomodationMaxSpeed).toDouble());
checkReflectionsBlur->setChecked(view->view()->isFeatureEnabled(QGLView::qglReflectionsBlur));
spinShadowmapSize->setValue(view->view()->feature(QGLView::qglShadowsMapSize).toInt());
spinMotionBlurFactor->setValue(view->view()->feature(QGLView::qglMotionBlurFactor).toDouble());
spinMotionBlurSteps->setValue(view->view()->feature(QGLView::qglMotionBlurSteps).toInt());
spinBloomFactor->setValue(view->view()->feature(QGLView::qglBloomFactor).toDouble());
spinBloomRadius->setValue(view->view()->feature(QGLView::qglBloomRadius).toInt());
spinBloomThreshold->setValue(view->view()->feature(QGLView::qglBloomThreshold).toDouble());
spinSSAORadius->setValue(view->view()->feature(QGLView::qglSSAORadius).toInt());
groupDOF->setChecked(view->view()->isFeatureEnabled(QGLView::qglDepthOfFieldEnabled));
checkDOFAutoFocus->setChecked(view->view()->isFeatureEnabled(QGLView::qglDepthOfFieldAutoFocusEnabled));
spinDOFFocus->setValue(view->view()->feature(QGLView::qglDepthOfFieldFocus).toDouble());
spinDOFDiaphragm->setValue(view->view()->feature(QGLView::qglDepthOfFieldDiaphragm).toDouble());
spinDOFSpeed->setValue(view->view()->feature(QGLView::qglDepthOfFieldAutoFocusSpeed).toDouble());
view->view()->start(-1);
startTimer(1000/60);
connect(view->view(), SIGNAL(keyEvent(Qt::Key, Qt::KeyboardModifiers)), this, SLOT(view_keyEvent(Qt::Key, Qt::KeyboardModifiers)));
//connect(matEditor, SIGNAL(changed()), this, SLOT(materialChanged()));
sceneTree->assignQGLView(view->view());
matEditor->assignQGLView(view->view());
objectEditor->assignQGLView(view->view());
primitiveEditor->assignQGLView(view->view());
viewEditor->assignQGLView(view->view());
session.load();
//loadFile("axis.DAE.qgl");
//matEditor->setMaterial(const_cast<ObjectBase*>(view->view()->scene()->rootObject()->child(0))->material());
/*Scene * sc = loadScene("truck.obj");
//view->view()->scene()->addScene(sc);
sc->rootObject()->moveY(-8);
for (int i = 0; i < 7; ++i) {
sc->rootObject()->moveY(2);
view->view()->scene()->addScene(sc);
}
//view->view()->scene()->dump();
delete sc;*/
}
QGLViewWindow::~QGLViewWindow() {
session.save();
//delete ps;
}
void QGLViewWindow::changeEvent(QEvent * e) {
QMainWindow::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
retranslateUi(this);
return;
}
}
void QGLViewWindow::timerEvent(QTimerEvent * ) {
//static double t = 0.;
//((RendererSimple*)(view->view()->renderer()))->mpos = view->view()->mapFromGlobal(QCursor::pos());
statusBar()->showMessage(QString("FPS: %1").arg(QString::number(view->view()->currentFPS(), 'f', 2)));
}
void QGLViewWindow::loadFile(const QString & path, bool import) {
prev_path = path;
QApplication::setOverrideCursor(Qt::WaitCursor);
QFileInfo fi(path);
Scene * s = nullptr;
if (fi.suffix().toLower() == "qgl") s = loadFromQGLFile(path);
else s = loadScene(path);
QApplication::restoreOverrideCursor();
if (!s) {
QMessageBox::critical(this, "Import", "Can`t load " + path + "!");
return;
}
s->setName(fi.baseName());
if (import) view->scene()->addScene(s);
else {
TextureManager::clearSearchPathes();
view->scene()->assignFrom(s);
view->view()->focusOn(view->scene()->boundingBox());
}
TextureManager::addSearchPath(fi.absoluteDir().path());
delete s;
}
void QGLViewWindow::on_actionReset_triggered() {
///view->view()->removeObject(axis, false);
view->view()->scene()->clear();
///view->view()->addObject(axis);
}
void QGLViewWindow::on_actionImport_triggered() {
QStringList fl = QFileDialog::getOpenFileNames(this, "Select files", prev_path, extensions);
if (fl.isEmpty()) return;
prev_path = fl.back();
foreach (QString f, fl)
loadFile(f, true);
}
void QGLViewWindow::on_actionSave_triggered() {
QString f = QFileDialog::getSaveFileName(this, "Select file", prev_path, "QGLView(*.qgl)");
if (f.isEmpty()) return;
if (f.right(4).toLower() != ".qgl")
f += ".qgl";
prev_path = f;
QApplication::setOverrideCursor(Qt::WaitCursor);
saveToQGLFile(f, view->scene());
QApplication::restoreOverrideCursor();
}
void QGLViewWindow::on_actionSaveSelected_triggered() {
ObjectBase * sel_obj = view->view()->selectedObject();
if (!sel_obj) return;
QString f = QFileDialog::getSaveFileName(this, "Select file", prev_path, "QGLView(*.qgl)");
if (f.isEmpty()) return;
if (f.right(4).toLower() != ".qgl")
f += ".qgl";
prev_path = f;
QApplication::setOverrideCursor(Qt::WaitCursor);
///saveToQGLFile(f, sel_obj);
QApplication::restoreOverrideCursor();
}
void QGLViewWindow::on_actionOpen_triggered() {
QString f = QFileDialog::getOpenFileName(this, "Select file", prev_path, extensions);
if (f.isEmpty()) return;
prev_path = f;
loadFile(f);
}
void QGLViewWindow::view_keyEvent(Qt::Key k, Qt::KeyboardModifiers m) {
//qDebug() << k;
double spd = 0.2;
if (m.testFlag(Qt::ShiftModifier))
spd = 0.5;
switch (k) {
case Qt::Key_W: view->view()->camera()->moveForward(spd); break;
case Qt::Key_S: view->view()->camera()->moveBackward(spd); break;
case Qt::Key_A: view->view()->camera()->moveLeft(spd); break;
case Qt::Key_D: view->view()->camera()->moveRight(spd); break;
default: break;
}
}
void QGLViewWindow::on_actionArrow_triggered(bool on) {
actionArrow ->setChecked(true);
actionMove ->setChecked(false);
actionRotate->setChecked(false);
actionScale ->setChecked(false);
view->view()->setCurrentAction(RendererService::haNoAction);
}
void QGLViewWindow::on_actionMove_triggered(bool on) {
actionArrow ->setChecked(false);
actionMove ->setChecked(true);
actionRotate->setChecked(false);
actionScale ->setChecked(false);
view->view()->setCurrentAction(RendererService::haMove);
}
void QGLViewWindow::on_actionRotate_triggered(bool on) {
actionArrow ->setChecked(false);
actionMove ->setChecked(false);
actionRotate->setChecked(true);
actionScale ->setChecked(false);
view->view()->setCurrentAction(RendererService::haRotate);
}
void QGLViewWindow::on_actionScale_triggered(bool on) {
actionArrow ->setChecked(false);
actionMove ->setChecked(false);
actionRotate->setChecked(false);
actionScale ->setChecked(true);
view->view()->setCurrentAction(RendererService::haScale);
}
#include "glcubemap.h"
void QGLViewWindow::on_pushButton_3_clicked() {
QString f = QFileDialog::getOpenFileName(this, "Select file", "", "*");
if (f.isEmpty()) return;
}

View File

@@ -1,119 +0,0 @@
/*
QGLViewWindow
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QGLVIEWWINDOW_H
#define QGLVIEWWINDOW_H
#include <QTranslator>
#include <QInputDialog>
#include <QFileDialog>
#include <QColorDialog>
#include <QCloseEvent>
#include <QClipboard>
#include <QRadioButton>
#include <QUrl>
#include <QThread>
#include <QTime>
#include <QSplitter>
#include "ui_qglview_window.h"
#include "formats/loader_qgl.h"
#include "formats/loader_assimp.h"
#include "session_manager.h"
//#include "renderer_rt.h"
#include "qglview.h"
#include "ui_qglview_window.h"
class QGLViewWindow: public QMainWindow, public Ui::QGLViewWindow
{
Q_OBJECT
public:
QGLViewWindow(QWidget * parent = 0);
~QGLViewWindow();
void loadFile(const QString & path, bool import = false);
private:
// Qt`s overloaded
void changeEvent(QEvent * e);
void timerEvent(QTimerEvent * );
QString extensions;
QTranslator translator;
QString prev_path;
//GLPrimitiveCube * box;
Material m;
SessionManager session;
bool isChanged;
private slots:
void on_groupShadows_clicked(bool val) {view->view()->setFeature(QGLView::qglShadowsEnabled, val);}
void on_groupEyeAccomodation_clicked(bool val) {view->view()->setFeature(QGLView::qglEyeAccomodationEnabled, val);}
void on_groupBloom_clicked(bool val) {view->view()->setFeature(QGLView::qglBloomEnabled, val);}
void on_groupMotionBlur_clicked(bool val) {view->view()->setFeature(QGLView::qglMotionBlurEnabled, val);}
void on_groupReflections_clicked(bool val) {view->view()->setFeature(QGLView::qglReflectionsEnabled, val);}
void on_checkSoftShadows_clicked(bool val) {view->view()->setFeature(QGLView::qglShadowsSoftEnabled, val);}
void on_groupSSAO_clicked(bool val) {view->view()->setFeature(QGLView::qglSSAOEnabled, val);}
void on_groupDOF_clicked(bool val) {view->view()->setFeature(QGLView::qglDepthOfFieldEnabled, val);}
void on_checkDOFAutoFocus_clicked(bool val) {view->view()->setFeature(QGLView::qglDepthOfFieldAutoFocusEnabled, val);}
void on_spinDOFFocus_valueChanged(double val) {view->view()->setFeature(QGLView::qglDepthOfFieldFocus, val);}
void on_spinDOFDiaphragm_valueChanged(double val) {view->view()->setFeature(QGLView::qglDepthOfFieldDiaphragm, val);}
void on_spinDOFSpeed_valueChanged(double val) {view->view()->setFeature(QGLView::qglDepthOfFieldAutoFocusSpeed, val);}
void on_spinAccom_valueChanged(double val) {view->view()->setFeature(QGLView::qglEyeAccomodationTime, val);}
void on_spinAccomMS_valueChanged(double val) {view->view()->setFeature(QGLView::qglEyeAccomodationMaxSpeed, val);}
void on_checkReflectionsBlur_clicked(bool val) {view->view()->setFeature(QGLView::qglReflectionsBlur, val);}
void on_spinShadowmapSize_valueChanged(double val) {view->view()->setFeature(QGLView::qglShadowsMapSize, val);}
void on_spinMotionBlurFactor_valueChanged(double val) {view->view()->setFeature(QGLView::qglMotionBlurFactor, val);}
void on_spinMotionBlurSteps_valueChanged(int val) {view->view()->setFeature(QGLView::qglMotionBlurSteps, val);}
void on_spinBloomFactor_valueChanged(double val) {view->view()->setFeature(QGLView::qglBloomFactor, val);}
void on_spinBloomRadius_valueChanged(int val) {view->view()->setFeature(QGLView::qglBloomRadius, val);}
void on_spinBloomThreshold_valueChanged(double val) {view->view()->setFeature(QGLView::qglBloomThreshold, val);}
void on_spinSSAORadius_valueChanged(int val) {view->view()->setFeature(QGLView::qglSSAORadius, val);}
void on_actionExit_triggered() {close();}
void on_actionReset_triggered();
void on_actionImport_triggered();
void on_actionSave_triggered();
void on_actionSaveSelected_triggered();
void on_actionOpen_triggered();
void view_keyEvent(Qt::Key k, Qt::KeyboardModifiers m);
void on_pushButton_2_clicked() {view->view()->reloadShaders();}
void on_actionArrow_triggered(bool on);
void on_actionMove_triggered(bool on);
void on_actionRotate_triggered(bool on);
void on_actionScale_triggered(bool on);
void on_colorFogBack_colorChanged(const QColor & v) {view->view()->setFogColor(v);}
void on_spinFogDensity_valueChanged(double v) {view->view()->setFogDensity(v);}
void on_spinFogDecay_valueChanged(double v) {view->view()->setFogDecay(v);}
void on_pushButton_3_clicked();
public slots:
signals:
private:
QMatrix4x4 cam_mat;
};
#endif // QGLVIEWWINDOW_H

View File

@@ -1,361 +0,0 @@
/*
QGL Renderer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include <qad_types.h>
#include "renderer.h"
#include "qglview.h"
#include "glmesh.h"
#include "gltexture_manager.h"
#include "glshaders.h"
using namespace QGLEngineShaders;
Renderer::Renderer(QGLView * view_): RendererBase(view_),
fbo_ds (view_, QVector<GLenum>() << GL_RGBA16F << GL_RGBA32F << GL_RGBA16F << GL_RGBA16F << GL_RGBA16F),
fbo_out (view_, obrBuffersCount, false, GL_RGBA16F),
rend_mat(this), rend_service(this), rend_selection(this), tone_proc(this), tex_env(view_, 512) {
quad = Primitive::plane(2., 2.);
cam_light = new Light();
cam_light->intensity = 0.75;
cam_light->setName("Camera_Light");
shader_files[srSelectionFill ] = "selection.glsl";
shader_files[srSelectionHalo ] = "selection_halo.glsl";
shader_files[srSelectionApply] = "selection_apply.glsl";
shader_files[srSelectionFrame] = "selection_frame.glsl";
shader_files[srServiceFill ] = "service_fill.glsl";
shader_files[srServiceFrame] = "service_frame.glsl";
shader_files[srServiceLine ] = "service_line.glsl";
shader_files[srGeometryPass ] = "ds_geom.glsl";
shader_files[srLightOmniPass] = "ds_light.glsl";
shader_files[srLightSpotPass] = "ds_light.glsl"; shader_defines[srLightSpotPass] << "SPOT";
shader_files[srFinalPass ] = "ds_final.glsl";
shader_files[srTonemapPass ] = "ds_tonemap.glsl";
shader_fxaa = 0;
gamma_ = 1.;
edit_mode = need_init_shaders = true;
camera_light_mode = QGLView::clmAuto;
}
Renderer::~Renderer() {
delete quad;
delete cam_light;
qDeleteAll(shaders.values());
if (shader_fxaa) delete shader_fxaa;
}
void Renderer::init(int width, int height) {
resize(width, height);
rend_mat.init(width, height);
rend_service.init(width, height);
rend_selection.init(width, height);
tone_proc.init();
initQuad(quad);
initTextureArrays();
initCoeffTextures();
tex_env.init();
need_init_shaders = true;
}
void Renderer::resize(int width, int height) {
rend_mat.resize(width, height);
rend_service.resize(width, height);
rend_selection.resize(width, height);
fbo_ds .resize(width, height);
fbo_out .resize(width, height);
tone_proc.resize();
}
void Renderer::reloadShaders() {
QMapIterator<ShaderRole, QString> it(shader_files);
QString dir = ":shaders/";
while (it.hasNext()) {
it.next();
loadShadersMulti(shaders[it.key()], dir + it.value(), true, shader_defines.value(it.key()));
}
loadShadersMulti(tone_proc.shader_sum, dir + "sum.glsl", false);
QStringList fxaa_defs;
fxaa_defs << "FXAA_PC 1" << "FXAA_GLSL_130 1" << "FXAA_QUALITY__PRESET 15";
loadShaders(shader_fxaa, QStringList() << (dir + "fxaa.vert") << (dir + "fxaa.frag"), true, fxaa_defs);
need_init_shaders = true;
view->scene()->setLightsChanged();
view->scene()->setTreeStructChanged();
view->scene()->setMaterialsChanged();
}
bool Renderer::bindShader(Renderer::ShaderRole role, QOpenGLShaderProgram ** ret) {
QOpenGLShaderProgram * prog = shaders.value(role);
if (ret) *ret = prog;
if (!prog) return false;
if (!prog->isLinked()) return false;
prog->bind();
return true;
}
bool Renderer::bindShader(QOpenGLShaderProgram * sp) {
if (!sp) return true;
if (!sp->isLinked()) return true;
if (!sp->bind()) return false;
return true;
}
void Renderer::initShaders() {
if (!need_init_shaders) return;
need_init_shaders = false;
initUniformBuffer(shaders.value(srGeometryPass ), &buffer_materials , bpMaterials , "QGLMaterialData" );
initUniformBuffer(shaders.value(srLightOmniPass), &buffer_materials , bpMaterials , "QGLMaterialData" );
initUniformBuffer(shaders.value(srLightOmniPass), &buffer_lights , bpLightParameters, "QGLLightParameterData");
initUniformBuffer(shaders.value(srLightOmniPass), &buffer_lights_pos, bpLightPositions , "QGLLightPositionData" );
initUniformBuffer(shaders.value(srLightSpotPass), &buffer_materials , bpMaterials , "QGLMaterialData" );
initUniformBuffer(shaders.value(srLightSpotPass), &buffer_lights , bpLightParameters, "QGLLightParameterData");
initUniformBuffer(shaders.value(srLightSpotPass), &buffer_lights_pos, bpLightPositions , "QGLLightPositionData" );
ShaderRole roles[] = {srLightOmniPass, srLightSpotPass};
QOpenGLShaderProgram * prog = 0;
for (int p = 0; p < 2; ++p) {
if (!bindShader(roles[p], &prog)) continue;
for (int i = 0; i < 5; ++i)
prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i);
prog->setUniformValue("tex_coeffs[0]", (int)Renderer::dbrBuffersCount);
prog->setUniformValue("tex_env", (int)Renderer::dbrBuffersCount+1);
}
if (bindShader(srFinalPass, &prog)) {
prog->setUniformValue("tex_g1" , 0);
prog->setUniformValue("tex_s_0", 1);
prog->setUniformValue("tex_s_1", 2);
prog->setUniformValue("tex_t_0", 3);
prog->setUniformValue("tex_t_1", 4);
}
if (bindShader(srGeometryPass, &prog)) {
setUniformMaps(prog);
}
if (bindShader(srTonemapPass, &prog)) {
prog->setUniformValue("tex_0", 0);
prog->setUniformValue("tex_sum", 1);
}
}
void Renderer::releaseShader() {
view->glUseProgram(0);
}
void Renderer::fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass) {
cur_objects_.resize(ol.size());
for (int i = 0; i < ol.size(); ++i) {
Object & so(cur_objects_[i]);
ObjectBase * o = ol[i];
if (o->material()) {
so.material = o->material()->_index;
so.color = QVector4D(1,1,1,1);
} else {
so.material = 0;
so.color = QColor2QVector(o->color());
}
so.object_id = o->id();
o->worldTransform().transposed().copyDataTo(so.modelmatrix);
//qDebug() << "load obj" << o->name() << o->worldTransform();
}
//qDebug() << "fillObjectsBuffer" << ol.size();
}
void Renderer::renderObjects(Scene & scene, RenderPass pass) {
QOpenGLExtraFunctions * f = view;
QMapIterator<Mesh*, ObjectBaseList> it(scene.geometries_used[pass]);
bool emit_pos_change = false;
while (it.hasNext()) {
it.next();
Mesh * mesh = it.key();
if (mesh->isObjectsChanged(pass)) {
mesh->setObjectsChanged(pass, false);
emit_pos_change = true;
fillObjectsBuffer(it.value(), pass);
//qDebug() << "loadObjects" << pass << cur_objects_.size();
mesh->loadObjects(f, cur_objects_, pass);
}
if (mesh->isSelectionChanged(pass) && edit_mode) {
mesh->setSelectionChanged(pass, false);
fillSelectionsBuffer(rend_selection.cur_selections_, it.value());
//qDebug() << "fillSelectionsBuffer" << pass << rend_selection.cur_selections_.size();
mesh->loadSelections(f, rend_selection.cur_selections_, pass);
}
//qDebug() << "draw" << pass << it.value().size();
mesh->draw(f, it.value().size(), pass);
}
if (emit_pos_change) emit view->objectsPositionChanged();
}
void Renderer::renderLight(int first_wr_buff, bool clear_only) {
QOpenGLShaderProgram * prog = 0;
Camera * cam = view->camera();
for (int i = 0; i < 2; ++i) {
view->glActiveTexture(GL_TEXTURE0 + Renderer::dbrBuffersCount + i);
view->glBindTexture(GL_TEXTURE_2D, tex_coeff[i]);
}
fbo_ds.bindColorTextures();
fbo_out.bind();
tex_env.bind((int)Renderer::dbrBuffersCount+1);
typedef QPair<Renderer::ShaderRole, Light::Type> PassPair;
QVector<PassPair> passes;
passes << PassPair(srLightOmniPass, Light::Omni) << PassPair(srLightSpotPass, Light::Cone);
QColor back = view->fogColor();
back.setAlpha(0);
foreach (PassPair pass, passes) {
if (bindShader(pass.first, &prog)) {
fbo_out.setWriteBuffer(first_wr_buff + pass.second);
glClearFramebuffer(back, false);
if (clear_only) continue;
setUniformCamera(prog, cam);
setUniformViewCorners(prog, cam);
prog->setUniformValue("lights_start", lights_start[pass.second]);
prog->setUniformValue("lights_count", (int)cur_lights[pass.second].size());
prog->setUniformValue("fog_color", view->fogColor());
prog->setUniformValue("fog_decay", qMax(view->fogDecay(), 0.001f));
prog->setUniformValue("fog_density", view->fogDensity());
prog->setUniformValue("view_mat", cam->viewMatrix().inverted().toGenericMatrix<3,3>());
renderQuad(prog, quad, cam);
}
}
}
void Renderer::renderScene() {
initShaders();
tex_env.load();
QOpenGLExtraFunctions * f = view;
Scene & scene(*(view->scene()));
Camera * cam = view->camera();
QOpenGLShaderProgram * prog = 0;
bool scene_changed = scene.prepare();
scene.destroyUnused(f);
/// reload materials on change
if (scene_changed || scene.need_reload_materials) {
rend_selection.generateObjectsID(scene);
reloadMaterials(scene);
if (edit_mode)
recreateMaterialThumbnails();
emit view->materialsChanged();
}
/// material thumbnails
if (edit_mode && !scene_changed) {
rend_mat.procQueue();
}
/// lights
cur_lights = scene.lights_used;
bool use_camlight = (camera_light_mode == QGLView::clmOn);
if ((camera_light_mode == QGLView::clmAuto) && cur_lights.isEmpty())
use_camlight = true;
if (use_camlight) {
cur_lights[Light::Omni] << cam_light;
cam_light->setPos(cam->pos());
}
if (scene.lights_changed) {
scene.lights_changed = false;
reloadLightsParameters(cur_lights);
}
reloadLightsPositions(cam);
/// selection
if (edit_mode) {
rend_selection.renderSelection(scene);
}
/// solid geometry pass
fbo_ds.bind();
glEnableDepth();
glClearFramebuffer();
if (bindShader(srGeometryPass, &prog)) {
setUniformCamera(prog, cam);
textures_empty.bind(f, tarEmpty);
textures_maps .bind(f, tarMaps );
renderObjects(scene, rpSolid);
}
fbo_ds.release();
/// lighting passes
renderLight(obrSolidOmni, scene.geometries_used[rpSolid].isEmpty());
/// transparent geometry pass
fbo_ds.bind();
glEnableDepth();
glClearFramebuffer(Qt::black, false);
if (bindShader(srGeometryPass, &prog)) {
renderObjects(scene, rpTransparent);
}
fbo_ds.release();
/// lighting passes
renderLight(obrTransparentOmni, scene.geometries_used[rpTransparent].isEmpty());
/// blending layers
if (bindShader(srFinalPass, &prog)) {
fbo_out.bindColorTexture(obrSolidOmni , 1);
fbo_out.bindColorTexture(obrSolidSpot , 2);
fbo_out.bindColorTexture(obrTransparentOmni, 3);
fbo_out.bindColorTexture(obrTransparentSpot, 4);
fbo_out.setWriteBuffer(obrSum);
renderQuad(prog, quad);
}
/// tonemapping
if (tone_proc.process())
fbo_out.bind();
if (bindShader(srTonemapPass, &prog)) {
prog->setUniformValue("gamma", gamma_);
prog->setUniformValue("frame_max", tone_proc.frameMax());
fbo_out.bindColorTexture(obrSum, 0);
fbo_out.setWriteBuffer(obrTonemap);
renderQuad(prog, quad);
} else
fbo_out.blit(obrSum, fbo_out.id(), obrTonemap, fbo_out.rect(), fbo_out.rect());
fbo_out.release();
/// apply hovers and selection frame
if (edit_mode) {
rend_selection.drawSelection(fbo_out, obrTonemap);
rend_service.renderService();
} else {
fbo_out.blit(obrTonemap, 0, 0, fbo_out.rect(), QRect(QPoint(), view->size()));
}
}
void Renderer::setCameraLightMode(int m) {
camera_light_mode = m;
view->scene()->setLightsChanged();
}

View File

@@ -1,130 +0,0 @@
/*
QGL Renderer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RENDERER_H
#define RENDERER_H
#include "renderer_base.h"
#include "renderer_material.h"
#include "renderer_service.h"
#include "renderer_selection.h"
#include "tonemapping_proc.h"
#include "glcubemap.h"
#include <QQueue>
class Renderer: public RendererBase {
friend class QGLView;
friend class MouseController;
friend class RendererMaterial;
friend class RendererService;
friend class RendererSelection;
friend class TonemappingProc;
enum ShaderRole {
// Selection
srSelectionFill,
srSelectionHalo,
srSelectionApply,
srSelectionFrame,
// Service
srServiceFill,
srServiceFrame,
srServiceLine,
// Deferred shading
srGeometryPass,
srLightOmniPass,
srLightSpotPass,
srFinalPass,
srTonemapPass,
};
enum DeferredBufferRole {
dbrDiffuse,
dbrNormalZ,
dbrSpecularReflect,
dbrEmissionRough,
dbrSpeedBitangXY,
dbrBuffersCount,
};
enum OutBufferRole {
obrTonemap,
obrSum,
obrSolidOmni,
obrSolidSpot,
obrTransparentOmni,
obrTransparentSpot,
obrBuffersCount,
};
public:
Renderer(QGLView * view_);
virtual ~Renderer();
void init(int width, int height);
void resize(int width, int height);
void reloadShaders();
void renderScene();
void setCameraLightMode(int m);
int cameraLightMode() const {return camera_light_mode;}
QImage materialThumbnail(Material * m) {return rend_mat.materialThumbnail(m);}
void recreateMaterialThumbnails(bool force_all = false) {rend_mat.recreateMaterialThumbnails(force_all);}
protected:
void fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass);
void reloadObjects();
void renderObjects(Scene & scene, RenderPass pass);
void renderLight(int first_wr_buff, bool clear_only);
bool bindShader(ShaderRole role, QOpenGLShaderProgram ** ret = 0);
bool bindShader(QOpenGLShaderProgram * sp);
void initShaders();
void releaseShader();
private:
float gamma_;
int camera_light_mode;
bool edit_mode, need_init_shaders, need_render_sum;
Framebuffer fbo_ds, fbo_out;
QMap<ShaderRole, QString> shader_files;
QMap<ShaderRole, QStringList> shader_defines;
QMap<ShaderRole, QOpenGLShaderProgram*> shaders;
QOpenGLShaderProgram * shader_fxaa;
RendererMaterial rend_mat;
RendererService rend_service;
RendererSelection rend_selection;
TonemappingProc tone_proc;
Mesh * quad;
Light * cam_light;
CubeTexture tex_env;
QPoint mouse_pos;
QRect mouse_rect;
QMatrix4x4 prev_view, prev_proj;
QMatrix3x3 nm;
QVector4D corner_dirs[4];
QVector<QVector3D> hcontent;
QMap<int, QList<Light*>> cur_lights;
};
#endif // RENDERER_H

View File

@@ -1,67 +0,0 @@
/*
QGL RendererBase
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RENDERER_BASE_H
#define RENDERER_BASE_H
#include "glshaders_types.h"
#include "gltexturearray.h"
#include "glbuffer.h"
class RendererBase {
public:
RendererBase(QGLView * view_);
~RendererBase();
protected:
void initTextureArrays();
void initUniformBuffer (QOpenGLShaderProgram * prog, Buffer * buffer, int bind_point, const char * blockName);
void setUniformHalo (QOpenGLShaderProgram * prog, const char * type, QColor color, float fill);
void setUniformMaps (QOpenGLShaderProgram * prog);
void setUniformCamera (QOpenGLShaderProgram * prog, Camera * cam, bool matrices = true, QSize viewport = QSize());
void setUniformViewCorners(QOpenGLShaderProgram * prog, Camera * cam, QSize viewport = QSize());
void fillSelectionsBuffer(QVector<uchar> & buffer, const ObjectBaseList & ol);
void fillSelectionsBuffer(QVector<uchar> & buffer, bool yes, int size);
void reloadMaterials(Scene & scene);
void reloadLightsParameters(const QMap<int, QList<Light*>> & lights);
void reloadLightsPositions (Camera * cam);
void markReloadTextures();
void setMapsSize(QSize sz);
void initQuad(Mesh * mesh, QMatrix4x4 mat = QMatrix4x4());
void renderQuad(QOpenGLShaderProgram * prog, Mesh * mesh, Camera * cam = 0, bool uniforms = true);
void initCoeffTextures();
void createCoeffTexture(GLuint & id, const void * data, int size, int channels = 1);
QGLView * view;
TextureManager * textures_manager;
QVector<QGLEngineShaders::Object> cur_objects_;
QVector<QGLEngineShaders::QGLMaterial> cur_materials_;
QVector<QGLEngineShaders::QGLLightParameter> cur_lights_params_;
QVector<QGLEngineShaders::QGLLightPosition> cur_lights_pos_;
Buffer buffer_materials;
Buffer buffer_lights, buffer_lights_pos;
Texture2DArray textures_empty, textures_maps;
QSize maps_size;
uint maps_hash;
GLuint tex_coeff[2];
QMap<int, int> lights_start;
QList<Light*> current_lights;
};
#endif // RENDERER_BASE_H

View File

@@ -1,51 +0,0 @@
/*
QGL RendererMaterial
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RENDERER_MATERIAL_H
#define RENDERER_MATERIAL_H
#include "glframebuffer.h"
#include <QQueue>
class RendererMaterial {
friend class QGLView;
public:
RendererMaterial(Renderer * r_);
virtual ~RendererMaterial();
void init(int width, int height);
void resize(int width, int height);
QImage materialThumbnail(Material * m);
void recreateMaterialThumbnails(bool force_all = false);
void renderMaterial(Material * m);
void procQueue();
private:
Renderer * r;
Framebuffer fbo_mat_thumb;
Mesh * mat_sphere;
Camera * mat_camera;
Light * mat_light;
QMap<Material*, QImage> mat_thumbnails;
Material * last_thumb_material;
QQueue<Material*> mat_thumb_queue;
};
#endif // RENDERER_MATERIAL_H

View File

@@ -1,19 +0,0 @@
<RCC>
<qresource prefix="/">
<file>shaders/ds_final.glsl</file>
<file>shaders/ds_geom.glsl</file>
<file>shaders/ds_light.glsl</file>
<file>shaders/ds_tonemap.glsl</file>
<file>shaders/fxaa.frag</file>
<file>shaders/fxaa.vert</file>
<file>shaders/fxaa_v3.h</file>
<file>shaders/selection.glsl</file>
<file>shaders/selection_apply.glsl</file>
<file>shaders/selection_frame.glsl</file>
<file>shaders/selection_halo.glsl</file>
<file>shaders/service_fill.glsl</file>
<file>shaders/service_frame.glsl</file>
<file>shaders/service_line.glsl</file>
<file>shaders/sum.glsl</file>
</qresource>
</RCC>

View File

@@ -3,15 +3,21 @@
out vec3 geom_normal; out vec3 geom_normal;
out mat3 TBN; out mat3 TBN;
out vec4 object_color; out vec4 object_color;
out float object_flags;
const vec3 luma = vec3(0.299, 0.587, 0.114);
void main(void) { void main(void) {
qgl_MaterialIndex = qgl_Material; qgl_MaterialIndex = qgl_Material;
qgl_FragTexture = qgl_Texture; qgl_FragTexture = qgl_getFragTexture();
gl_Position = qgl_ftransform();
geom_normal = normalize(qgl_Normal * qgl_getNormalMatrix()); geom_normal = normalize(qgl_Normal * qgl_getNormalMatrix());
TBN = qgl_getTangentMatrix() * mat3(qgl_Tangent, qgl_Bitangent, qgl_Normal); TBN = qgl_getTangentMatrix() * mat3(qgl_Tangent, qgl_Bitangent, qgl_Normal);
object_color = qgl_ObjectColor; object_color = qgl_ObjectColor;
object_flags = qgl_ObjectFlags;
float height = dot(qgl_materialTexture(QGL_MAP_RELIEF, qgl_FragTexture, vec4(0.)).rgb, luma);
gl_Position = qgl_ViewProjMatrix * (qgl_ModelMatrix * (vec4(qgl_Vertex + qgl_Normal * height, 1.)));//qgl_ftransform();
} }
@@ -20,9 +26,11 @@ void main(void) {
in vec3 geom_normal; in vec3 geom_normal;
in mat3 TBN; in mat3 TBN;
in vec4 object_color; in vec4 object_color;
in float object_flags;
uniform vec2 dt; uniform vec2 dt;
uniform float z_near; uniform float z_near;
uniform int out_index_normal = dbrNormalZ, out_index_metal = dbrMetalRoughReflectFlags;
const vec3 luma = vec3(0.299, 0.587, 0.114); const vec3 luma = vec3(0.299, 0.587, 0.114);
const float _pe = 2.4e-7; const float _pe = 2.4e-7;
@@ -30,9 +38,13 @@ const float _pe = 2.4e-7;
void main(void) { void main(void) {
vec2 tc = qgl_FragTexture.xy; vec2 tc = qgl_FragTexture.xy;
vec4 diffuse = qgl_materialTexture(QGL_MAP_DIFFUSE, tc, vec4(0)) * object_color; vec4 diffuse = qgl_materialTexture(QGL_MAP_DIFFUSE, tc, vec4(0.)) * object_color;
diffuse.rgb *= qgl_material[qgl_MaterialIndex].color_diffuse.rgb; diffuse.rgb *= qgl_material[qgl_MaterialIndex].color_diffuse.rgb;
diffuse.a *= (1.f - qgl_material[qgl_MaterialIndex].transparency); #ifdef SOLID
if(diffuse.a < 0.5)
discard;
#endif
diffuse.a *= (1. - qgl_material[qgl_MaterialIndex].transparency);
vec3 normal, dn; vec3 normal, dn;
dn = qgl_materialTexture(QGL_MAP_NORMAL, tc, -vec4(0.5, 0.5, 1., 0.)).xyz; dn = qgl_materialTexture(QGL_MAP_NORMAL, tc, -vec4(0.5, 0.5, 1., 0.)).xyz;
@@ -42,28 +54,27 @@ void main(void) {
dn *= dn_sl / (length(dn) + 1E-6); dn *= dn_sl / (length(dn) + 1E-6);
normal = normalize(geom_normal + dn); normal = normalize(geom_normal + dn);
float metalness = dot(qgl_materialTexture(QGL_MAP_METALNESS, tc, vec4(0)).rgb, luma); float metalness = dot(qgl_materialTexture(QGL_MAP_METALNESS, tc, vec4(0.)).rgb, luma);
metalness = clamp(metalness, 0, 1); metalness = clamp(metalness, 0, 1);
float roughness = dot(qgl_materialTexture(QGL_MAP_ROUGHNESS, tc, vec4(0)).rgb, luma); float roughness = dot(qgl_materialTexture(QGL_MAP_ROUGHNESS, tc, vec4(0.)).rgb, luma);
roughness = clamp(roughness, 0.0001, 0.9999); roughness = clamp(roughness, 0.0001, 0.9999);
float reflectivity = clamp(qgl_material[qgl_MaterialIndex].reflectivity, 0., 1.); float reflectivity = clamp(qgl_material[qgl_MaterialIndex].reflectivity, 0., 1.);
vec4 emission = qgl_materialTexture(QGL_MAP_EMISSION, tc, vec4(0)); vec4 emission = qgl_materialTexture(QGL_MAP_EMISSION, tc, vec4(0.));
emission *= qgl_material[qgl_MaterialIndex].color_emission; emission *= qgl_material[qgl_MaterialIndex].color_emission;
float height = dot(qgl_materialTexture(QGL_MAP_RELIEF, tc, vec4(0)).rgb, luma);
float z = gl_FragCoord.z; float z = gl_FragCoord.z;
z = z + z - 1; z = z + z - 1.;
z = ((_pe - 2.) * z_near) / (z + _pe - 1.); // infinite depth z = ((_pe - 2.) * z_near) / (z + _pe - 1.); // infinite depth
qgl_FragData[0] = vec4(diffuse .rgba); qgl_FragData[dbrDiffuse ] = vec4(diffuse .rgba);
qgl_FragData[1] = vec4(normal .xyz, z); qgl_FragData[out_index_normal] = vec4(normal .xyz, z);
qgl_FragData[2] = vec4(metalness, roughness, reflectivity, 0); qgl_FragData[out_index_metal ] = vec4(metalness, roughness, reflectivity, object_flags);
qgl_FragData[3] = vec4(emission.rgb, 0/*bn.x*/); qgl_FragData[dbrEmission ] = vec4(emission.rgb, 0./*bn.x*/);
//qgl_FragData[4] = vec4(speed.xy, bn.yz); //qgl_FragData[dbrSpeedBitangXY] = vec4(speed.xy, bn.yz);
qgl_FragData[dbrGeoNormal ] = vec4(normalize(geom_normal), 1.);
//ivec2 itc = ivec2(gl_FragCoord.xy); //ivec2 itc = ivec2(gl_FragCoord.xy);
//qgl_FragData[0].rgb = vec3(dot(n,vec3(0,0,1))); //qgl_FragData[0].rgb = vec3(dot(n,vec3(0,0,1)));

View File

@@ -18,22 +18,143 @@ in vec3 view_dir, world_dir;
uniform vec2 dt; uniform vec2 dt;
uniform float z_near; uniform float z_near;
uniform sampler2D tex_coeffs[2]; uniform sampler2D tex_coeff_brdf, tex_noise;
uniform sampler2D tex_0, tex_1, tex_2, tex_3, tex_4; uniform sampler2D tex_0, tex_1, tex_2, tex_3, tex_4, tex_5, tex_sh;
//uniform sampler2DShadow tex_shadow[16];
#ifdef SHADOWS
uniform vec2 shadow_size;
uniform sampler2DArrayShadow tex_shadows_cone;
uniform sampler2DArray tex_depths_cone;
uniform samplerCubeArrayShadow tex_shadows_omni;
uniform samplerCubeArray tex_depths_omni;
uniform bool soft_shadows_enabled = false;
uniform float soft_shadows_quality = 1.;
uniform int soft_shadows_samples = 16, noise_size = 64;
#endif
uniform samplerCube tex_env; uniform samplerCube tex_env;
uniform int lights_start, lights_count; uniform int lights_start, lights_count;
uniform vec4 fog_color = vec4(0.5, 0.5, 0.5, 1.);
uniform vec4 fog_color = vec4(0.5, 0.5, 0.5, 1); uniform float fog_decay = 10., fog_density = 0.;
uniform float fog_decay = 10, fog_density = 0;
uniform mat3 view_mat; uniform mat3 view_mat;
const float _pe = 2.4e-7;
const vec3 luma = vec3(0.299, 0.587, 0.114); const vec3 luma = vec3(0.299, 0.587, 0.114);
const float _min_rough = 1.e-8, max_lod = 8; const float _min_rough = 1.e-8, max_lod = 8.;
const float PI = 3.1416;
ivec2 tc;
vec4 pos, lpos, shp; vec4 pos, lpos, shp;
vec3 li, si, ldir, halfV, bn, bn2, lwdir; vec3 li, si, ldir, halfV, bn, bn2, lwdir;
//vec3 vds, vds2; vec3 normal, geom_normal, vds, vds2;
float rough_diff, rough_spec, dist, NdotL, NdotH, spot, ldist, diff, spec, sdist, shadow; float rough_diff, rough_spec, dist, NdotL, NdotH, spot, ldist, diff, spec, sdist;
uint flags;
vec4 mapScreenToShadow(in int light_index, in vec3 offset) {
vec4 shp = qgl_light_position[light_index].shadow_matrix * (pos + vec4(offset, 0));
//shp.z += 0.5;
return shp;
}
#ifdef SHADOWS
#ifdef SPOT
float getShadowCone(in vec3 uvz, in int layer) {
/*vec2 uvpix = uvz.xy * shadow_size + vec2(0.5f);
vec2 uvp = fract(uvpix), iuvp = vec2(1.f) - uvp;
vec4 gt = textureGather(tex_shadows_cone, vec3(floor(uvpix.xy) / shadow_size, layer), 0);
vec4 uvv;
uvv[0] = iuvp.x * uvp.y;
uvv[1] = uvp.x * uvp.y;
uvv[2] = uvp.x * iuvp.y;
uvv[3] = iuvp.x * iuvp.y;
shadow_dz = max(max(uvz.z - gt[0], uvz.z - gt[1]), max(uvz.z - gt[2], uvz.z - gt[3]));
return clamp(dot(step(vec4(uvz.z), gt), uvv), 0, 1);*/
float z = 1. - 1. / (uvz.z - z_near + 1.);
return texture(tex_shadows_cone, vec4(uvz.xy, layer, z));
}
#else
float getShadowOmni(in vec4 uvwz, in int layer) {
/*vec3 uvpix = uvwz.xyz * vec3(shadow_size.x) + vec3(0.5f);
vec3 uvp = fract(uvpix), iuvp = vec3(1.f) - uvp;
vec4 gt = textureGather(tex_shadows_omni, vec4(floor(uvpix.xyz) / vec3(shadow_size.x), layer), 0);
vec4 uvv;
uvv[0] = iuvp.y * uvp.z;
uvv[1] = uvp.y * uvp.z;
uvv[2] = uvp.y * iuvp.z;
uvv[3] = iuvp.y * iuvp.z;
return clamp(dot(step(vec4(uvwz.w), gt), uvv), 0, 1);*/
float d = 1. - 1. / (uvwz.w - z_near + 1.);
return texture(tex_shadows_omni, vec4(uvwz.xyz, layer), d);
//return step(uvwz.w, gt[3]);
}
#endif
uint hash(uint x) {
x += (x << 10u);
x ^= (x >> 6u);
x += (x << 3u);
x ^= (x >> 11u);
x += (x << 15u);
return x;
}
uint hash( uvec2 v ) { return hash( v.x ^ hash(v.y) ); }
uint hash( uvec3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ); }
uint hash( uvec4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); }
float floatConstruct( uint m ) {
const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask
const uint ieeeOne = 0x3F800000u; // 1.0 in IEEE binary32
m &= ieeeMantissa; // Keep only mantissa bits (fractional part)
m |= ieeeOne; // Add fractional part to 1.0
float f = uintBitsToFloat( m ); // Range [1:2]
return f - 1.; // Range [0:1]
}
float random( float x ) { return floatConstruct(hash(floatBitsToUint(x))); }
float random( vec2 v ) { return floatConstruct(hash(floatBitsToUint(v))); }
float random( vec3 v ) { return floatConstruct(hash(floatBitsToUint(v))); }
float random( vec4 v ) { return floatConstruct(hash(floatBitsToUint(v))); }
float random( int x ) { return floatConstruct(hash(x)); }
float random( ivec2 v ) { return floatConstruct(hash(v)); }
float random( ivec3 v ) { return floatConstruct(hash(v)); }
float random( ivec4 v ) { return floatConstruct(hash(v)); }
uvec2 noise_hash;
void noise2init(vec2 v) {
noise_hash = uvec2(hash(uint(v.x + 1)), hash(uint(v.y - 1)));
}
vec2 noise2() {
noise2init(vec2(noise_hash));
//return vec2(floatConstruct(noise_hash.x), floatConstruct(noise_hash.y)) * 2 - vec2(1.);
float r = floatConstruct(noise_hash.x);
float a = floatConstruct(noise_hash.y) * 2 * PI;
return r * vec2(cos(a), sin(a));
}
float rand(vec2 co) {
float a = 12.9898;
float b = 78.233;
float c = 43758.5453;
float d = dot(co.xy, vec2(a, b));
float e = sin(mod(d, 3.14)) * c;
return fract(e) - 0.5;
}
#endif // SHADOWS
vec4 qgl_lightTexture(int index, vec2 coord, vec4 tex_shift) {
coord *= qgl_light_parameter[index].map.scale;
vec4 t = texture(qgl_texture_array[qgl_light_parameter[index].map.array_index],
vec3(coord, qgl_light_parameter[index].map.map_index));
t += tex_shift;
t.rgb *= qgl_light_parameter[index].map.amount + qgl_light_parameter[index].map.offset;
return t;
}
void calcLight(in int index, in vec3 n, in vec3 v) { void calcLight(in int index, in vec3 n, in vec3 v) {
lpos = qgl_light_position[index].position; lpos = qgl_light_position[index].position;
@@ -45,42 +166,109 @@ void calcLight(in int index, in vec3 n, in vec3 v) {
NdotL = max(dot(n, ldir), 1E-8); NdotL = max(dot(n, ldir), 1E-8);
NdotH = max(dot(n, halfV), 1E-8); NdotH = max(dot(n, halfV), 1E-8);
spot = step(1.001E-8, NdotL) * qgl_light_parameter[index].decay_intensity.w; spot = step(1.001E-8, NdotL) * qgl_light_parameter[index].decay_intensity.w;
vec3 light_color = qgl_light_parameter[index].color.rgb;
#ifdef SPOT #ifdef SPOT
float scos = max(dot(-ldir, qgl_light_position[index].direction.xyz), 0.); float scos = max(dot(-ldir, qgl_light_position[index].direction.xyz), 0.);
spot *= scos * step(qgl_light_parameter[index].angles.w, scos); spot *= scos * step(qgl_light_parameter[index].angles.w, scos);
spot *= smoothstep(qgl_light_parameter[index].angles.w, qgl_light_parameter[index].angles.y, scos); spot *= smoothstep(qgl_light_parameter[index].angles.w, qgl_light_parameter[index].angles.y, scos);
/*//lwdir = mat3(mat_viewi) * qgl_Light[index].direction.xyz; vec4 shp = mapScreenToShadow(index, vec3(0));
//bn = normalize(cross(lwdir, vec3(1, 0, 0))); shp.xy /= shp.w;
//bn2 = normalize(cross(lwdir, bn)); vec4 light_map_pix = qgl_lightTexture(index, shp.xy, vec4(0));
float ds = ldist/200.;//max(abs(sdist) / 5000, 0.02); light_color *= light_map_pix.rgb;
//spot *= clamp(1. - sdist, 0, 1); spot *= light_map_pix.a;
vds = ds * bn.xyz;
vds2 = ds * bn2.xyz;
float shadow = getShadow(index, pos.xyz, vec3(0)) * 3.;
shadow += getShadow(index, pos.xyz, vds ) * 2.;
shadow += getShadow(index, pos.xyz, - vds ) * 2.;
shadow += getShadow(index, pos.xyz, - vds2 ) * 2.;
shadow += getShadow(index, pos.xyz, + vds2 ) * 2.;
//shadow += getShadow(index, pos.xyz, vds - vds2 ) * 1.5;
//shadow += getShadow(index, pos.xyz, vds + vds2 ) * 1.5;
//shadow += getShadow(index, pos.xyz, - vds - vds2 ) * 1.5;
//shadow += getShadow(index, pos.xyz, - vds + vds2 ) * 1.5;
//shadow += getShadow(index, pos.xyz, vds + vds );
//shadow += getShadow(index, pos.xyz, - vds - vds );
//shadow += getShadow(index, pos.xyz, - vds2 - vds2);
//shadow += getShadow(index, pos.xyz, + vds2 + vds2);
//shadow += getShadow(index, pos.xyz, vds + vds - vds2 );
//shadow += getShadow(index, pos.xyz, - vds - vds - vds2 );
//shadow += getShadow(index, pos.xyz, vds + vds + vds2 );
//shadow += getShadow(index, pos.xyz, - vds - vds + vds2 );
//shadow += getShadow(index, pos.xyz, vds - vds2 - vds2);
//shadow += getShadow(index, pos.xyz, vds + vds2 + vds2);
//shadow += getShadow(index, pos.xyz, - vds - vds2 - vds2);
//shadow += getShadow(index, pos.xyz, - vds + vds2 + vds2);
//shadow += shadow += getShadow(index, pos.xyz, vds+vds2)*10;
spot *= mix(1., shadow / 11., shadow_on);*/
#endif #endif
vec3 dist_decay = vec3(1, ldist, ldist*ldist);
#ifdef SHADOWS
if (int(round(qgl_light_parameter[index].flags)) == 1 && bitfieldExtract(flags, 3, 1) == 1 && (spot > 1E-4)) {
#ifndef SPOT
vec3 odir = -(view_mat * ldir);
#endif
int layer = index - lights_start;
float shadow = 0.;
//float bias = abs(tan(PI/2.*(1 - abs(dot(normal, ldir)))) + 1) * z_near * 1;
float bias = (1. + 1. / abs(dot(geom_normal, ldir))) * z_near * 2.;
//bias = bias * bias + z_near;
if (soft_shadows_enabled) {
float depth = 1.;
#ifdef SPOT
const int gm_size = 2;
for (int i = -gm_size; i <= gm_size; ++i) {
for (int j = -gm_size; j <= gm_size; ++j) {
//depth = min(depth, textureOffset(tex_depths_cone, vec3(shp.xy, layer), ivec2(i, j)).x);
depth = min(depth, texture(tex_depths_cone, vec3(shp.xy + vec2(i, j) / vec2(shadow_size.x), layer)).x);
}
}
#else
const int gm_size = 2;
for (int i = -gm_size; i <= gm_size; ++i) {
for (int j = -gm_size; j <= gm_size; ++j) {
for (int k = -gm_size; k <= gm_size; ++k) {
depth = min(depth, texture(tex_depths_omni, vec4(odir + vec3(i, j, k) / vec3(shadow_size.x), layer)).r);
}
}
}
shp.z = ldist;
#endif
depth = 1. / (1. - depth) - 1. + z_near;
float dz = max(0., shp.z - depth);
float ds = qgl_light_parameter[index].size * dz / (ldist - dz);
//float ds = (ldist / 2.) / qgl_light_parameter[index].size;
float srate = abs(ds / pos.z) * 10. * soft_shadows_quality;
//qgl_FragColor.rgb = vec3(srate);
int samples = clamp(int(round(srate * float(soft_shadows_samples))), 1, soft_shadows_samples);
vds = ds * bn.xyz;
vds2 = ds * bn2.xyz;
vec2 so;
ivec2 sotc = tc;
noise2init(vec2(hash(ivec2(tc.x * 2. + 1., tc.y)), hash(ivec2(tc.x, (tc.y * 2. + 1.)))));
for (int i = 0; i < samples; ++i) {
so = noise2();
#ifdef SPOT
//vec4 nc = texelFetch(tex_noise, sotc % noise_size, 0);
//sotc += ivec2(nc.ba * 256) % noise_size;
//so = (nc.rg - vec2(0.5));
//so = vec2(rand(vec2(shp.x + i, shp.y)), rand(vec2(shp.x + i + 1, shp.y)));
vec4 shp = mapScreenToShadow(index, vds * so.x + vds2 * so.y);
shp.xy /= shp.w;
shp.z -= bias;
shadow += getShadowCone(shp.xyz, layer);
#else
//so = vec2(rand(vec2(odir.x + i, odir.y)), rand(vec2(odir.x + i + 1, odir.y)))*1.25;
vec3 old = lpos.xyz - ((pos.xyz + vec3(vds * so.x + vds2 * so.y)) * lpos.w);
odir = -(view_mat * old);
shadow += getShadowOmni(vec4(odir, length(old) - bias), layer);
#endif
}
spot *= min(1., 2. * shadow / samples);
//spot *= shadow / soft_shadows_samples;
//spot *= shadow / soft_shadows_samples + 1;
} else {
#ifdef SPOT
shp.xy;
shp.z -= bias;
spot *= getShadowCone(shp.xyz, layer);
#else
spot *= getShadowOmni(vec4(odir, ldist - bias), layer);
#endif
}
//shp.z -= bias;
//shadow += getShadowCone(shp.xyz, layer, vec2(0));
}
#endif // SHADOWS
vec3 dist_decay = vec3(1., ldist, ldist*ldist);
spot /= dot(qgl_light_parameter[index].decay_intensity.xyz, dist_decay); spot /= dot(qgl_light_parameter[index].decay_intensity.xyz, dist_decay);
float NdotLs = NdotL*NdotL; float NdotLs = NdotL*NdotL;
@@ -89,53 +277,36 @@ void calcLight(in int index, in vec3 n, in vec3 v) {
float ndlc = (1. - NdotLs) / NdotLs; float ndlc = (1. - NdotLs) / NdotLs;
diff = 2. / (1. + sqrt(1. + (1. - rough_diff) * ndlc)); diff = 2. / (1. + sqrt(1. + (1. - rough_diff) * ndlc));
//diff = texture(tex_coeffs[0], vec2(roughness, (NdotLs))).r; //diff = texture(tex_coeffs[0], vec2(roughness, (NdotLs))).r;
li += spot * diff * qgl_light_parameter[index].color.rgb; li += spot * diff * light_color;
ndlc = (1. - NdotHs) / NdotHs; ndlc = (1. - NdotHs) / NdotHs;
float der = NdotHs * (rough_spec + ndlc); float der = NdotHs * (rough_spec + ndlc);
spec = rough_spec / (der*der) / 3.1416; spec = rough_spec / (der*der) / PI;
//spec = texture(tex_coeffs[1], vec2(roughness, (NdotHs))).r; //spec = texture(tex_coeffs[1], vec2(roughness, (NdotHs))).r;
si += spot * spec * qgl_light_parameter[index].color.rgb; si += spot * spec * light_color;
} }
float GeometrySchlickGGX(float NdotV, float roughness) {
float a = roughness;
float k = (a * a) / 2.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
// ----------------------------------------------------------------------------
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
void main(void) { void main(void) {
ivec2 tc = ivec2(gl_FragCoord.xy); tc = ivec2(gl_FragCoord.xy);
vec4 v1 = texelFetch(tex_1, tc, 0); vec4 v1 = texelFetch(tex_1, tc, 0);
float z = v1.w; float z = v1.w;
if (z == 1.) { if (z == 1.) {
discard; discard;
} }
pos.w = 1; pos.w = 1.;
pos.xyz = view_dir * z; pos.xyz = view_dir * z;
vec3 v = normalize(-pos.xyz); vec3 v = normalize(-pos.xyz);
vec4 v0 = texelFetch(tex_0, tc, 0), vec4 v0 = texelFetch(tex_0, tc, 0),
v2 = texelFetch(tex_2, tc, 0), v2 = texelFetch(tex_2, tc, 0),
v3 = texelFetch(tex_3, tc, 0), v3 = texelFetch(tex_3, tc, 0),
v4 = texelFetch(tex_4, tc, 0); v4 = texelFetch(tex_4, tc, 0),
v5 = texelFetch(tex_5, tc, 0);
vec3 diffuse = v0.rgb; vec3 diffuse = v0.rgb;
vec3 normal = v1.xyz; normal = v1.xyz;
geom_normal = v5.xyz;
vec3 emission = v3.rgb; vec3 emission = v3.rgb;
float alpha = v0.a; float alpha = v0.a;
float metalness = v2.r; float metalness = v2.r;
@@ -143,35 +314,79 @@ void main(void) {
float reflectivity = v2.b; float reflectivity = v2.b;
float NdotV = dot(normal, v); float NdotV = dot(normal, v);
float roughness3 = roughness*roughness*roughness; float roughness3 = roughness*roughness*roughness;
//bn = normalize(vec3(v3.w, v4.zw)); bn = normalize(cross(normal, vec3(1.,0.,0.)) + cross(normal, vec3(0.,1.,0.)));
//bn2 = normalize(cross(n, bn)); bn2 = normalize(cross(normal, bn));
bn = cross(normal, bn2);
rough_diff = max(roughness, _min_rough); rough_diff = max(roughness, _min_rough);
rough_spec = max(roughness3, _min_rough); rough_spec = max(roughness3, _min_rough);
float shlick = clamp(metalness + (1 - metalness) * pow(1 - NdotV, 5), 0, 1); float shlick = clamp(metalness + (1. - metalness) * pow(1. - NdotV, 5.), 0., 1.);
flags = uint(round(v2.w));
//qgl_FragColor.rgba = vec4(0);
li = vec3(0.);//qgl_AmbientLight.color.rgb * qgl_AmbientLight.intensity; li = vec3(0.);//qgl_AmbientLight.color.rgb * qgl_AmbientLight.intensity;
si = vec3(0.); si = vec3(0.);
for (int i = 0; i < lights_count; ++i) if (bitfieldExtract(flags, 0, 1) == 1) {
calcLight(lights_start + i, normal, v); for (int i = 0; i < lights_count; ++i)
calcLight(lights_start + i, normal, v);
} else {
li = vec3(1.);
}
si *= shlick; si *= shlick;
li *= (1 - shlick); li *= (1. - shlick);
alpha = min(1, alpha * (1 + shlick)); alpha = min(1., alpha * (1. + shlick));
vec2 brdf = texture(tex_coeffs[0], vec2(NdotV*0.99, roughness*0.995)).rg; vec2 brdf = texture(tex_coeff_brdf, vec2(NdotV*0.99, roughness*0.995)).rg;
float env_spec = shlick * brdf.x + brdf.y; float env_spec = shlick * brdf.x + brdf.y;
vec3 spec_col = mix(vec3(1), diffuse, metalness); vec3 spec_col = mix(vec3(1.), diffuse, metalness);
vec3 env_dir = view_mat * reflect(-v, normal); vec3 env_dir = view_mat * reflect(-v, normal);
vec3 env_col = textureLod(tex_env, env_dir, sqrt(roughness) * max_lod).rgb * spec_col; vec3 env_col = textureLod(tex_env, env_dir, sqrt(roughness) * max_lod).rgb * spec_col;
vec3 res_col = max(vec3(0), li * diffuse + si * spec_col + emission); vec3 res_col = max(vec3(0.), li * diffuse + si * spec_col + emission);
res_col = mix(res_col, env_col, env_spec * reflectivity); res_col = mix(res_col, env_col, env_spec * reflectivity);
float plen = length(pos.xyz); if (bitfieldExtract(flags, 1, 1) == 1) {
float fog = 1 - exp(-plen / fog_decay); float plen = length(pos.xyz);
fog = clamp(fog * fog_color.a * fog_density, 0, 1); float fog = 1. - exp(-plen / fog_decay);
res_col = mix(res_col, fog_color.rgb, fog); fog = clamp(fog * fog_color.a * fog_density, 0., 1.);
res_col = mix(res_col, fog_color.rgb, fog);
}
qgl_FragColor = vec4(res_col, alpha); qgl_FragColor = vec4(res_col, alpha);
//qgl_FragColor = vec4(diffuse.rgb, 0.25);
//qgl_FragColor.a = alpha;
//qgl_FragColor.rgb = vec3(geom_normal.rgb);
//qgl_FragColor.rgba = vec4(vec3(0), 0.5);
#ifdef SPOT
//vec4 shp = mapScreenToShadow(0, vec3(0));
//shp.xy /= shp.w;
//float depth = texture(tex_depths_cone, vec3(shp.xy, 0)).r;
////depth = 1 / (1 - depth) - 1 + z_near;
//float dz = max(0, shp.z - depth);
//shp.z -= bias;
//for (int xi = -2; xi <= 2; ++xi) {
// for (int yi = -2; yi <= 2; ++yi) {
//qgl_FragColor.rgb = vec3(step(shp.z, texture(tex_shadows_cone, vec3(shp.xy, 0)).r));
//qgl_FragColor.r = texture(tex_shadows_cone, vec3(0)).r;
//qgl_FragColor.rgb = vec3(abs(depth) + 1);
//float _d = texture(tex_depths_cone, vec3(shp.xy, 0)).r;
//_d = 1 / (1 - _d) - 1 + z_near;
//qgl_FragColor.rgb = vec3(texelFetch(tex_noise, tc % noise_size, 0).b);//vec4(res_col, alpha);
//shp.z += 0.095;
//qgl_FragColor.rgb = vec3(texture(tex_sh, shp.xy).rgb);
//qgl_FragColor.rgb = vec3(textureProj(tex_shadow[0], shp));
//vec4 rp = qgl_ViewProjMatrix*vec4(qgl_FragTexture.xy,z,1);
//qgl_FragColor.rgb = vec3(texture(tex_shadows_cone, vec3(gl_FragCoord.xy/1000, 0)).r);
#else
//vec3 odir = -(view_mat * ldir);
//float otex = texture(tex_shadows_omni, vec4(odir, 0), 0.8);
//qgl_FragColor.rgb = vec3(otex);
//qgl_FragColor.rgb = vec3(ldist/50);
//qgl_FragColor.rgb = vec3(abs(otex - ldist) * 1.);
//qgl_FragColor.rgb = vec3(tan((1-abs(dot(view_mat*normal, odir)))));
#endif
//vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y);
//qgl_FragColor.rgb = vec3(shlick * brdf.x + brdf.y); //qgl_FragColor.rgb = vec3(shlick * brdf.x + brdf.y);

View File

@@ -19,7 +19,7 @@ void main(void) {
float l = dot(res, luma) * 0.75; float l = dot(res, luma) * 0.75;
float g = gamma / frame_max; float g = gamma / frame_max;
res /= l; res /= l;
l = 1 - exp(-l*g); l = 1. - exp(-l*g);
res *= l; res = max(vec3(0.), res * l);
qgl_FragColor = vec4(res, dot(res, luma)); qgl_FragColor = vec4(res, dot(res, luma));
} }

50
shaders/shadow.glsl Normal file
View File

@@ -0,0 +1,50 @@
// vert //
flat out uint object_flags;
out float distance;
out vec4 pos;
const vec3 luma = vec3(0.299, 0.587, 0.114);
void main(void) {
object_flags = qgl_ObjectFlags;
if (bitfieldExtract(object_flags, 2, 1) == 0)
return;
qgl_MaterialIndex = qgl_Material;
qgl_FragTexture = qgl_getFragTexture();
float height = dot(qgl_materialTexture(QGL_MAP_RELIEF, qgl_FragTexture, vec4(0.)).rgb, luma);
pos = qgl_ViewProjMatrix * (qgl_ModelMatrix * (vec4(qgl_Vertex + qgl_Normal * height, 1.)));//qgl_ftransform();
gl_Position = pos;
}
// frag //
flat in uint object_flags;
in float distance;
in vec4 pos;
float z_near = 0.1f;
const float _pe = 2.4e-7;
void main(void) {
if (bitfieldExtract(object_flags, 2, 1) == 0)
discard;
vec4 diffuse = qgl_materialTexture(QGL_MAP_DIFFUSE, qgl_FragTexture.xy, vec4(0.f));
if(diffuse.a < 0.5f)
discard;
//float z = gl_FragCoord.z;
//z = z + z - 1;
//z = ((_pe - 2.) * z_near) / (z + z + _pe - 2.); // infinite depth
#ifdef OMNI
float z = length(pos.xyz);
#else
float z = pos.z;
#endif
z = 1.f - 1.f / (z - z_near + 1.f);
gl_FragDepth = z;
qgl_FragData[0].r = z;
//qgl_FragData[0].r = length(vec3(pos.xy, z));//1/gl_FragCoord.w;
}

9
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,9 @@
#if (NOT DEFINED ANDROID_PLATFORM)
# if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin")
# #add_subdirectory(plugin)
# endif()
#endif()
foreach (_d "core" "widgets" "qglview_test") # "plugin")
add_subdirectory("${_d}")
endforeach()
shstk_copy_to_parent()

36
src/core/CMakeLists.txt Normal file
View File

@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.0)
project(qglengine_core)
if (POLICY CMP0017)
cmake_policy(SET CMP0017 NEW)
endif()
qad_find_qt(Core Gui OpenGL OpenGLWidgets Xml)
find_package(OpenGL REQUIRED)
qad_sources(SRC)
set(_includes "${_qglengine_root_build}")
foreach (_d "formats" "core" "scene" "render" "view")
qad_sources(FSRC DIR "${_d}")
list(APPEND SRC ${FSRC})
list(APPEND _includes "${CMAKE_CURRENT_SOURCE_DIR}/${_d}")
endforeach()
qad_wrap(${SRC} HDRS out_HDR CPPS out_CPP QMS out_QM)
file(GLOB PHS "*_p.h")
list(REMOVE_ITEM out_HDR "${PHS}")
import_version(${PROJECT_NAME} QGLEngine)
set_deploy_property(${PROJECT_NAME} ${QGLEngine_LIB_TYPE}
LABEL "QGLEngine core library"
FULLNAME "${QGLEngine_DOMAIN}.qglengine_core"
COMPANY "${QGLEngine_COMPANY}"
INFO "QGLEngine core library")
make_rc(${PROJECT_NAME} _RC)
pip_code_model(CCM "render/renderer.h" OPTIONS "-DQGLENGINE_CORE_EXPORT" "-Es")
qad_add_library(${PROJECT_NAME} ${QGLEngine_LIB_TYPE} out_CPP ${_RC} ${CCM})
qad_generate_export_header(${PROJECT_NAME})
list(APPEND out_HDR "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_export.h")
qad_target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" ${_includes})
qad_target_link_libraries(${PROJECT_NAME} QAD::Widgets QAD::PIQtUtils assimp ${OPENGL_LIBRARIES})
message(STATUS "Building QGLEngine version ${QGLEngine_VERSION} (${QGLEngine_LIB_TYPE_MSG}) for ${QtVersions}")
list(APPEND QT_MULTILIB_LIST ${PROJECT_NAME})
shstk_copy_to_parent()
#message(STATUS "Building ${PROJECT_NAME}")
shstk_qad_install("qglengine" FALSE "${PROJECT_NAME}" "${out_HDR}" "out_QM")

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

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

58
src/core/core/glbuffer.h Normal file
View File

@@ -0,0 +1,58 @@
/*
QGL Buffer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 QGLENGINE_CORE_EXPORT Buffer {
friend class ObjectBase;
public:
Buffer(GLenum target, GLenum usage = GL_DYNAMIC_DRAW);
~Buffer();
void init(QOpenGLExtraFunctions * f);
void destroy(QOpenGLExtraFunctions * f);
void reinit();
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_; }
GLenum target() const { return target_; }
void setTarget(GLenum t) { target_ = t; }
bool isInit() const { return buffer_ != 0; }
private:
GLenum target_, usage_;
GLuint buffer_;
int prev_size;
};
#endif // GLBUFFER_H

View File

@@ -1,23 +1,24 @@
/* /*
QGL CubeTexture QGL CubeTexture
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "gltypes.h"
#include "glcubemap.h" #include "glcubemap.h"
#include "gltypes.h"
#include "hdr_p.h" #include "hdr_p.h"
using namespace QGLEngineShaders; using namespace QGLEngineShaders;
@@ -51,9 +52,9 @@ QVector<QVector3D> loadFileHDR(const QString & path, QSize * size) {
qDebug() << "[QGLEngine] File" << path << "has unknown size!"; qDebug() << "[QGLEngine] File" << path << "has unknown size!";
return ret; return ret;
} }
sz.setWidth (sl[3].toInt()); sz.setWidth(sl[3].toInt());
sz.setHeight(sl[1].toInt()); sz.setHeight(sl[1].toInt());
//qDebug() << "found size" << sz; // qDebug() << "found size" << sz;
break; break;
} }
} }
@@ -61,26 +62,23 @@ QVector<QVector3D> loadFileHDR(const QString & path, QSize * size) {
f.seek(ts.pos()); f.seek(ts.pos());
QDataStream ds(&f); QDataStream ds(&f);
int count = sz.width() * sz.height(); int count = sz.width() * sz.height();
QVector<float> data(count*3); QVector<float> data(count * 3);
if (!RGBE_ReadPixels_RLE(&ds, data.data(), sz.width(), sz.height())) if (!RGBE_ReadPixels_RLE(&ds, data.data(), sz.width(), sz.height())) return ret;
return ret;
if (size) *size = sz; if (size) *size = sz;
ret.resize(count); ret.resize(count);
//QColor col; // QColor col;
//QImage im(sz, QImage::Format_ARGB32); // QImage im(sz, QImage::Format_ARGB32);
//QRgb * imdata = (QRgb*)im.bits(); // QRgb * imdata = (QRgb*)im.bits();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
QVector3D p(pow(data[i*3 + 2], 1. / 2.2), QVector3D p(pow(data[i * 3 + 2], 1. / 2.2), pow(data[i * 3 + 1], 1. / 2.2), pow(data[i * 3 + 0], 1. / 2.2));
pow(data[i*3 + 1], 1. / 2.2),
pow(data[i*3 + 0], 1. / 2.2));
ret[i] = p; ret[i] = p;
//col = QColor::fromRgbF(piClamp(p[0], 0.f, 1.f), // col = QColor::fromRgbF(piClamp(p[0], 0.f, 1.f),
// piClamp(p[1], 0.f, 1.f), // piClamp(p[1], 0.f, 1.f),
// piClamp(p[2], 0.f, 1.f)); // piClamp(p[2], 0.f, 1.f));
//imdata[i] = col.rgb(); // imdata[i] = col.rgb();
} }
//im.save("_hdr.png"); // im.save("_hdr.png");
return ret; return ret;
} }
@@ -90,72 +88,71 @@ QVector<QVector3D> faceHDR(const QVector<QVector3D> & data, QSize sz, QSize & fs
QVector<QVector3D> ret; QVector<QVector3D> ret;
if (data.isEmpty() || sz.isNull()) return ret; if (data.isEmpty() || sz.isNull()) return ret;
QRect fr; QRect fr;
int fw = sz.width () / 4; int fw = sz.width() / 4;
int fh = sz.height() / 3; int fh = sz.height() / 3;
fsz = QSize(fw, fh); fsz = QSize(fw, fh);
ret.reserve(fw * fh); ret.reserve(fw * fh);
switch (face) { switch (face) {
case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
fr.setRect(fw, fh, fw, fh); fr.setRect(fw, fh, fw, fh);
for (int x = fr.left(); x <= fr.right(); ++x) { for (int x = fr.left(); x <= fr.right(); ++x) {
for (int y = fr.top(); y <= fr.bottom(); ++y) { for (int y = fr.top(); y <= fr.bottom(); ++y) {
ret << data[y*sz.width() + x]; ret << data[y * sz.width() + x];
} }
} }
break; break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
fr.setRect(fw*3, fh, fw, fh); fr.setRect(fw * 3, fh, fw, fh);
for (int x = fr.right(); x >= fr.left(); --x) { for (int x = fr.right(); x >= fr.left(); --x) {
for (int y = fr.bottom(); y >= fr.top(); --y) { for (int y = fr.bottom(); y >= fr.top(); --y) {
ret << data[y*sz.width() + x]; ret << data[y * sz.width() + x];
} }
} }
break; break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
fr.setRect( 0, fh, fw, fh); fr.setRect(0, fh, fw, fh);
for (int y = fr.bottom(); y >= fr.top(); --y) { for (int y = fr.bottom(); y >= fr.top(); --y) {
for (int x = fr.left(); x <= fr.right(); ++x) { for (int x = fr.left(); x <= fr.right(); ++x) {
ret << data[y*sz.width() + x]; ret << data[y * sz.width() + x];
} }
} }
break; break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
fr.setRect(fw*2, fh, fw, fh); fr.setRect(fw * 2, fh, fw, fh);
for (int y = fr.top(); y <= fr.bottom(); ++y) { for (int y = fr.top(); y <= fr.bottom(); ++y) {
for (int x = fr.right(); x >= fr.left(); --x) { for (int x = fr.right(); x >= fr.left(); --x) {
ret << data[y*sz.width() + x]; ret << data[y * sz.width() + x];
} }
} }
break; break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
fr.setRect(fw, 0, fw, fh); fr.setRect(fw, 0, fw, fh);
for (int x = fr.left(); x <= fr.right(); ++x) { for (int x = fr.left(); x <= fr.right(); ++x) {
for (int y = fr.top(); y <= fr.bottom(); ++y) { for (int y = fr.top(); y <= fr.bottom(); ++y) {
ret << data[y*sz.width() + x]; ret << data[y * sz.width() + x];
} }
} }
break; break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
fr.setRect(fw, fh*2, fw, fh); fr.setRect(fw, fh * 2, fw, fh);
for (int x = fr.left(); x <= fr.right(); ++x) { for (int x = fr.left(); x <= fr.right(); ++x) {
for (int y = fr.top(); y <= fr.bottom(); ++y) { for (int y = fr.top(); y <= fr.bottom(); ++y) {
ret << data[y*sz.width() + x]; ret << data[y * sz.width() + x];
} }
} }
break; break;
default: break; default: break;
} }
if (fr.isEmpty()) return ret; if (fr.isEmpty()) return ret;
//qDebug() << ret.size() << fr; // qDebug() << ret.size() << fr;
return ret; return ret;
} }
CubeTexture::CubeTexture(QOpenGLExtraFunctions * f_, int _size, const GLenum & _format): f(f_) { CubeTexture::CubeTexture(QOpenGLExtraFunctions * f_, int _size, const GLenum & _format): f(f_) {
size = _size; size = _size;
format_ = _format; format_ = _format;
id_ = 0; id_ = 0;
changed_ = false; changed_ = false;
} }
@@ -199,9 +196,17 @@ void CubeTexture::loadHDR(const QVector<QVector3D> & data, QSize sz) {
QVector<QVector3D> fd; QVector<QVector3D> fd;
for (int i = 0; i < 6; ++i) { for (int i = 0; i < 6; ++i) {
fd = faceHDR(data, sz, fsz, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i); fd = faceHDR(data, sz, fsz, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i);
//qDebug() << "load cube" << fd[0]; // qDebug() << "load cube" << fd[0];
f->glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format_, fsz.width(), fsz.height(), 0, GL_RGB, GL_FLOAT, fd.isEmpty() ? 0 : fd.constData()); f->glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
//qDebug() << QString::number(GetLastError(), 16); 0,
format_,
fsz.width(),
fsz.height(),
0,
GL_RGB,
GL_FLOAT,
fd.isEmpty() ? 0 : fd.constData());
// qDebug() << QString::number(GetLastError(), 16);
} }
f->glGenerateMipmap(GL_TEXTURE_CUBE_MAP); f->glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
} }
@@ -230,4 +235,3 @@ void CubeTexture::load() {
} }
changed_ = false; changed_ = false;
} }

60
src/core/core/glcubemap.h Normal file
View File

@@ -0,0 +1,60 @@
/*
QGL CubeTexture
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLCUBEMAP_H
#define GLCUBEMAP_H
#include "chunkstream.h"
#include "glshaders_types.h"
QVector<QVector3D> QGLENGINE_CORE_EXPORT loadFileHDR(const QString & path, QSize * size = 0);
class QGLENGINE_CORE_EXPORT CubeTexture {
public:
CubeTexture(QOpenGLExtraFunctions * f_, int _size, const GLenum & _format = GL_RGB16F);
bool init();
void destroy();
void bind(int channel = 0);
void release();
void resize(int _size) {
size = _size;
changed_ = true;
}
void loadHDR(const QVector<QVector3D> & data, QSize sz);
void setFileHDR(const QString & path);
QString fileHDR() const { return hdr_path; }
GLenum format() const { return format_; }
void setFormat(GLenum f) {
format_ = f;
changed_ = true;
}
GLuint id() const { return id_; }
bool isInit() const { return id_ != 0; }
void load();
private:
QOpenGLExtraFunctions * f;
bool changed_;
int size;
GLenum format_;
GLuint id_;
QString hdr_path;
};
#endif // GLCUBEMAP_H

View File

@@ -0,0 +1,108 @@
/*
QGL CubeMapArray
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include "glcubemaparray.h"
#include <QOpenGLExtraFunctions>
CubeMapArray::CubeMapArray(GLenum format, bool filter) {
target_ = GL_TEXTURE_CUBE_MAP_ARRAY;
format_ = format;
texture_ = 0;
layers_ = 0;
filtering_ = filter;
}
CubeMapArray::~CubeMapArray() {}
void CubeMapArray::init(QOpenGLExtraFunctions * f) {
if (!isInit()) {
f->glGenTextures(1, &texture_);
}
}
void CubeMapArray::destroy(QOpenGLExtraFunctions * f) {
if (texture_ != 0) {
f->glDeleteTextures(1, &texture_);
}
texture_ = 0;
}
void CubeMapArray::reinit() {
texture_ = 0;
layers_ = 0;
}
void CubeMapArray::bind(QOpenGLExtraFunctions * f, int channel) {
f->glActiveTexture(GL_TEXTURE0 + channel);
f->glBindTexture(target_, texture_);
}
void CubeMapArray::release(QOpenGLExtraFunctions * f) {
f->glBindTexture(target_, 0);
}
bool CubeMapArray::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);
}
GLenum bformat = format_;
GLenum btype = GL_UNSIGNED_BYTE;
if (format_ == GL_R16F || format_ == GL_R32F) {
bformat = GL_RED;
btype = GL_FLOAT;
}
f->glTexImage3D(target_, 0, format_, size_.width(), size_.height(), layers_ * 6, 0, bformat, btype, nullptr);
return true;
}
void CubeMapArray::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() << "CubeMapArray::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 CubeMapArray::mipmaps(QOpenGLExtraFunctions * f) {
f->glBindTexture(target_, texture_);
f->glGenerateMipmap(target_);
}

View File

@@ -0,0 +1,55 @@
/*
QGL Texture2DArray
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLCUBEMAPARRAY_H
#define GLCUBEMAPARRAY_H
#include "gltypes.h"
class QGLENGINE_CORE_EXPORT CubeMapArray {
public:
CubeMapArray(GLenum format, bool filter);
~CubeMapArray();
void init(QOpenGLExtraFunctions * f);
void destroy(QOpenGLExtraFunctions * f);
void reinit();
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; }
int layersCount() const { return layers_; }
private:
GLenum target_, format_;
GLuint texture_;
QSize size_;
int layers_;
bool filtering_;
};
#endif // GLCUBEMAPARRAY_H

View File

@@ -1,56 +1,59 @@
/* /*
QGL Framebuffer QGL Framebuffer
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <QOpenGLExtraFunctions>
#include "glframebuffer.h" #include "glframebuffer.h"
#include <QOpenGLExtraFunctions>
#include <QTime> #include <QTime>
Framebuffer::Framebuffer(QOpenGLExtraFunctions * f_, int colorAttachments_, bool withDepth, GLenum colorFormat_, GLenum _target) Framebuffer::Framebuffer(QOpenGLExtraFunctions * f_, int colorAttachments_, bool withDepth, GLenum colorFormat_, GLenum _target)
: f(f_), pbo(GL_PIXEL_PACK_BUFFER, GL_STREAM_DRAW) { : f(f_)
, pbo(GL_PIXEL_PACK_BUFFER, GL_STREAM_DRAW) {
is_depth = withDepth; is_depth = withDepth;
target_ = _target; target_ = _target;
color_formats.fill(colorFormat_, colorAttachments_); color_formats.fill(colorFormat_, colorAttachments_);
colors.fill(0, colorAttachments_); colors.fill(0, colorAttachments_);
fbo = drbo = 0; fbo = drbo = 0;
tex_d = 0; tex_d = 0;
wid = hei = 0; wid = hei = 0;
pbo_queried = 0; pbo_queried = 0;
is_changed = false; is_changed = false;
} }
Framebuffer::Framebuffer(QOpenGLExtraFunctions * f_, QVector<GLenum> colors_, bool withDepth, GLenum _target) Framebuffer::Framebuffer(QOpenGLExtraFunctions * f_, QVector<GLenum> colors_, bool withDepth, GLenum _target)
: f(f_), pbo(GL_PIXEL_PACK_BUFFER, GL_STREAM_DRAW) { : f(f_)
is_depth = withDepth; , pbo(GL_PIXEL_PACK_BUFFER, GL_STREAM_DRAW) {
target_ = _target; is_depth = withDepth;
target_ = _target;
color_formats = colors_; color_formats = colors_;
colors.fill(0, colors_.size()); colors.fill(0, colors_.size());
fbo = drbo = 0; fbo = drbo = 0;
tex_d = 0; tex_d = 0;
wid = hei = 0; wid = hei = 0;
pbo_queried = 0; pbo_queried = 0;
is_changed = false; is_changed = false;
} }
Framebuffer::~Framebuffer() { Framebuffer::~Framebuffer() {
deleteGLFramebuffer(fbo); if (fbo > 0) deleteGLFramebuffer(fbo);
deleteGLRenderbuffer(drbo); deleteGLRenderbuffer(drbo);
for (int i = 0; i < colors.size(); ++i) for (int i = 0; i < colors.size(); ++i)
deleteGLTexture(f, colors[i]); deleteGLTexture(f, colors[i]);
@@ -59,12 +62,15 @@ Framebuffer::~Framebuffer() {
void Framebuffer::resize(int width, int height, bool force) { void Framebuffer::resize(int width, int height, bool force) {
if ((wid == width) && (hei == height) && !force) return; if (fbo > 0) {
if ((wid == width) && (hei == height) && !force) return;
}
wid = width; wid = width;
hei = height; hei = height;
deleteGLFramebuffer(fbo); if (fbo > 0) deleteGLFramebuffer(fbo);
f->glGenFramebuffers(1, &fbo); f->glGenFramebuffers(1, &fbo);
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo); f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// qDebug() << "resize" << f << wid << hei << fbo << colors.size();
for (int i = 0; i < colors.size(); ++i) { for (int i = 0; i < colors.size(); ++i) {
deleteGLTexture(f, colors[i]); deleteGLTexture(f, colors[i]);
createGLTexture(f, colors[i], width, height, color_formats[i], target_); createGLTexture(f, colors[i], width, height, color_formats[i], target_);
@@ -77,7 +83,7 @@ void Framebuffer::resize(int width, int height, bool force) {
} }
if (is_depth) { if (is_depth) {
deleteGLTexture(f, tex_d); deleteGLTexture(f, tex_d);
deleteGLRenderbuffer(drbo); if (drbo > 0) deleteGLRenderbuffer(drbo);
f->glGenRenderbuffers(1, &drbo); f->glGenRenderbuffers(1, &drbo);
f->glBindRenderbuffer(GL_RENDERBUFFER, drbo); f->glBindRenderbuffer(GL_RENDERBUFFER, drbo);
f->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); f->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
@@ -88,6 +94,7 @@ void Framebuffer::resize(int width, int height, bool force) {
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 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_WRAP_T, GL_CLAMP_TO_EDGE);
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target_, tex_d, 0); f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target_, tex_d, 0);
// f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target_, tex_d, 0);
} }
f->glBindFramebuffer(GL_FRAMEBUFFER, 0); f->glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (pbo.isInit()) { if (pbo.isInit()) {
@@ -97,6 +104,17 @@ void Framebuffer::resize(int width, int height, bool force) {
} }
void Framebuffer::reinit(QOpenGLExtraFunctions * f_) {
if (f_) f = f_;
pbo.reinit();
colors.fill(0);
fbo = drbo = 0;
tex_d = 0;
pbo_queried = 0;
is_changed = true;
}
QImage Framebuffer::grab() const { QImage Framebuffer::grab() const {
return QImage(); return QImage();
} }
@@ -139,8 +157,7 @@ uint Framebuffer::getPoint() const {
uint ret = 0; uint ret = 0;
pbo.bind(f); pbo.bind(f);
void * map = pbo.map(f, GL_MAP_READ_BIT, sizeof(uint)); void * map = pbo.map(f, GL_MAP_READ_BIT, sizeof(uint));
if (map) if (map) memcpy(&ret, map, sizeof(uint));
memcpy(&ret, map, sizeof(uint));
pbo.unmap(f); pbo.unmap(f);
pbo.release(f); pbo.release(f);
return ret; return ret;
@@ -153,8 +170,7 @@ QVector<uint> Framebuffer::getPointsByte() const {
ret.resize(pbo_queried); ret.resize(pbo_queried);
pbo.bind(f); pbo.bind(f);
void * map = pbo.map(f, GL_MAP_READ_BIT, pbo_queried * sizeof(uint)); void * map = pbo.map(f, GL_MAP_READ_BIT, pbo_queried * sizeof(uint));
if (map) if (map) memcpy(ret.data(), map, pbo_queried * sizeof(uint));
memcpy(ret.data(), map, pbo_queried * sizeof(uint));
pbo.unmap(f); pbo.unmap(f);
pbo.release(f); pbo.release(f);
return ret; return ret;
@@ -167,8 +183,7 @@ QVector<QVector4D> Framebuffer::getPointsFloat() const {
ret.resize(pbo_queried); ret.resize(pbo_queried);
pbo.bind(f); pbo.bind(f);
void * map = pbo.map(f, GL_MAP_READ_BIT, pbo_queried * sizeof(QVector4D)); void * map = pbo.map(f, GL_MAP_READ_BIT, pbo_queried * sizeof(QVector4D));
if (map) if (map) memcpy(ret.data(), map, pbo_queried * sizeof(QVector4D));
memcpy(ret.data(), map, pbo_queried * sizeof(QVector4D));
pbo.unmap(f); pbo.unmap(f);
pbo.release(f); pbo.release(f);
return ret; return ret;
@@ -178,12 +193,11 @@ QVector<QVector4D> Framebuffer::getPointsFloat() const {
QImage Framebuffer::getImage() const { QImage Framebuffer::getImage() const {
QImage ret; QImage ret;
if (!pbo.isInit() || (pbo_queried == 0)) return ret; if (!pbo.isInit() || (pbo_queried == 0)) return ret;
ret = QImage(size(), QImage::Format_RGBA8888); ret = QImage(size(), QImage::Format_RGBA8888);
int bytes = width() * height() * 4; int bytes = width() * height() * 4;
pbo.bind(f); pbo.bind(f);
void * map = pbo.map(f, GL_MAP_READ_BIT, bytes); void * map = pbo.map(f, GL_MAP_READ_BIT, bytes);
if (map) if (map) memcpy(ret.bits(), map, bytes);
memcpy(ret.bits(), map, bytes);
pbo.unmap(f); pbo.unmap(f);
pbo.release(f); pbo.release(f);
return ret; return ret;
@@ -264,7 +278,7 @@ void Framebuffer::unsetWriteBuffers() {
void Framebuffer::enablePixelBuffer() { void Framebuffer::enablePixelBuffer() {
pbo.init(f); pbo.init(f);
pbo.bind(f); pbo.bind(f);
pbo.resize(f, width()*height()*4*4); pbo.resize(f, width() * height() * 4 * 4);
pbo.release(f); pbo.release(f);
} }
@@ -283,6 +297,14 @@ void Framebuffer::bindColorTexture(int index, int channel) {
} }
void Framebuffer::bindColorTextures(const QVector<int> & indeces) {
for (int i = indeces.size() - 1; i >= 0; --i) {
f->glActiveTexture(GL_TEXTURE0 + i);
f->glBindTexture(GL_TEXTURE_2D, colors[indeces[i]]);
}
}
void Framebuffer::bindColorTextures() { void Framebuffer::bindColorTextures() {
for (int i = colors.size() - 1; i >= 0; --i) { for (int i = colors.size() - 1; i >= 0; --i) {
f->glActiveTexture(GL_TEXTURE0 + i); f->glActiveTexture(GL_TEXTURE0 + i);
@@ -298,14 +320,12 @@ void Framebuffer::bindDepthTexture(int channel) {
void Framebuffer::deleteGLRenderbuffer(GLuint & drbo) { void Framebuffer::deleteGLRenderbuffer(GLuint & drbo) {
if (drbo != 0) if (drbo != 0) f->glDeleteRenderbuffers(1, &drbo);
f->glDeleteRenderbuffers(1, &drbo);
drbo = 0; drbo = 0;
} }
void Framebuffer::deleteGLFramebuffer(GLuint & fbo) { void Framebuffer::deleteGLFramebuffer(GLuint & fbo) {
if (fbo != 0) if (fbo != 0) f->glDeleteFramebuffers(1, &fbo);
f->glDeleteFramebuffers(1, &fbo);
fbo = 0; fbo = 0;
} }

View File

@@ -0,0 +1,99 @@
/*
QGL Framebuffer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 QGLENGINE_CORE_EXPORT Framebuffer {
friend class FramebufferMipmap;
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]; }
GLuint depthTexture() const { return tex_d; }
GLenum target() const { return target_; }
bool isInit() const { return fbo != 0; }
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, GLenum pixel_format = GL_UNSIGNED_BYTE);
void queryImage(int index);
uint getPoint() const;
QVector<uint> getPointsByte() const;
QVector<QVector4D> getPointsFloat() 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) const;
void resize(QSize sz, bool force = false) { resize(sz.width(), sz.height(), force); }
void resize(int width, int height, bool force = false);
void reinit(QOpenGLExtraFunctions * f_ = nullptr);
void bind();
void release();
void setReadBuffer(int index) { glReadBuffer(GL_COLOR_ATTACHMENT0 + index); }
void setWriteBuffer(int index);
void setWriteBuffers(const int * indeces, int count);
void setWriteBuffers(const QVector<int> & indeces) { setWriteBuffers(indeces.constData(), indeces.size()); }
void setWriteBuffers();
void unsetWriteBuffers();
void enablePixelBuffer();
void setColorTextureFiltering(int index, GLenum filter);
void copyDepthFrom(GLuint tex) { ; }
void bindColorTexture(int index, int channel = 0);
void bindColorTextures(const QVector<int> & indeces);
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

View File

@@ -0,0 +1,60 @@
/*
QGL FramebufferMipmap
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "glframebuffer_mipmap.h"
#include <QOpenGLExtraFunctions>
#include <QTime>
FramebufferMipmap::FramebufferMipmap(const Framebuffer & fb, int index_from_, int levels): src_fb(fb) {
index_from = index_from_;
for (int i = 0; i < levels; ++i)
fbo << new Framebuffer(fb.f, 1, false, fb.color_formats[index_from]);
}
FramebufferMipmap::~FramebufferMipmap() {}
void FramebufferMipmap::setIndexFrom(int index) {
index_from = index;
}
void FramebufferMipmap::resize() {
QSize sz = src_fb.size();
for (int i = 0; i < fbo.size(); ++i) {
sz /= 2;
fbo[i]->resize(sz.width(), sz.height());
}
}
void FramebufferMipmap::create() {
if (fbo.isEmpty()) return;
src_fb.blit(index_from, fbo[0]->id(), 0, src_fb.rect(), fbo[0]->rect(), GL_COLOR_BUFFER_BIT, GL_LINEAR);
for (int i = 0; i < fbo.size() - 1; ++i)
fbo[i]->blit(0, fbo[i + 1]->id(), 0, fbo[i]->rect(), fbo[i + 1]->rect(), GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
void FramebufferMipmap::reinit() {
for (auto * f: fbo)
f->reinit();
}

View File

@@ -0,0 +1,50 @@
/*
QGL FramebufferMipmap
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLFRAMEBUFFER_MIPMAP_H
#define GLFRAMEBUFFER_MIPMAP_H
#include "glframebuffer.h"
class QGLENGINE_CORE_EXPORT FramebufferMipmap {
public:
FramebufferMipmap(const Framebuffer & fb, int index_from_, int levels = 2);
virtual ~FramebufferMipmap();
int levelsCount() const { return fbo.size(); }
int lastLevel() const { return fbo.size() - 1; }
Framebuffer & plane(int level) { return *fbo[level]; }
Framebuffer & lastPlane() { return *fbo[lastLevel()]; }
int width(int level) const { return fbo[level]->wid; }
int height(int level) const { return fbo[level]->hei; }
QSize size(int level) const { return fbo[level]->size(); }
QRect rect(int level) const { return fbo[level]->rect(); }
void setIndexFrom(int index);
void resize();
void create();
void reinit();
private:
int index_from;
const Framebuffer & src_fb;
QVector<Framebuffer *> fbo;
};
#endif // GLFRAMEBUFFER_MIPMAP_H

View File

@@ -0,0 +1,145 @@
/*
QGL Framebuffer effect basic
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "glframebuffereffectbase.h"
#include "renderer.h"
#include <QTime>
FramebufferEffectBase::FramebufferEffectBase() {}
FramebufferEffectBase::~FramebufferEffectBase() {
/*if (fbo > 0) deleteGLFramebuffer(fbo);
deleteGLRenderbuffer(drbo);
for (int i = 0; i < colors.size(); ++i)
deleteGLTexture(f, colors[i]);
deleteGLTexture(f, tex_d);*/
}
void FramebufferEffectBase::resize(int width, int height, bool force) {
/*if (fbo > 0) {
if ((wid == width) && (hei == height) && !force) return;
}
wid = width;
hei = height;
if (fbo > 0) deleteGLFramebuffer(fbo);
f->glGenFramebuffers(1, &fbo);
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// qDebug() << "resize" << f << wid << hei << 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_LINEAR);
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, target_, colors[i], 0);
}
if (is_depth) {
deleteGLTexture(f, tex_d);
if (drbo > 0) 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->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target_, tex_d, 0);
}
f->glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (pbo.isInit()) {
enablePixelBuffer();
}
is_changed = false;*/
}
void FramebufferEffectBase::reinit() {
/*pbo.reinit();
colors.fill(0);
fbo = drbo = 0;
tex_d = 0;
pbo_queried = 0;
is_changed = true;*/
}
void FramebufferEffectBase::bindDeferredBuffer(int role, int channel) {
r->fbo_ds.bindColorTexture(role, channel);
}
void FramebufferEffectBase::bindDepthBuffer(int channel) {
r->fbo_ds.bindDepthTexture(channel);
}
void FramebufferEffectBase::bindPreviousOutput(int channel) {
r->fbo_out.bindColorTexture(r->prev_write_plane, channel);
}
void FramebufferEffectBase::setOutputPlane(int channel) {
r->fbo_out.setWriteBuffer(channel);
r->prev_write_plane = r->cur_write_plane;
r->cur_write_plane = channel;
}
void FramebufferEffectBase::drawScreen(QOpenGLShaderProgram * prog) {
r->renderQuad(prog, r->quad, nullptr);
}
void FramebufferEffectBase::drawInternal() {
if (!r) return;
draw();
}
void FramebufferEffectBase::reloadShadersInternal() {
if (!r) return;
if (is_loaded) return;
reloadShaders();
is_loaded = true;
}
QVector<int> FramebufferEffectBase::getFreePlanes(int count) {
return r->getFreePlanes(count);
}
int FramebufferEffectBase::previousOutputPlane() const {
return r->prev_write_plane;
}
void FramebufferEffectBase::deleteShader(QOpenGLShaderProgram *& s) {
if (!s) return;
delete s;
s = nullptr;
}

View File

@@ -0,0 +1,68 @@
/*
QGL Framebuffer effect basic
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef glframebuffereffectbase_H
#define glframebuffereffectbase_H
#include "gltypes.h"
#include "parameteredobject.h"
#include <QElapsedTimer>
class QGLENGINE_CORE_EXPORT FramebufferEffectBase: public ParameteredObject {
friend class FramebufferMipmap;
friend class Renderer;
public:
FramebufferEffectBase();
virtual ~FramebufferEffectBase();
virtual QString name() const = 0;
void setEnabled(bool on) { enabled_ = on; }
bool isEnabled() const { return enabled_; }
virtual void draw() = 0;
protected:
void resize(int width, int height, bool force = false);
void reinit();
virtual int maxPlanesUsed() const { return 1; }
virtual void reloadShaders() {}
void bindDeferredBuffer(int role, int channel);
void bindDepthBuffer(int channel);
void bindPreviousOutput(int channel);
void setOutputPlane(int channel);
void drawScreen(QOpenGLShaderProgram * prog);
void drawInternal();
void reloadShadersInternal();
QVector<int> getFreePlanes(int count);
int previousOutputPlane() const;
static void deleteShader(QOpenGLShaderProgram *& s);
private:
bool enabled_ = true;
bool is_loaded = false;
Renderer * r = nullptr;
GLint wid, hei;
};
#endif

View File

@@ -0,0 +1,179 @@
/*
QGL Material
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gltexture_manager.h"
using namespace QGLEngineShaders;
Map::Map() {
bitmap_id = 0;
color_amount = 1.f;
color_offset = 0.f;
bitmap_scale = QPointF(1., 1.);
use_bitmap = false;
_changed = true;
_layer = 0;
_bitmap_hash = 0;
}
void Map::setBitmapPath(const QString & p) {
bitmap_path = p;
_changed = true;
_bitmap_hash = 0;
}
void Map::load(TextureManager * tm) {
_bitmap_hash = 0;
if (!bitmap_path.isEmpty()) tm->loadTextureImage(bitmap_path, _type == mtNormal, bake_options, &_bitmap_hash);
_changed = false;
}
void Map::setMapLayer(TextureManager * tm) {
if (loadedBitmap())
_layer = tm->textureLayer(_bitmap_hash);
else
_layer = 0;
}
void Map::copyToQGLMap(QGLMap & m) const {
m.amount = color_amount;
m.offset = color_offset;
m.scale = QVector2D(bitmap_scale);
if (loadedBitmap() && use_bitmap) {
m.array_index = 1;
m.map_index = _layer;
} else {
m.array_index = 0;
m.map_index = emptyMapIndex(_type);
}
}
GLuint Map::emptyMapIndex(int type) {
switch (type) {
case mtNormal: return emrBlue;
case mtRelief: return emrBlack;
default: return emrWhite;
}
return 0;
}
Material::Material(const QString _name) {
setTypes();
name = _name;
color_diffuse = Qt::white;
color_emission = Qt::black;
glass = false;
transparency = reflectivity = 0.f;
map_roughness.color_amount = 0.75f;
map_metalness.color_amount = 0.25f;
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_metalness._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 mtMetalness: return map_metalness._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_metalness.load(tm);
map_roughness.load(tm);
map_emission.load(tm);
map_relief.load(tm);
}
void Material::setMapsLayers(TextureManager * tm) {
map_diffuse.setMapLayer(tm);
map_normal.setMapLayer(tm);
map_metalness.setMapLayer(tm);
map_roughness.setMapLayer(tm);
map_emission.setMapLayer(tm);
map_relief.setMapLayer(tm);
}
void Material::setMapsChanged() {
map_diffuse._changed = true;
map_normal._changed = true;
map_metalness._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_metalness._type = mtMetalness;
map_roughness._type = mtRoughness;
map_emission._type = mtEmission;
map_relief._type = mtRelief;
}
void Material::detectMaps() {
map_diffuse.use_bitmap = !map_diffuse.bitmap_path.isEmpty();
map_normal.use_bitmap = !map_normal.bitmap_path.isEmpty();
map_metalness.use_bitmap = !map_metalness.bitmap_path.isEmpty();
map_roughness.use_bitmap = !map_roughness.bitmap_path.isEmpty();
map_emission.use_bitmap = !map_emission.bitmap_path.isEmpty();
map_relief.use_bitmap = !map_relief.bitmap_path.isEmpty();
}
uint MapBakeOptions::hash() const {
return qHash((uint)invert_R + ((uint)invert_G << 1) + ((uint)invert_B << 2));
}

168
src/core/core/glmaterial.h Normal file
View File

@@ -0,0 +1,168 @@
/*
QGL Material
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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>
struct QGLENGINE_CORE_EXPORT MapBakeOptions {
uint hash() const;
bool invert_R = false;
bool invert_G = false;
bool invert_B = false;
};
class QGLENGINE_CORE_EXPORT Map {
public:
Map();
void setBitmapPath(const QString & p);
void clearBitmap() { setBitmapPath(QString()); }
bool hasBitmap() const { return !bitmap_path.isEmpty(); }
bool loadedBitmap() const { return _bitmap_hash != 0; }
void load(TextureManager * tm);
void setMapLayer(TextureManager * tm);
void copyToQGLMap(QGLEngineShaders::QGLMap & m) const;
static GLuint emptyMapIndex(int type);
QString bitmap_path;
GLuint bitmap_id;
QPointF bitmap_offset;
QPointF bitmap_scale;
float color_amount;
float color_offset;
bool use_bitmap;
MapBakeOptions bake_options;
bool _changed;
int _type, _layer;
uint _bitmap_hash;
};
class QGLENGINE_CORE_EXPORT 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 setMapsLayers(TextureManager * tm);
void setMapsChanged();
void setTypes();
void detectMaps();
QString name;
QColor color_diffuse;
QColor color_emission;
bool glass;
float transparency;
float reflectivity;
float iof;
float dispersion;
Map map_diffuse;
Map map_normal;
Map map_metalness;
Map map_roughness;
Map map_emission;
Map map_relief;
bool _changed;
int _index;
};
inline QDataStream & operator<<(QDataStream & s, const MapBakeOptions & m) {
ChunkStream cs;
cs.add(1, m.invert_R).add(2, m.invert_G).add(3, m.invert_B);
s << cs.data();
return s;
}
inline QDataStream & operator>>(QDataStream & s, MapBakeOptions & m) {
ChunkStream cs(s);
cs.readAll();
cs.get(1, m.invert_R).get(2, m.invert_G).get(3, m.invert_B);
return s;
}
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)
.add(7, m.use_bitmap)
.add(11, m.bake_options);
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)
.get(7, m.use_bitmap)
.get(11, m.bake_options);
return s;
}
inline QDataStream & operator<<(QDataStream & s, const Material * m) {
ChunkStream cs;
cs.add(1, m->name)
.add(2, m->color_diffuse)
.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_metalness)
.add(12, m->map_roughness)
.add(13, m->map_emission);
s << (cs.data());
return s;
}
inline QDataStream & operator>>(QDataStream & s, Material *& m) {
m = new Material();
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 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_metalness); break;
case 12: cs.get(m->map_roughness); break;
case 13: cs.get(m->map_emission); break;
}
}
m->setTypes();
return s;
}
#endif // GLMATERIAL_H

View File

@@ -1,56 +1,59 @@
/* /*
QGL Mesh QGL Mesh
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "glmesh.h" #include "glmesh.h"
#include "globject.h" #include "globject.h"
#include <QOpenGLExtraFunctions>
#include <QTime> #include <QTime>
using namespace QGLEngineShaders; using namespace QGLEngineShaders;
//static int _count = 0; // static int _count = 0;
Mesh::Mesh(GLenum geom_type_): geom_type(geom_type_), Mesh::Mesh(GLenum geom_type_)
buffer_geom(GL_ARRAY_BUFFER, GL_STATIC_DRAW), : geom_type(geom_type_)
buffer_ind (GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW) { , buffer_geom(GL_ARRAY_BUFFER, GL_STATIC_DRAW)
hash_ = 0; , buffer_ind(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW) {
hash_ = 0;
changed = hash_changed = true; changed = hash_changed = true;
//qDebug() << "Mesh, now" << ++_count; // qDebug() << "Mesh, now" << ++_count;
} }
Mesh::~Mesh() { Mesh::~Mesh() {
//qDebug() << "~Mesh, now" << --_count; // qDebug() << "~Mesh, now" << --_count;
} }
Mesh * Mesh::clone() { Mesh * Mesh::clone() {
Mesh * c = new Mesh(); Mesh * c = new Mesh();
c->vertices_ = vertices_ ; c->vertices_ = vertices_;
c->normals_ = normals_ ; c->normals_ = normals_;
c->texcoords_ = texcoords_; c->texcoords_ = texcoords_;
c->triangles_ = triangles_; c->triangles_ = triangles_;
c->lines_ = lines_; c->lines_ = lines_;
c->geom_type = geom_type; c->geom_type = geom_type;
c->hash_ = hash_; c->hash_ = hash_;
c->hash_changed = hash_changed; c->hash_changed = hash_changed;
//qDebug() << "clone VBO"; // qDebug() << "clone VBO";
return c; return c;
} }
@@ -58,17 +61,27 @@ Mesh * Mesh::clone() {
void Mesh::init(QOpenGLExtraFunctions * f) { void Mesh::init(QOpenGLExtraFunctions * f) {
if (!isInit()) { if (!isInit()) {
buffer_geom.init(f); buffer_geom.init(f);
buffer_ind .init(f); buffer_ind.init(f);
changed = true; changed = true;
} }
} }
void Mesh::reinit() {
buffer_geom.reinit();
buffer_ind.reinit();
QMapIterator<int, VertexObject *> it(vao_map);
while (it.hasNext())
it.next().value()->reinit();
changed = true;
}
void Mesh::destroy(QOpenGLExtraFunctions * f) { void Mesh::destroy(QOpenGLExtraFunctions * f) {
buffer_geom.destroy(f); buffer_geom.destroy(f);
buffer_ind .destroy(f); buffer_ind.destroy(f);
QList<VertexObject*> vaol = vao_map.values(); QList<VertexObject *> vaol = vao_map.values();
foreach (VertexObject* vao, vaol) foreach(VertexObject * vao, vaol)
vao->destroy(f); vao->destroy(f);
qDeleteAll(vao_map); qDeleteAll(vao_map);
vao_map.clear(); vao_map.clear();
@@ -78,12 +91,12 @@ void Mesh::destroy(QOpenGLExtraFunctions * f) {
void Mesh::calculateNormals() { void Mesh::calculateNormals() {
normals_.resize(vertices_.size()); normals_.resize(vertices_.size());
QVector3D dv1, dv2, n; QVector3D dv1, dv2, n;
foreach (const Vector3i & t, triangles_) { foreach(const Vector3i & t, triangles_) {
QVector3D & v0(vertices_[t.p0]); QVector3D & v0(vertices_[t.p0]);
QVector3D & v1(vertices_[t.p1]); QVector3D & v1(vertices_[t.p1]);
QVector3D & v2(vertices_[t.p2]); QVector3D & v2(vertices_[t.p2]);
dv1 = v1 - v0, dv2 = v2 - v0; dv1 = v1 - v0, dv2 = v2 - v0;
n = QVector3D::crossProduct(dv1, dv2).normalized(); n = QVector3D::crossProduct(dv1, dv2).normalized();
normals_[t.p0] = n; normals_[t.p0] = n;
normals_[t.p1] = n; normals_[t.p1] = n;
normals_[t.p2] = n; normals_[t.p2] = n;
@@ -94,32 +107,32 @@ void Mesh::calculateNormals() {
void Mesh::calculateTangents() { void Mesh::calculateTangents() {
if (vertices_.isEmpty() || texcoords_.isEmpty()) return; if (vertices_.isEmpty() || texcoords_.isEmpty()) return;
if (texcoords_.size() != vertices_.size()) return; if (texcoords_.size() != vertices_.size()) return;
tangents_ .resize(vertices_.size()); tangents_.resize(vertices_.size());
bitangents_.resize(vertices_.size()); bitangents_.resize(vertices_.size());
//qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "..."; // qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "...";
QVector3D dv1, dv2; QVector3D dv1, dv2;
QVector2D dt1, dt2; QVector2D dt1, dt2;
QVector3D tan, bitan; QVector3D tan, bitan;
foreach (const Vector3i & t, triangles_) { foreach(const Vector3i & t, triangles_) {
QVector3D & v0(vertices_ [t.p0]); QVector3D & v0(vertices_[t.p0]);
QVector3D & v1(vertices_ [t.p1]); QVector3D & v1(vertices_[t.p1]);
QVector3D & v2(vertices_ [t.p2]); QVector3D & v2(vertices_[t.p2]);
QVector2D & t0(texcoords_[t.p0]); QVector2D & t0(texcoords_[t.p0]);
QVector2D & t1(texcoords_[t.p1]); QVector2D & t1(texcoords_[t.p1]);
QVector2D & t2(texcoords_[t.p2]); QVector2D & t2(texcoords_[t.p2]);
dv1 = v1 - v0, dv2 = v2 - v0; dv1 = v1 - v0, dv2 = v2 - v0;
dt1 = t1 - t0, dt2 = t2 - t0; dt1 = t1 - t0, dt2 = t2 - t0;
tan = (dv1 * dt2.y() - dv2 * dt1.y()).normalized(); tan = (dv1 * dt2.y() - dv2 * dt1.y()).normalized();
bitan = (dv2 * dt1.x() - dv1 * dt2.x()).normalized(); bitan = (dv2 * dt1.x() - dv1 * dt2.x()).normalized();
tangents_ [t.p0] = tan; tangents_[t.p0] = tan;
tangents_ [t.p1] = tan; tangents_[t.p1] = tan;
tangents_ [t.p2] = tan; tangents_[t.p2] = tan;
bitangents_[t.p0] = bitan; bitangents_[t.p0] = bitan;
bitangents_[t.p1] = bitan; bitangents_[t.p1] = bitan;
bitangents_[t.p2] = bitan; bitangents_[t.p2] = bitan;
//qDebug() << " t" << t << vi << ti << dv1.toQVector3D() << "..."; // qDebug() << " t" << t << vi << ti << dv1.toQVector3D() << "...";
} }
//qDebug() << "calculateBinormals" << vcnt << tcnt << tangents_.size(); // qDebug() << "calculateBinormals" << vcnt << tcnt << tangents_.size();
} }
@@ -135,8 +148,7 @@ VertexObject * Mesh::vaoByType(int type) {
bool Mesh::rebuffer(QOpenGLExtraFunctions * f) { bool Mesh::rebuffer(QOpenGLExtraFunctions * f) {
changed = false; changed = false;
if (vertices_.isEmpty()) return true; if (vertices_.isEmpty()) return true;
if (normals_.isEmpty()) if (normals_.isEmpty()) calculateNormals();
calculateNormals();
calculateTangents(); calculateTangents();
vert_count = qMin(vertices_.size(), normals_.size()); vert_count = qMin(vertices_.size(), normals_.size());
vert_count = qMin(vert_count, tangents_.size()); vert_count = qMin(vert_count, tangents_.size());
@@ -145,11 +157,11 @@ bool Mesh::rebuffer(QOpenGLExtraFunctions * f) {
data_.resize(vert_count); data_.resize(vert_count);
for (int i = 0; i < vert_count; ++i) { for (int i = 0; i < vert_count; ++i) {
Vertex & v(data_[i]); Vertex & v(data_[i]);
v.pos = vertices_ [i]; v.pos = vertices_[i];
v.normal = normals_ [i]; v.normal = normals_[i];
v.tangent = tangents_ [i]; v.tangent = tangents_[i];
v.bitangent = bitangents_[i]; v.bitangent = bitangents_[i];
v.tex = texcoords_ [i]; v.tex = texcoords_[i];
} }
int gsize = data_.size() * sizeof(Vertex); int gsize = data_.size() * sizeof(Vertex);
int tsize = triangles_.size() * sizeof(Vector3i); int tsize = triangles_.size() * sizeof(Vector3i);
@@ -176,7 +188,7 @@ void Mesh::draw(QOpenGLExtraFunctions * f, int count, int type) {
if (isEmpty()) return; if (isEmpty()) return;
if (!isInit()) init(f); if (!isInit()) init(f);
if (changed) rebuffer(f); if (changed) rebuffer(f);
//qDebug() << "draw" << geom_type << vert_count << count; // qDebug() << "draw" << geom_type << vert_count << count;
VertexObject * vao = vaoByType(type); VertexObject * vao = vaoByType(type);
vao->bindBuffers(f, buffer_geom, buffer_ind); vao->bindBuffers(f, buffer_geom, buffer_ind);
@@ -188,14 +200,14 @@ void Mesh::draw(QOpenGLExtraFunctions * f, int count, int type) {
void Mesh::clear() { void Mesh::clear() {
vertices_ .clear(); vertices_.clear();
normals_ .clear(); normals_.clear();
tangents_ .clear(); tangents_.clear();
bitangents_.clear(); bitangents_.clear();
texcoords_ .clear(); texcoords_.clear();
triangles_ .clear(); triangles_.clear();
lines_ .clear(); lines_.clear();
data_ .clear(); data_.clear();
changed = hash_changed = true; changed = hash_changed = true;
} }
@@ -221,23 +233,23 @@ void Mesh::loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels
uint Mesh::hash() const { uint Mesh::hash() const {
if (hash_changed) { if (hash_changed) {
hash_changed = false; hash_changed = false;
hash_ = qHashBits(vertices_ .constData(), vertices_ .size() * sizeof(QVector3D)); hash_ = qHashBits(vertices_.constData(), vertices_.size() * sizeof(QVector3D));
hash_ ^= qHashBits(normals_ .constData(), normals_ .size() * sizeof(QVector3D)); hash_ ^= qHashBits(normals_.constData(), normals_.size() * sizeof(QVector3D));
hash_ ^= qHashBits(texcoords_.constData(), texcoords_.size() * sizeof(QVector2D)); hash_ ^= qHashBits(texcoords_.constData(), texcoords_.size() * sizeof(QVector2D));
hash_ ^= qHashBits(triangles_.constData(), triangles_.size() * sizeof( Vector3i)); hash_ ^= qHashBits(triangles_.constData(), triangles_.size() * sizeof(Vector3i));
hash_ ^= qHashBits(lines_ .constData(), lines_ .size() * sizeof( Vector2i)); hash_ ^= qHashBits(lines_.constData(), lines_.size() * sizeof(Vector2i));
} }
return hash_; return hash_;
} }
bool Mesh::isObjectsChanged(int type) const { bool Mesh::isObjectsChanged(int type) const {
return (const_cast<Mesh*>(this))->vaoByType(type)->isObjectsChanged(); return (const_cast<Mesh *>(this))->vaoByType(type)->isObjectsChanged();
} }
bool Mesh::isSelectionChanged(int type) const { bool Mesh::isSelectionChanged(int type) const {
return (const_cast<Mesh*>(this))->vaoByType(type)->isSelectionChanged(); return (const_cast<Mesh *>(this))->vaoByType(type)->isSelectionChanged();
} }
@@ -252,14 +264,14 @@ void Mesh::setSelectionChanged(int type, bool yes) {
void Mesh::setAllObjectsChanged(bool yes) { void Mesh::setAllObjectsChanged(bool yes) {
QMapIterator<int, VertexObject * > it(vao_map); QMapIterator<int, VertexObject *> it(vao_map);
while (it.hasNext()) while (it.hasNext())
it.next().value()->setObjectsChanged(yes); it.next().value()->setObjectsChanged(yes);
} }
void Mesh::setAllSelectionChanged(bool yes) { void Mesh::setAllSelectionChanged(bool yes) {
QMapIterator<int, VertexObject * > it(vao_map); QMapIterator<int, VertexObject *> it(vao_map);
while (it.hasNext()) while (it.hasNext())
it.next().value()->setSelectionChanged(yes); it.next().value()->setSelectionChanged(yes);
} }
@@ -291,8 +303,7 @@ void Mesh::transformPoints(const QMatrix4x4 & mat) {
int vcnt = vertices_.size(), ncnt = normals_.size(); int vcnt = vertices_.size(), ncnt = normals_.size();
for (int i = 0; i < vcnt; ++i) { for (int i = 0; i < vcnt; ++i) {
vertices_[i] = (mat * QVector4D(vertices_[i], 1)).toVector3D(); vertices_[i] = (mat * QVector4D(vertices_[i], 1)).toVector3D();
if (i < ncnt) if (i < ncnt) normals_[i] = (mat * QVector4D(normals_[i], 0)).toVector3D();
normals_[i] = (mat * QVector4D(normals_[i], 0)).toVector3D();
} }
changed = hash_changed = true; changed = hash_changed = true;
} }
@@ -301,7 +312,7 @@ void Mesh::transformPoints(const QMatrix4x4 & mat) {
void Mesh::flipNormals() { void Mesh::flipNormals() {
if (vertices_.isEmpty()) return; if (vertices_.isEmpty()) return;
for (int i = 0; i < triangles_.size(); ++i) for (int i = 0; i < triangles_.size(); ++i)
piSwap(triangles_[i].p1, triangles_[i].p2); piSwap(triangles_[i].p0, triangles_[i].p1);
for (int i = 0; i < lines_.size(); ++i) for (int i = 0; i < lines_.size(); ++i)
piSwap(lines_[i].p0, lines_[i].p1); piSwap(lines_[i].p0, lines_[i].p1);
int ncnt = normals_.size(); int ncnt = normals_.size();
@@ -316,8 +327,8 @@ void Mesh::append(const Mesh * m) {
if (m->isEmpty()) return; if (m->isEmpty()) return;
if (normals_.isEmpty()) calculateNormals(); if (normals_.isEmpty()) calculateNormals();
int vcnt = vertices_.size(); int vcnt = vertices_.size();
vertices_ .append(m->vertices_ ); vertices_.append(m->vertices_);
normals_ .append(m->normals_ ); normals_.append(m->normals_);
texcoords_.append(m->texcoords_); texcoords_.append(m->texcoords_);
QVector<Vector3i> tri = m->triangles_; QVector<Vector3i> tri = m->triangles_;
for (int i = 0; i < tri.size(); ++i) for (int i = 0; i < tri.size(); ++i)
@@ -368,7 +379,7 @@ bool Mesh::loadFromFile(const QString & filename) {
Box3D Mesh::boundingBox() const { Box3D Mesh::boundingBox() const {
if (vertices_.isEmpty()) return Box3D(); if (vertices_.isEmpty()) return Box3D();
int vcnt = vertices_.size(); int vcnt = vertices_.size();
//qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "..."; // qDebug() << "calculateBinormals" << vcnt << tcnt << vertices_.size() << texcoords_.size() << "...";
GLfloat mix, miy, miz, max, may, maz; GLfloat mix, miy, miz, max, may, maz;
QVector3D v0(vertices_[0]); QVector3D v0(vertices_[0]);
mix = max = v0.x(); mix = max = v0.x();
@@ -384,9 +395,9 @@ Box3D Mesh::boundingBox() const {
if (miz > v.z()) miz = v.z(); if (miz > v.z()) miz = v.z();
if (maz < v.z()) maz = v.z(); if (maz < v.z()) maz = v.z();
} }
bound.x = mix; bound.x = mix;
bound.y = miy; bound.y = miy;
bound.z = miz; bound.z = miz;
bound.length = max - mix; bound.length = max - mix;
bound.width = may - miy; bound.width = may - miy;
bound.height = maz - miz; bound.height = maz - miz;
@@ -394,26 +405,26 @@ Box3D Mesh::boundingBox() const {
} }
QDataStream & operator <<(QDataStream & s, const Mesh * m) { QDataStream & operator<<(QDataStream & s, const Mesh * m) {
ChunkStream cs; ChunkStream cs;
//qDebug() << "place VBO" << m.vertices_.size() << m.normals_.size() << m.texcoords_.size() << m.colors_.size() << "..."; // 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_) 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));
.add(6, m->triangles_).add(7, m->lines_).add(10, int(m->geom_type)); // qDebug() << "place VBO done" << cs.data().size() << "...";
//qDebug() << "place VBO done" << cs.data().size() << "..."; s << cs.data();
s << cs.data(); return s; return s;
} }
QDataStream & operator >>(QDataStream & s, Mesh *& m) { QDataStream & operator>>(QDataStream & s, Mesh *& m) {
m = new Mesh(); m = new Mesh();
ChunkStream cs(s); ChunkStream cs(s);
while (!cs.atEnd()) { while (!cs.atEnd()) {
switch (cs.read()) { switch (cs.read()) {
case 1 : cs.get(m->vertices_ ); break; case 1: cs.get(m->vertices_); break;
case 2 : cs.get(m->normals_ ); break; case 2: cs.get(m->normals_); break;
case 3 : cs.get(m->texcoords_); break; case 3: cs.get(m->texcoords_); break;
case 6 : cs.get(m->triangles_); break; case 6: cs.get(m->triangles_); break;
case 7 : cs.get(m->lines_ ); break; case 7: cs.get(m->lines_); break;
case 10: m->geom_type = cs.getData<int>(); break; case 10: m->geom_type = cs.getData<int>(); break;
} }
} }

123
src/core/core/glmesh.h Normal file
View File

@@ -0,0 +1,123 @@
/*
QGL Mesh
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLMESH_H
#define GLMESH_H
#include "glvertexobject.h"
#include <chunkstream.h>
class QGLENGINE_CORE_EXPORT Mesh {
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();
void init(QOpenGLExtraFunctions * f);
void destroy(QOpenGLExtraFunctions * f);
bool rebuffer(QOpenGLExtraFunctions * f);
void draw(QOpenGLExtraFunctions * f, int count, int type = 0);
void reinit();
void clear();
void loadObject(QOpenGLExtraFunctions * f, const QGLEngineShaders::Object & object, int type = 0);
void loadObjects(QOpenGLExtraFunctions * f, const QVector<QGLEngineShaders::Object> & objects, int type = 0);
void loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels, int type = 0);
int verticesCount() const { return vertices_.size(); }
int trianglesCount() const { return triangles_.size(); }
int linesCount() const { return lines_.size(); }
bool isInit() const { return buffer_geom.isInit(); }
bool isEmpty() const { return vertices_.isEmpty(); }
uint hash() const;
bool isObjectsChanged(int type = 0) const;
bool isSelectionChanged(int type = 0) const;
void setObjectsChanged(int type = 0, bool yes = true);
void setSelectionChanged(int type = 0, bool yes = true);
void setAllObjectsChanged(bool yes = true);
void setAllSelectionChanged(bool yes = true);
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 flipNormals();
void append(const Mesh * m);
bool saveToFile(const QString & filename);
bool loadFromFile(const QString & filename);
Box3D boundingBox() const;
private:
void calculateNormals();
void calculateTangents();
VertexObject * vaoByType(int type);
QVector<QVector3D> vertices_, normals_, tangents_, bitangents_;
QVector<QVector2D> texcoords_;
QVector<Vector3i> triangles_;
QVector<Vector2i> lines_;
QVector<QGLEngineShaders::Vertex> data_;
GLenum geom_type;
Buffer buffer_geom, buffer_ind;
QMap<int, VertexObject *> vao_map;
mutable uint hash_;
mutable bool hash_changed;
int vert_count;
bool changed;
};
QGLENGINE_CORE_EXPORT QDataStream & operator<<(QDataStream & s, const Mesh * m);
QGLENGINE_CORE_EXPORT QDataStream & operator>>(QDataStream & s, Mesh *& m);
#endif // GLMESH_H

View File

@@ -1,54 +1,67 @@
/* /*
QGL Primitives QGL Primitives
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "glprimitives.h" #include "glprimitives.h"
#include "glmesh.h" #include "glmesh.h"
Mesh * Primitive::plane(float width, float length) { Mesh * Primitive::plane(float width, float length, int width_segments, int length_segments) {
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & i(ret->indicesTriangles ()); QVector<Vector3i> & i(ret->indicesTriangles());
float hw = width / 2.f, hl = length / 2.f; float hw = width / 2.f, hl = length / 2.f;
for (int j = 0; j < 4; ++j) n << QVector3D(0., 0., 1.); float w1 = 1.f / width_segments, l1 = 1.f / length_segments;
t << QVector2D(0., 0.) << QVector2D(0., 1.) << QVector2D(1., 1.) << QVector2D(1., 0.); int sind = 0;
v << QVector3D(-hw, -hl, 0.) << QVector3D(-hw, hl, 0.) << QVector3D(hw, hl, 0.) << QVector3D(hw, -hl, 0.); for (int wi = 0; wi < width_segments; ++wi) {
i << Vector3i(0, 2, 1) << Vector3i(0, 3, 2); for (int li = 0; li < length_segments; ++li) {
for (int j = 0; j < 4; ++j)
n << QVector3D(0., 0., 1.);
float ws = (float)wi / width_segments;
float ls = (float)li / length_segments;
t << QVector2D(ws, ls) << QVector2D(ws, ls + l1) << QVector2D(ws + w1, ls + l1) << QVector2D(ws + w1, ls);
v << QVector3D(ws * width - hw, ls * length - hl, 0.) << QVector3D(ws * width - hw, (ls + l1) * length - hl, 0.)
<< QVector3D((ws + w1) * width - hw, (ls + l1) * length - hl, 0.) << QVector3D((ws + w1) * width - hw, ls * length - hl, 0.);
i << Vector3i(sind + 0, sind + 2, sind + 1) << Vector3i(sind + 0, sind + 3, sind + 2);
sind += 4;
}
}
return ret; return ret;
} }
Mesh * Primitive::cube(float width, float length, float height) { Mesh * Primitive::cube(float width, float length, float height, int width_segments, int length_segments, int height_segments) {
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
QVector3D scale(width, length, height); QVector3D scale(width, length, height);
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & i(ret->indicesTriangles ()); QVector<Vector3i> & i(ret->indicesTriangles());
float hs = 0.5f; float hs = 0.5f;
int si = 0; int si = 0;
QMatrix4x4 mat; QMatrix4x4 mat;
si = v.size(); si = v.size();
for (int j = 0; j < 4; ++j) n << QVector3D(0., -1., 0.); for (int j = 0; j < 4; ++j)
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.); 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); 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); i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
@@ -60,21 +73,21 @@ Mesh * Primitive::cube(float width, float length, float height) {
n << cn; n << cn;
v << mat.map(QVector4D(v[j])).toVector3D(); v << mat.map(QVector4D(v[j])).toVector3D();
} }
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.); 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); i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
} }
mat.setToIdentity(); mat.setToIdentity();
mat.rotate(90., 1., 0.,0.); mat.rotate(90., 1., 0., 0.);
for (int r = 0; r < 2; ++r) { for (int r = 0; r < 2; ++r) {
si = v.size(); si = v.size();
mat.rotate(180., 1., 0.,0.); mat.rotate(180., 1., 0., 0.);
QVector3D cn = mat.map(n[0]); QVector3D cn = mat.map(n[0]);
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
n << cn; n << cn;
v << mat.map(QVector4D(v[j])).toVector3D(); v << mat.map(QVector4D(v[j])).toVector3D();
} }
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.); 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); i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
} }
@@ -87,10 +100,10 @@ Mesh * Primitive::cube(float width, float length, float height) {
Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float radius, float end_angle) { Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float radius, float end_angle) {
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indicesTriangles()); QVector<Vector3i> & ind(ret->indicesTriangles());
int hseg = segments_h + 1, wlseg = segments_wl + 1; int hseg = segments_h + 1, wlseg = segments_wl + 1;
double crw, crl, a, ch, twl; double crw, crl, a, ch, twl;
double eang = deg2rad * end_angle; double eang = deg2rad * end_angle;
@@ -99,16 +112,16 @@ Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float radius, float
for (int i = 0; i <= hseg; i++) { for (int i = 0; i <= hseg; i++) {
ch = -cos((double)i / hseg * M_PI); ch = -cos((double)i / hseg * M_PI);
cp.setZ(ch * radius); cp.setZ(ch * radius);
twl = sqrt(1. - ch * ch); twl = sqrt(1. - ch * ch);
crw = twl * radius; crw = twl * radius;
crl = twl * radius; crl = twl * radius;
int cvcnt = wlseg * 2; int cvcnt = wlseg * 2;
for (int j = 0; j < cvcnt; j++) { for (int j = 0; j < cvcnt; j++) {
a = (double)j / (cvcnt - 1) * eang; a = (double)j / (cvcnt - 1) * eang;
cp.setX(crl * cos(a)); cp.setX(crl * cos(a));
cp.setY(crw * sin(a)); cp.setY(crw * sin(a));
v << cp; v << cp;
t << QVector2D((double)j / (cvcnt - 1), ch/2.f + 0.5f); t << QVector2D((double)j / (cvcnt - 1), ch / 2.f + 0.5f);
n << cp.normalized(); n << cp.normalized();
int si = v.size() - 1; int si = v.size() - 1;
if (j > 0 && i > 0) { if (j > 0 && i > 0) {
@@ -118,7 +131,7 @@ Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float radius, float
} }
} }
if (end_angle < 360.) { if (end_angle < 360.) {
Mesh * cap = Primitive::disc(segments_h+1, radius, 180); Mesh * cap = Primitive::disc(segments_h + 1, radius, 180);
cap->rotatePoints(90, 0, 1, 0); cap->rotatePoints(90, 0, 1, 0);
cap->rotatePoints(-90, 0, 0, 1); cap->rotatePoints(-90, 0, 0, 1);
ret->append(cap); ret->append(cap);
@@ -133,10 +146,10 @@ Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float radius, float
Mesh * Primitive::disc(int segments, float radius, float end_angle) { Mesh * Primitive::disc(int segments, float radius, float end_angle) {
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indicesTriangles()); QVector<Vector3i> & ind(ret->indicesTriangles());
segments = qMax(segments + 1, 4); segments = qMax(segments + 1, 4);
QVector3D cp; QVector3D cp;
@@ -173,10 +186,10 @@ QVector3D coneNormal(double r, double height, double ang) {
Mesh * Primitive::cone(int segments, float radius, float height) { Mesh * Primitive::cone(int segments, float radius, float height) {
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indicesTriangles()); QVector<Vector3i> & ind(ret->indicesTriangles());
int seg = qMax(segments + 1, 4); int seg = qMax(segments + 1, 4);
QVector3D cp; QVector3D cp;
@@ -194,8 +207,7 @@ Mesh * Primitive::cone(int segments, float radius, float height) {
t << QVector2D((double)i / (seg - 1), 0.f); t << QVector2D((double)i / (seg - 1), 0.f);
n << coneNormal(radius, height, a); n << coneNormal(radius, height, a);
int si = v.size() - 1; int si = v.size() - 1;
if (i > 0) if (i > 0) ind << Vector3i(si - 1, si - 2, si);
ind << Vector3i(si - 1, si - 2, si);
} }
Mesh * cap = Primitive::disc(segments, radius); Mesh * cap = Primitive::disc(segments, radius);
@@ -209,10 +221,10 @@ Mesh * Primitive::cone(int segments, float radius, float height) {
Mesh * Primitive::cylinder(int segments, float radius, float height, float end_angle) { Mesh * Primitive::cylinder(int segments, float radius, float height, float end_angle) {
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indicesTriangles()); QVector<Vector3i> & ind(ret->indicesTriangles());
int seg = qMax(segments + 1, 4); int seg = qMax(segments + 1, 4);
QVector3D cp, norm; QVector3D cp, norm;
@@ -229,7 +241,8 @@ Mesh * Primitive::cylinder(int segments, float radius, float height, float end_a
v << cp; v << cp;
t << QVector2D((double)i / (seg - 1), 0.f); t << QVector2D((double)i / (seg - 1), 0.f);
t << QVector2D((double)i / (seg - 1), 1.f); t << QVector2D((double)i / (seg - 1), 1.f);
n << norm; n << norm; n << norm;
n << norm;
int si = v.size() - 1; int si = v.size() - 1;
if (i > 0) { if (i > 0) {
ind << Vector3i(si - 2, si - 1, si); ind << Vector3i(si - 2, si - 1, si);
@@ -248,7 +261,7 @@ Mesh * Primitive::cylinder(int segments, float radius, float height, float end_a
if (end_angle < 360.) { if (end_angle < 360.) {
Mesh * cap = Primitive::plane(radius, height); Mesh * cap = Primitive::plane(radius, height);
cap->rotatePoints(90, 1, 0, 0); cap->rotatePoints(90, 1, 0, 0);
cap->translatePoints(radius/2, 0, height/2); cap->translatePoints(radius / 2, 0, height / 2);
ret->append(cap); ret->append(cap);
cap->flipNormals(); cap->flipNormals();
cap->rotatePoints(end_angle, 0, 0, 1); cap->rotatePoints(end_angle, 0, 0, 1);
@@ -263,8 +276,8 @@ Mesh * Primitive::cylinder(int segments, float radius, float height, float end_a
Mesh * Primitive::arrow(int segments, float thick, float angle) { Mesh * Primitive::arrow(int segments, float thick, float angle) {
double cone_r = 1.5 * thick; double cone_r = 1.5 * thick;
double cone_h = 2. * cone_r / tan(angle * deg2rad); double cone_h = 2. * cone_r / tan(angle * deg2rad);
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
Mesh * m = Primitive::cylinder(segments, thick / 2., 1. - cone_h); Mesh * m = Primitive::cylinder(segments, thick / 2., 1. - cone_h);
ret->append(m); ret->append(m);
delete m; delete m;
m = Primitive::cone(segments, cone_r, cone_h); m = Primitive::cone(segments, cone_r, cone_h);
@@ -277,10 +290,10 @@ Mesh * Primitive::arrow(int segments, float thick, float angle) {
Mesh * Primitive::torus(int segments_main, int segments_second, float radius_main, float radius_second, float end_angle) { Mesh * Primitive::torus(int segments_main, int segments_second, float radius_main, float radius_second, float end_angle) {
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector3i> & ind(ret->indicesTriangles()); QVector<Vector3i> & ind(ret->indicesTriangles());
QVector<QVector3D> cv, cn; QVector<QVector3D> cv, cn;
QVector<QVector2D> ct; QVector<QVector2D> ct;
@@ -315,7 +328,7 @@ Mesh * Primitive::torus(int segments_main, int segments_second, float radius_mai
pcnt = v.size(); pcnt = v.size();
} }
if (end_angle < 360.) { if (end_angle < 360.) {
Mesh * cap = Primitive::disc(segments_second-1, radius_second); Mesh * cap = Primitive::disc(segments_second - 1, radius_second);
cap->rotatePoints(90, 1, 0, 0); cap->rotatePoints(90, 1, 0, 0);
cap->translatePoints(radius_main, 0, 0); cap->translatePoints(radius_main, 0, 0);
ret->append(cap); ret->append(cap);
@@ -328,22 +341,20 @@ Mesh * Primitive::torus(int segments_main, int segments_second, float radius_mai
} }
Mesh * Primitive::cubeFrame(float width, float length, float height) { Mesh * Primitive::cubeFrame(float width, float length, float height) {
Mesh * ret = new Mesh(GL_LINES); Mesh * ret = new Mesh(GL_LINES);
QVector3D scale(width, length, height); QVector3D scale(width, length, height);
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector2i> & i(ret->indicesLines()); QVector<Vector2i> & i(ret->indicesLines());
float hs = 0.5f; 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);
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) { for (int j = 0; j < 8; ++j) {
v[j] *= scale; v[j] *= scale;
t << QVector2D(0, 0); t << QVector2D(0, 0);
n << QVector3D(0,0,1); n << QVector3D(0, 0, 1);
} }
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
i << Vector2i(j, (j + 1) % 4); i << Vector2i(j, (j + 1) % 4);
@@ -356,10 +367,10 @@ Mesh * Primitive::cubeFrame(float width, float length, float height) {
Mesh * Primitive::ellipsoidFrame(int segments_wl, int segments_h, float radius) { Mesh * Primitive::ellipsoidFrame(int segments_wl, int segments_h, float radius) {
Mesh * ret = new Mesh(GL_LINES); Mesh * ret = new Mesh(GL_LINES);
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector2i> & ind(ret->indicesLines()); QVector<Vector2i> & ind(ret->indicesLines());
int hseg = segments_h + 1, wlseg = segments_wl + 1; int hseg = segments_h + 1, wlseg = segments_wl + 1;
double crw, crl, a, ch, twl; double crw, crl, a, ch, twl;
@@ -367,16 +378,16 @@ Mesh * Primitive::ellipsoidFrame(int segments_wl, int segments_h, float radius)
for (int i = 0; i <= hseg; i++) { for (int i = 0; i <= hseg; i++) {
ch = -cos((double)i / hseg * M_PI); ch = -cos((double)i / hseg * M_PI);
cp.setZ(ch * radius); cp.setZ(ch * radius);
twl = sqrt(1. - ch * ch); twl = sqrt(1. - ch * ch);
crw = twl * radius; crw = twl * radius;
crl = twl * radius; crl = twl * radius;
int cvcnt = wlseg * 2; int cvcnt = wlseg * 2;
for (int j = 0; j < cvcnt; j++) { for (int j = 0; j < cvcnt; j++) {
a = (double)j / (cvcnt - 1) * M_2PI; a = (double)j / (cvcnt - 1) * M_2PI;
cp.setX(crl * cos(a)); cp.setX(crl * cos(a));
cp.setY(crw * sin(a)); cp.setY(crw * sin(a));
v << cp; v << cp;
t << QVector2D((double)j / (cvcnt - 1), ch/2.f + 0.5f); t << QVector2D((double)j / (cvcnt - 1), ch / 2.f + 0.5f);
n << cp.normalized(); n << cp.normalized();
int si = v.size() - 1; int si = v.size() - 1;
if (j > 0 && i > 0) { if (j > 0 && i > 0) {
@@ -391,10 +402,10 @@ Mesh * Primitive::ellipsoidFrame(int segments_wl, int segments_h, float radius)
Mesh * Primitive::coneFrame(int segments, float radius, float height) { Mesh * Primitive::coneFrame(int segments, float radius, float height) {
Mesh * ret = new Mesh(GL_LINES); Mesh * ret = new Mesh(GL_LINES);
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector2i> & ind(ret->indicesLines()); QVector<Vector2i> & ind(ret->indicesLines());
int seg = qMax(segments + 1, 4); int seg = qMax(segments + 1, 4);
QVector3D cp; QVector3D cp;
@@ -424,13 +435,13 @@ Mesh * Primitive::coneFrame(int segments, float radius, float height) {
Mesh * Primitive::lineFrame(QVector3D p0, QVector3D p1) { Mesh * Primitive::lineFrame(QVector3D p0, QVector3D p1) {
Mesh * ret = new Mesh(GL_LINES); Mesh * ret = new Mesh(GL_LINES);
QVector<QVector3D> & v(ret->vertices ()); QVector<QVector3D> & v(ret->vertices());
QVector<QVector3D> & n(ret->normals ()); QVector<QVector3D> & n(ret->normals());
QVector<QVector2D> & t(ret->texcoords()); QVector<QVector2D> & t(ret->texcoords());
QVector< Vector2i> & ind(ret->indicesLines()); QVector<Vector2i> & ind(ret->indicesLines());
v << p0 << p1; v << p0 << p1;
n << QVector3D(0,0,1) << QVector3D(0,0,1); n << QVector3D(0, 0, 1) << QVector3D(0, 0, 1);
t << QVector2D(0,0) << QVector2D(1,0); t << QVector2D(0, 0) << QVector2D(1, 0);
ind << Vector2i(0, 1); ind << Vector2i(0, 1);
return ret; return ret;
} }

View File

@@ -0,0 +1,57 @@
/*
QGL Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 {
QGLENGINE_CORE_EXPORT Mesh * plane(float width = 1., float length = 1., int width_segments = 1, int length_segments = 1);
QGLENGINE_CORE_EXPORT Mesh *
cube(float width = 1., float length = 1., float height = 1., int width_segments = 1, int length_segments = 1, int height_segments = 1);
QGLENGINE_CORE_EXPORT Mesh * ellipsoid(int segments_wl, int segments_h, float radius = 1., float end_angle = 360.);
QGLENGINE_CORE_EXPORT Mesh * disc(int segments, float radius = 1., float end_angle = 360.);
QGLENGINE_CORE_EXPORT Mesh * cone(int segments, float radius = 1., float height = 1.);
QGLENGINE_CORE_EXPORT Mesh * cylinder(int segments, float radius = 1., float height = 1., float end_angle = 360.);
QGLENGINE_CORE_EXPORT Mesh * arrow(int segments = 16, float thick = 0.04, float angle = 30.); // length = 1
QGLENGINE_CORE_EXPORT Mesh *
torus(int segments_main = 30, int segments_second = 16, float radius_main = 2.5, float radius_second = 0.5, float end_angle = 360.);
QGLENGINE_CORE_EXPORT Mesh * lineFrame(QVector3D p0, QVector3D p1);
QGLENGINE_CORE_EXPORT Mesh * cubeFrame(float width = 1., float length = 1., float height = 1.);
QGLENGINE_CORE_EXPORT Mesh * ellipsoidFrame(int segments_wl, int segments_h, float radius = 1.);
QGLENGINE_CORE_EXPORT Mesh * coneFrame(int segments, float radius = 1., float height = 1.);
} // namespace Primitive
#endif // GLPRIMITIVE_CUBE_H

View File

@@ -1,54 +1,63 @@
/* /*
QGLEngineShaders QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "glshaders.h"
#include "glshaders_headers.h"
#include "gltypes.h" #include "gltypes.h"
#include "qglview.h" #include "qglview.h"
#include "glshaders.h"
#include "glshaders_headers.h"
using namespace QGLEngineShaders; using namespace QGLEngineShaders;
bool addShader(QOpenGLShaderProgram * prog, QOpenGLShader::ShaderType type, QString & content, const QString & file, bool add_qgl, const QString & defs) { bool addShader(QOpenGLShaderProgram * prog,
QOpenGLShader::ShaderType type,
QString & content,
const QString & file,
bool add_qgl,
const QString & defs) {
if (type == 0 || content.isEmpty()) { if (type == 0 || content.isEmpty()) {
content.clear(); content.clear();
return true; return true;
} }
//qDebug() << "[QGLEngine] Shader" << file << "found" << (QOpenGLShader::ShaderTypeBit)(int)type << "section ..."; // qDebug() << "[QGLEngine] Shader" << file << "found" << (QOpenGLShader::ShaderTypeBit)(int)type << "section ...";
if (add_qgl) { if (add_qgl) {
switch (type) { switch (type) {
case QOpenGLShader::Fragment: case QOpenGLShader::Fragment:
content.prepend(qgl_material_head);
content.prepend(qgl_fragment_head); content.prepend(qgl_fragment_head);
content.prepend(qgl_uniform); content.prepend(qgl_uniform_light);
content.prepend(qgl_uniform_material);
content.prepend(qgl_structs); content.prepend(qgl_structs);
break; break;
case QOpenGLShader::Vertex : case QOpenGLShader::Vertex:
content.prepend(qgl_vertex_head ); content.prepend(qgl_material_head);
break; content.prepend(qgl_vertex_head);
case QOpenGLShader::Geometry: content.prepend(qgl_uniform_material);
content.prepend(qgl_geometry_head); content.prepend(qgl_structs);
break; break;
case QOpenGLShader::Geometry: content.prepend(qgl_geometry_head); break;
} }
} }
content.prepend(defs); content.prepend(defs);
content.prepend(qgl_common_head); content.prepend(qgl_common_head);
bool ret = prog->addShaderFromSourceCode(type, content.toLatin1()); bool ret = prog->addShaderFromSourceCode(type, content.toLatin1());
if (!ret) qDebug() << "[QGLEngine] Shader" << file << "Compile error:\n" << prog->log(); if (!ret) qDebug() << "[QGLEngine] Shader" << file << "Compile error:\n" << prog->log().toLocal8Bit().constData();
content.clear(); content.clear();
return ret; return ret;
} }
@@ -57,15 +66,18 @@ bool addShader(QOpenGLShaderProgram * prog, QOpenGLShader::ShaderType type, QStr
QString prepareDefines(const QStringList & defines) { QString prepareDefines(const QStringList & defines) {
if (defines.isEmpty()) return QString(); if (defines.isEmpty()) return QString();
QString ret; QString ret;
foreach (QString s, defines) foreach(QString s, defines)
ret.append("#define " + s + "\n"); ret.append("#define " + s + "\n");
return ret; return ret;
} }
bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog, const QString & file, bool add_qgl, const QStringList & defines) { bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog,
if (!prog) const QString & file,
prog = new QOpenGLShaderProgram(); bool add_qgl,
const QStringList & defines,
const QString & custom_header) {
if (!prog) prog = new QOpenGLShaderProgram();
prog->removeAllShaders(); prog->removeAllShaders();
QFile f(file); QFile f(file);
if (!f.open(QIODevice::ReadOnly)) { if (!f.open(QIODevice::ReadOnly)) {
@@ -73,11 +85,11 @@ bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog, const QStr
return false; return false;
} }
QTextStream ts(&f); QTextStream ts(&f);
QString cur_shader, line, pl, defs = prepareDefines(defines); QString cur_shader, line, pl, defs = prepareDefines(defines) + "\n" + custom_header;
QOpenGLShader::ShaderType type = QOpenGLShader::ShaderType(); QOpenGLShader::ShaderType type = QOpenGLShader::ShaderType();
while (!ts.atEnd()) { while (!ts.atEnd()) {
line = ts.readLine(); line = ts.readLine();
pl = line.trimmed().remove(' ').remove('\t').mid(2).toLower(); pl = line.trimmed().remove(' ').remove('\t').mid(2).toLower();
pl.chop(2); pl.chop(2);
if (pl == "vertex" || pl == "vert") { if (pl == "vertex" || pl == "vert") {
if (!addShader(prog, type, cur_shader, file, add_qgl, defs)) return false; if (!addShader(prog, type, cur_shader, file, add_qgl, defs)) return false;
@@ -109,7 +121,7 @@ bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog, const QStr
} }
if (!addShader(prog, type, cur_shader, file, add_qgl, defs)) return false; if (!addShader(prog, type, cur_shader, file, add_qgl, defs)) return false;
if (!prog->link()) { if (!prog->link()) {
qDebug() << "[QGLEngine] Shader" << file << "Link error:\n" << prog->log(); qDebug() << "[QGLEngine] Shader" << file << "Link error:\n" << prog->log().toLocal8Bit().constData();
return false; return false;
} }
qDebug() << "[QGLEngine] Shader" << file << "ok"; qDebug() << "[QGLEngine] Shader" << file << "ok";
@@ -117,15 +129,18 @@ bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog, const QStr
} }
bool QGLEngineShaders::loadShaders(QOpenGLShaderProgram *& prog, const QStringList & files, bool add_qgl, const QStringList & defines) { bool QGLEngineShaders::loadShaders(QOpenGLShaderProgram *& prog,
if (!prog) const QStringList & files,
prog = new QOpenGLShaderProgram(); bool add_qgl,
const QStringList & defines,
const QString & custom_header) {
if (!prog) prog = new QOpenGLShaderProgram();
prog->removeAllShaders(); prog->removeAllShaders();
QString cur_shader, defs = prepareDefines(defines); QString cur_shader, defs = prepareDefines(defines) + "\n" + custom_header;
foreach (QString f, files) { foreach(QString f, files) {
QFileInfo fi(f); QFileInfo fi(f);
QOpenGLShader::ShaderType type = QOpenGLShader::ShaderType(); QOpenGLShader::ShaderType type = QOpenGLShader::ShaderType();
if (fi.suffix().toLower() == "vert") type = QOpenGLShader::Vertex ; if (fi.suffix().toLower() == "vert") type = QOpenGLShader::Vertex;
if (fi.suffix().toLower() == "frag") type = QOpenGLShader::Fragment; if (fi.suffix().toLower() == "frag") type = QOpenGLShader::Fragment;
if (fi.suffix().toLower() == "geom") type = QOpenGLShader::Geometry; if (fi.suffix().toLower() == "geom") type = QOpenGLShader::Geometry;
if (type == 0) continue; if (type == 0) continue;
@@ -138,7 +153,7 @@ bool QGLEngineShaders::loadShaders(QOpenGLShaderProgram *& prog, const QStringLi
if (!addShader(prog, type, cur_shader, f, add_qgl, defs)) return false; if (!addShader(prog, type, cur_shader, f, add_qgl, defs)) return false;
} }
if (!prog->link()) { if (!prog->link()) {
qDebug() << "[QGLEngine] Shader" << files << "Link error:\n" << prog->log(); qDebug() << "[QGLEngine] Shader" << files << "Link error:\n" << prog->log().toLocal8Bit().constData();
return false; return false;
} }
qDebug() << "[QGLEngine] Shader" << files << "ok"; qDebug() << "[QGLEngine] Shader" << files << "ok";

39
src/core/core/glshaders.h Normal file
View File

@@ -0,0 +1,39 @@
/*
QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 {
QGLENGINE_CORE_EXPORT bool loadShadersMulti(QOpenGLShaderProgram *& prog,
const QString & file,
bool add_qgl = true,
const QStringList & defines = QStringList(),
const QString & custom_header = QString());
QGLENGINE_CORE_EXPORT bool loadShaders(QOpenGLShaderProgram *& prog,
const QStringList & files,
bool add_qgl = true,
const QStringList & defines = QStringList(),
const QString & custom_header = QString());
} // namespace QGLEngineShaders
#endif // GLSHADERS_H

View File

@@ -0,0 +1,129 @@
/*
QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 = 256;
const char qgl_common_head[] = "#version 400 core\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 uvec4 qgl_ObjectIntegers;\n"
"layout(location = 7 ) in uint qgl_ObjectSelected;\n"
"layout(location = 8 ) in vec4 qgl_ObjectColor ;\n"
"layout(location = 9 ) in mat4 qgl_ModelMatrix ;\n"
"layout(location = 13) in mat2x3 qgl_TextureMatrix ;\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 inverse(mat3(qgl_ViewMatrix * qgl_ModelMatrix));}\n"
"mat3 qgl_getTangentMatrix() {return mat3(qgl_ViewMatrix * qgl_ModelMatrix);}\n"
"vec2 qgl_getFragTexture() {return (vec3(qgl_Texture, 1.f) * qgl_TextureMatrix).xy;}\n"
"vec4 qgl_ftransform() {return qgl_ViewProjMatrix * (qgl_ModelMatrix * vec4(qgl_Vertex, 1.f));}\n"
"#define qgl_Material qgl_ObjectIntegers[0]\n"
"#define qgl_ObjectID qgl_ObjectIntegers[1]\n"
"#define qgl_ObjectFlags qgl_ObjectIntegers[2]\n"
"";
const char qgl_material_head[] =
"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.rgb = t.rgb * qgl_material[qgl_MaterialIndex].map[type].amount + qgl_material[qgl_MaterialIndex].map[type].offset;\n"
" return t;\n"
"}\n"
"";
const char qgl_fragment_head[] = "in vec2 qgl_FragTexture;\n"
"flat in uint qgl_MaterialIndex;\n"
"out vec4 qgl_FragData[gl_MaxDrawBuffers];\n"
"uniform vec2 qgl_ViewSize;\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_METALNESS 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_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"
" vec4 decay_intensity;\n"
" vec4 angles;\n"
" float size;\n"
" float flags;\n"
" QGLMap map;\n"
"};\n"
"struct QGLLightPosition {\n"
" vec4 position;\n"
" vec4 direction;\n"
" mat4 shadow_matrix;\n"
"};\n"
"";
const char qgl_uniform_material[] = "layout (std140) uniform QGLMaterialData {\n"
" QGLMaterial qgl_material[128];\n"
"};\n"
"uniform sampler2DArray qgl_texture_array[2];\n"
"";
const char qgl_uniform_light[] = "layout (std140) uniform QGLLightParameterData {\n"
" QGLLightParameter qgl_light_parameter[256];\n"
"};\n"
"layout (std140) uniform QGLLightPositionData {\n"
" QGLLightPosition qgl_light_position[256];\n"
"};\n"
"";
} // namespace QGLEngineShaders
#endif // GLSHADERS_HEADERS_H

View File

@@ -0,0 +1,108 @@
/*
QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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(1., 1., 1., 0.);
color_emission = QVector4D(0., 0., 0., 0.);
transparency = 0.;
reflectivity = 0.;
iof = 0.;
dispersion = 0.;
map[mtNormal].map_index = emrBlue;
map[mtRelief].map_index = emrBlack;
map[mtRoughness].amount = 0.75;
map[mtMetalness].amount = 0.25;
}
void QGLEngineShaders::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 QGLEngineShaders::prepareDrawObj(QOpenGLExtraFunctions * f) {
// qDebug() << "prepareDrawObj";
f->glEnableVertexAttribArray(integers_loc);
f->glEnableVertexAttribArray(color_loc);
for (int i = 0; i < 4; ++i)
f->glEnableVertexAttribArray(modelmatrix_loc + i);
for (int i = 0; i < 2; ++i)
f->glEnableVertexAttribArray(texturematrix_loc + i);
GLsizei size = sizeof(Object);
f->glVertexAttribIPointer(integers_loc, 4, GL_UNSIGNED_INT, size, (const void *)integers_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));
}
for (int i = 0; i < 2; ++i) {
f->glVertexAttribPointer(texturematrix_loc + i,
3,
GL_FLOAT,
GL_FALSE,
size,
(const void *)(texturematrix_offset + sizeof(QVector3D) * i));
}
f->glVertexAttribDivisor(integers_loc, 1);
f->glVertexAttribDivisor(color_loc, 1);
for (int i = 0; i < 4; ++i)
f->glVertexAttribDivisor(modelmatrix_loc + i, 1);
for (int i = 0; i < 2; ++i)
f->glVertexAttribDivisor(texturematrix_loc + i, 1);
}
void QGLEngineShaders::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);
}

View File

@@ -0,0 +1,170 @@
/*
QGLEngineShaders
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 integers_offset = 0;
const GLsizei color_offset = sizeof(GLuint) * 4 + integers_offset;
const GLsizei modelmatrix_offset = sizeof(QVector4D) + color_offset;
const GLsizei texturematrix_offset = sizeof(QVector4D) * 4 + modelmatrix_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 integers_loc = 6; // qgl_ObjectIntegers
const GLuint color_loc = 8; // qgl_ObjectColor
const GLuint modelmatrix_loc = 9; // qgl_ModelViewProjectionMatrix
const GLuint texturematrix_loc = 13; // qgl_TextureMatrix
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 = flags = 0;
color = QVector4D(1, 1, 1, 1);
QMatrix4x4().copyDataTo(modelmatrix);
QMatrix2x3().transposed().copyDataTo(texturematrix);
}
GLuint material;
GLuint object_id;
union {
GLuint flags;
struct {
GLuint f_accept_light : 1;
GLuint f_accept_fog : 1;
GLuint f_accept_cast_shadow: 1;
GLuint f_accept_rec_shadow : 1;
};
};
GLuint _reserve;
QVector4D color;
GLfloat modelmatrix[16];
GLfloat texturematrix[6];
};
#pragma pack(pop)
/// UBO
enum BindingPoints {
bpMaterials,
bpLightParameters,
bpLightPositions,
};
enum MapType {
mtDiffuse = 0,
mtNormal = 1,
mtMetalness = 2,
mtRoughness = 3,
mtEmission = 4,
mtRelief = 5,
};
enum TextureRole {
trCoeffBRDF = 10,
trEnvironment = 11,
};
enum TextureArrayRole {
tarEmpty = 12,
tarMaps = 13,
tarShadowsCone = 16,
tarShadowsOmni = 17,
tarDepthsCone = 18,
tarDepthsOmni = 19,
};
enum EmptyMapRole {
emrWhite,
emrBlue,
emrBlack,
emrCount,
};
#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_emission;
GLfloat transparency;
GLfloat reflectivity;
GLfloat iof;
GLfloat dispersion;
QGLMap map[QGL_MAPS_COUNT];
};
struct QGLLightParameter {
QVector4D color;
QVector4D decay_intensity; // [^0, ^1, ^2, intensity]
QVector4D angles; // [start, cos(start), end, cos(end)]
GLfloat size = 0.1f;
GLfloat flags = 0;
GLfloat _align[2];
QGLMap map;
};
struct QGLLightPosition {
QGLLightPosition() { QMatrix4x4().copyDataTo(shadowmatrix); }
QVector4D position;
QVector4D direction;
GLfloat shadowmatrix[16];
};
#pragma pack(pop)
void prepareDrawGeom(QOpenGLExtraFunctions * f);
void prepareDrawObj(QOpenGLExtraFunctions * f);
void prepareDrawSel(QOpenGLExtraFunctions * f);
} // namespace QGLEngineShaders
#endif // GLSHADERS_TYPES_H

View File

@@ -1,36 +1,37 @@
/* /*
QGL Texture2DArray QGL Texture2DArray
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "gltexturearray.h" #include "gltexturearray.h"
#include <QOpenGLExtraFunctions>
Texture2DArray::Texture2DArray(bool filter) {
target_ = GL_TEXTURE_2D_ARRAY; Texture2DArray::Texture2DArray(GLenum format, bool filter) {
texture_ = 0; target_ = GL_TEXTURE_2D_ARRAY;
layers_ = 0; format_ = format;
texture_ = 0;
layers_ = 0;
filtering_ = filter; filtering_ = filter;
} }
Texture2DArray::~Texture2DArray() { Texture2DArray::~Texture2DArray() {}
}
void Texture2DArray::init(QOpenGLExtraFunctions * f) { void Texture2DArray::init(QOpenGLExtraFunctions * f) {
@@ -48,6 +49,12 @@ void Texture2DArray::destroy(QOpenGLExtraFunctions * f) {
} }
void Texture2DArray::reinit() {
texture_ = 0;
layers_ = 0;
}
void Texture2DArray::bind(QOpenGLExtraFunctions * f, int channel) { void Texture2DArray::bind(QOpenGLExtraFunctions * f, int channel) {
f->glActiveTexture(GL_TEXTURE0 + channel); f->glActiveTexture(GL_TEXTURE0 + channel);
f->glBindTexture(target_, texture_); f->glBindTexture(target_, texture_);
@@ -62,7 +69,7 @@ void Texture2DArray::release(QOpenGLExtraFunctions * f) {
bool Texture2DArray::resize(QOpenGLExtraFunctions * f, QSize new_size, int layers_count) { bool Texture2DArray::resize(QOpenGLExtraFunctions * f, QSize new_size, int layers_count) {
if (new_size.isNull() || layers_count <= 0) return false; if (new_size.isNull() || layers_count <= 0) return false;
if ((size_ == new_size) && (layers_ >= layers_count)) return false; if ((size_ == new_size) && (layers_ >= layers_count)) return false;
size_ = new_size; size_ = new_size;
layers_ = layers_count; layers_ = layers_count;
f->glBindTexture(target_, texture_); f->glBindTexture(target_, texture_);
f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_REPEAT); f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_REPEAT);
@@ -75,17 +82,26 @@ bool Texture2DArray::resize(QOpenGLExtraFunctions * f, QSize new_size, int layer
f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST); f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
f->glTexParameteri(target_, GL_TEXTURE_MIN_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); GLenum bformat = format_;
GLenum btype = GL_UNSIGNED_BYTE;
if (format_ == GL_R16F || format_ == GL_R32F) {
bformat = GL_RED;
btype = GL_FLOAT;
}
if (format_ == GL_DEPTH_COMPONENT || format_ == GL_DEPTH_COMPONENT16 || format_ == GL_DEPTH_COMPONENT24 ||
format_ == GL_DEPTH_COMPONENT32) {
bformat = GL_DEPTH_COMPONENT;
}
f->glTexImage3D(target_, 0, format_, size_.width(), size_.height(), layers_, 0, bformat, btype, nullptr);
return true; return true;
} }
void Texture2DArray::load(QOpenGLExtraFunctions * f, const QImage & image, int layer) { void Texture2DArray::load(QOpenGLExtraFunctions * f, const QImage & image, int layer) {
if (image.isNull() || size_.isNull() || layer < 0 || layer >= layers_) return; if (image.isNull() || size_.isNull() || layer < 0 || layer >= layers_) return;
QImage im = image.mirrored(false, true) QImage im =
.scaled(size_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation) image.mirrored(false, true).scaled(size_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).convertToFormat(QImage::Format_RGBA8888);
.convertToFormat(QImage::Format_RGBA8888); // qDebug() << "Texture2DArray::load image" << image.size() << "to layer" << layer;
//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()); f->glTexSubImage3D(target_, 0, 0, 0, layer, size_.width(), size_.height(), 1, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
} }

View File

@@ -0,0 +1,55 @@
/*
QGL Texture2DArray
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 QGLENGINE_CORE_EXPORT Texture2DArray {
public:
Texture2DArray(GLenum format, bool filter);
~Texture2DArray();
void init(QOpenGLExtraFunctions * f);
void destroy(QOpenGLExtraFunctions * f);
void reinit();
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; }
int layersCount() const { return layers_; }
private:
GLenum target_, format_;
GLuint texture_;
QSize size_;
int layers_;
bool filtering_;
};
#endif // GLTEXTUREARRAY_H

View File

@@ -1,36 +1,50 @@
/* /*
QGL Transform QGL Transform
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "gltransform.h" #include "gltransform.h"
#include "gltypes.h" #include "gltypes.h"
#include <cmath> #include <cmath>
inline void composeQMatrix4x4(const QVector3D & position, const QVector3D & orientation, const QVector3D & scale, QMatrix4x4 &m) { inline void composeQMatrix4x4(const QVector3D & position, const QVector3D & orientation, const QVector3D & scale, QMatrix4x4 & m) {
const QMatrix3x3 rot3x3(Transform::toRotationMatrix(orientation)); const QMatrix3x3 rot3x3(Transform::toRotationMatrix(orientation));
// set up final matrix with scale, rotation and translation // set up final matrix with scale, rotation and translation
m(0, 0) = scale.x() * rot3x3(0, 0); m(0, 1) = scale.y() * rot3x3(0, 1); m(0, 2) = scale.z() * rot3x3(0, 2); m(0, 3) = position.x(); m(0, 0) = scale.x() * rot3x3(0, 0);
m(1, 0) = scale.x() * rot3x3(1, 0); m(1, 1) = scale.y() * rot3x3(1, 1); m(1, 2) = scale.z() * rot3x3(1, 2); m(1, 3) = position.y(); m(0, 1) = scale.y() * rot3x3(0, 1);
m(2, 0) = scale.x() * rot3x3(2, 0); m(2, 1) = scale.y() * rot3x3(2, 1); m(2, 2) = scale.z() * rot3x3(2, 2); m(2, 3) = position.z(); m(0, 2) = scale.z() * rot3x3(0, 2);
m(0, 3) = position.x();
m(1, 0) = scale.x() * rot3x3(1, 0);
m(1, 1) = scale.y() * rot3x3(1, 1);
m(1, 2) = scale.z() * rot3x3(1, 2);
m(1, 3) = position.y();
m(2, 0) = scale.x() * rot3x3(2, 0);
m(2, 1) = scale.y() * rot3x3(2, 1);
m(2, 2) = scale.z() * rot3x3(2, 2);
m(2, 3) = position.z();
// no projection term // no projection term
m(3, 0) = 0.0f; m(3, 1) = 0.0f; m(3, 2) = 0.0f; m(3, 3) = 1.0f; m(3, 0) = 0.0f;
m(3, 1) = 0.0f;
m(3, 2) = 0.0f;
m(3, 3) = 1.0f;
} }
inline void decomposeQMatrix3x3(const QMatrix3x3 & m, QMatrix3x3 & Q, QVector3D & D, QVector3D & U) { inline void decomposeQMatrix3x3(const QMatrix3x3 & m, QMatrix3x3 & Q, QVector3D & D, QVector3D & U) {
@@ -62,24 +76,24 @@ inline void decomposeQMatrix3x3(const QMatrix3x3 & m, QMatrix3x3 & Q, QVector3D
// build orthogonal matrix Q // build orthogonal matrix Q
float invLen = 1.0f / std::sqrt(m(0, 0) * m(0, 0) + m(1, 0) * m(1, 0) + m(2, 0) * m(2, 0)); float invLen = 1.0f / std::sqrt(m(0, 0) * m(0, 0) + m(1, 0) * m(1, 0) + m(2, 0) * m(2, 0));
Q(0, 0) = m(0, 0) * invLen; Q(0, 0) = m(0, 0) * invLen;
Q(1, 0) = m(1, 0) * invLen; Q(1, 0) = m(1, 0) * invLen;
Q(2, 0) = m(2, 0) * invLen; Q(2, 0) = m(2, 0) * invLen;
float dot = Q(0, 0) * m(0, 1) + Q(1, 0) * m(1, 1) + Q(2, 0) * m(2, 1); float dot = Q(0, 0) * m(0, 1) + Q(1, 0) * m(1, 1) + Q(2, 0) * m(2, 1);
Q(0, 1) = m(0, 1) - dot * Q(0, 0); Q(0, 1) = m(0, 1) - dot * Q(0, 0);
Q(1, 1) = m(1, 1) - dot * Q(1, 0); Q(1, 1) = m(1, 1) - dot * Q(1, 0);
Q(2, 1) = m(2, 1) - dot * Q(2, 0); Q(2, 1) = m(2, 1) - dot * Q(2, 0);
invLen = 1.0f / std::sqrt(Q(0, 1) * Q(0, 1) + Q(1, 1) * Q(1, 1) + Q(2, 1) * Q(2, 1)); invLen = 1.0f / std::sqrt(Q(0, 1) * Q(0, 1) + Q(1, 1) * Q(1, 1) + Q(2, 1) * Q(2, 1));
Q(0, 1) *= invLen; Q(0, 1) *= invLen;
Q(1, 1) *= invLen; Q(1, 1) *= invLen;
Q(2, 1) *= invLen; Q(2, 1) *= invLen;
dot = Q(0, 0) * m(0, 2) + Q(1, 0) * m(1, 2) + Q(2, 0) * m(2, 2); dot = Q(0, 0) * m(0, 2) + Q(1, 0) * m(1, 2) + Q(2, 0) * m(2, 2);
Q(0, 2) = m(0, 2) - dot * Q(0, 0); Q(0, 2) = m(0, 2) - dot * Q(0, 0);
Q(1, 2) = m(1, 2) - dot * Q(1, 0); Q(1, 2) = m(1, 2) - dot * Q(1, 0);
Q(2, 2) = m(2, 2) - dot * Q(2, 0); Q(2, 2) = m(2, 2) - dot * Q(2, 0);
dot = Q(0, 1) * m(0, 2) + Q(1, 1) * m(1, 2) + Q(2, 1) * m(2, 2); dot = Q(0, 1) * m(0, 2) + Q(1, 1) * m(1, 2) + Q(2, 1) * m(2, 2);
Q(0, 2) -= dot * Q(0, 1); Q(0, 2) -= dot * Q(0, 1);
Q(1, 2) -= dot * Q(1, 1); Q(1, 2) -= dot * Q(1, 1);
Q(2, 2) -= dot * Q(2, 1); Q(2, 2) -= dot * Q(2, 1);
@@ -89,11 +103,9 @@ inline void decomposeQMatrix3x3(const QMatrix3x3 & m, QMatrix3x3 & Q, QVector3D
Q(2, 2) *= invLen; Q(2, 2) *= invLen;
// guarantee that orthogonal matrix has determinant 1 (no reflections) // guarantee that orthogonal matrix has determinant 1 (no reflections)
const float det = Q(0, 0) * Q(1, 1) * Q(2, 2) + Q(0, 1) * Q(1, 2) * Q(2, 0) + const float det = Q(0, 0) * Q(1, 1) * Q(2, 2) + Q(0, 1) * Q(1, 2) * Q(2, 0) + Q(0, 2) * Q(1, 0) * Q(2, 1) -
Q(0, 2) * Q(1, 0) * Q(2, 1) - Q(0, 2) * Q(1, 1) * Q(2, 0) - Q(0, 2) * Q(1, 1) * Q(2, 0) - Q(0, 1) * Q(1, 0) * Q(2, 2) - Q(0, 0) * Q(1, 2) * Q(2, 1);
Q(0, 1) * Q(1, 0) * Q(2, 2) - Q(0, 0) * Q(1, 2) * Q(2, 1); if (det < 0.0f) Q *= -1.0f;
if (det < 0.0f)
Q *= -1.0f;
// build "right" matrix R // build "right" matrix R
QMatrix3x3 R(Qt::Uninitialized); QMatrix3x3 R(Qt::Uninitialized);
@@ -105,30 +117,26 @@ inline void decomposeQMatrix3x3(const QMatrix3x3 & m, QMatrix3x3 & Q, QVector3D
R(2, 2) = Q(0, 2) * m(0, 2) + Q(1, 2) * m(1, 2) + Q(2, 2) * m(2, 2); R(2, 2) = Q(0, 2) * m(0, 2) + Q(1, 2) * m(1, 2) + Q(2, 2) * m(2, 2);
// the scaling component // the scaling component
D[0] = R(0, 0); D[0] = R(0, 0);
D[1] = R(1, 1); D[1] = R(1, 1);
D[2] = R(2, 2); D[2] = R(2, 2);
// the shear component // the shear component
U[0] = R(0, 1) / D[0]; U[0] = R(0, 1) / D[0];
U[1] = R(0, 2) / D[0]; U[1] = R(0, 2) / D[0];
U[2] = R(1, 2) / D[1]; U[2] = R(1, 2) / D[1];
} }
inline bool hasScale(const QMatrix4x4 &m) { inline bool hasScale(const QMatrix4x4 & m) {
// If the columns are orthonormal and form a right-handed system, then there is no scale // If the columns are orthonormal and form a right-handed system, then there is no scale
float t(m.determinant()); float t(m.determinant());
if (!qFuzzyIsNull(t - 1.0f)) if (!qFuzzyIsNull(t - 1.0f)) return true;
return true;
t = m(0, 0) * m(0, 0) + m(1, 0) * m(1, 0) + m(2, 0) * m(2, 0); t = m(0, 0) * m(0, 0) + m(1, 0) * m(1, 0) + m(2, 0) * m(2, 0);
if (!qFuzzyIsNull(t - 1.0f)) if (!qFuzzyIsNull(t - 1.0f)) return true;
return true;
t = m(0, 1) * m(0, 1) + m(1, 1) * m(1, 1) + m(2, 1) * m(2, 1); t = m(0, 1) * m(0, 1) + m(1, 1) * m(1, 1) + m(2, 1) * m(2, 1);
if (!qFuzzyIsNull(t - 1.0f)) if (!qFuzzyIsNull(t - 1.0f)) return true;
return true;
t = m(0, 2) * m(0, 2) + m(1, 2) * m(1, 2) + m(2, 2) * m(2, 2); t = m(0, 2) * m(0, 2) + m(1, 2) * m(1, 2) + m(2, 2) * m(2, 2);
if (!qFuzzyIsNull(t - 1.0f)) if (!qFuzzyIsNull(t - 1.0f)) return true;
return true;
return false; return false;
} }
@@ -142,64 +150,57 @@ inline void decomposeQMatrix4x4(const QMatrix4x4 & m, QVector3D & position, QVec
decomposeQMatrix3x3(m3x3, rot3x3, scale, position); decomposeQMatrix3x3(m3x3, rot3x3, scale, position);
} else { } else {
// we know there is no scaling part; no need for QDU decomposition // we know there is no scaling part; no need for QDU decomposition
scale = QVector3D(1.0f, 1.0f, 1.0f); scale = QVector3D(1.0f, 1.0f, 1.0f);
rot3x3 = m3x3; rot3x3 = m3x3;
} }
orientation = Transform::fromRotationMatrix(rot3x3); orientation = Transform::fromRotationMatrix(rot3x3);
position = QVector3D(m(0, 3), m(1, 3), m(2, 3)); position = QVector3D(m(0, 3), m(1, 3), m(2, 3));
} }
Transform::Transform(): m_scale(1.0f, 1.0f, 1.0f), m_translation(), m_eulerRotationAngles(), m_matrixDirty(false) {}
Transform::Transform(): m_scale(1.0f, 1.0f, 1.0f), Transform & Transform::operator=(const Transform & t) {
m_translation(), m_eulerRotationAngles(), m_matrixDirty(false) { m_scale = t.m_scale;
} m_translation = t.m_translation;
Transform & Transform::operator =(const Transform & t) {
m_scale = t.m_scale;
m_translation = t.m_translation;
m_eulerRotationAngles = t.m_eulerRotationAngles; m_eulerRotationAngles = t.m_eulerRotationAngles;
m_matrixDirty = true; m_matrixDirty = true;
return *this; return *this;
} }
void Transform::setMatrix(const QMatrix4x4 & m) { void Transform::setMatrix(const QMatrix4x4 & m) {
if (m != matrix()) { if (m != matrix()) {
m_matrix = m; m_matrix = m;
m_matrixDirty = false; m_matrixDirty = false;
QVector3D s; QVector3D s;
QVector3D t; QVector3D t;
QVector3D r; QVector3D r;
decomposeQMatrix4x4(m, t, r, s); decomposeQMatrix4x4(m, t, r, s);
m_scale = s; m_scale = s;
m_translation = t; m_translation = t;
m_eulerRotationAngles = r; m_eulerRotationAngles = r;
} }
} }
void Transform::setRotationX(float r) { void Transform::setRotationX(float r) {
if (m_eulerRotationAngles.x() == r) if (m_eulerRotationAngles.x() == r) return;
return;
m_eulerRotationAngles.setX(r); m_eulerRotationAngles.setX(r);
m_matrixDirty = true; m_matrixDirty = true;
} }
void Transform::setRotationY(float r) { void Transform::setRotationY(float r) {
if (m_eulerRotationAngles.y() == r) if (m_eulerRotationAngles.y() == r) return;
return;
m_eulerRotationAngles.setY(r); m_eulerRotationAngles.setY(r);
m_matrixDirty = true; m_matrixDirty = true;
} }
void Transform::setRotationZ(float r) { void Transform::setRotationZ(float r) {
if (m_eulerRotationAngles.z() == r) if (m_eulerRotationAngles.z() == r) return;
return;
m_eulerRotationAngles.setZ(r); m_eulerRotationAngles.setZ(r);
m_matrixDirty = true; m_matrixDirty = true;
} }
@@ -230,7 +231,7 @@ QMatrix4x4 Transform::matrixRotateScale() const {
QVector3D Transform::direction() const { QVector3D Transform::direction() const {
return matrixRotate().mapVector(QVector3D(0,0,-1)).normalized(); return matrixRotate().mapVector(QVector3D(0, 0, -1)).normalized();
} }
@@ -238,7 +239,7 @@ void Transform::buildMatrix() const {
if (m_matrixDirty) { if (m_matrixDirty) {
composeQMatrix4x4(m_translation, m_eulerRotationAngles, m_scale, m_matrix); composeQMatrix4x4(m_translation, m_eulerRotationAngles, m_scale, m_matrix);
composeQMatrix4x4(QVector3D(), m_eulerRotationAngles, m_scale, m_matrixWT); composeQMatrix4x4(QVector3D(), m_eulerRotationAngles, m_scale, m_matrixWT);
composeQMatrix4x4(QVector3D(), m_eulerRotationAngles, QVector3D(1,1,1), m_matrixR); composeQMatrix4x4(QVector3D(), m_eulerRotationAngles, QVector3D(1, 1, 1), m_matrixR);
composeQMatrix4x4(QVector3D(), QVector3D(), m_scale, m_matrixS); composeQMatrix4x4(QVector3D(), QVector3D(), m_scale, m_matrixS);
m_matrixDirty = false; m_matrixDirty = false;
} }
@@ -262,7 +263,7 @@ float Transform::rotationZ() const {
void Transform::setScale(const QVector3D & s) { void Transform::setScale(const QVector3D & s) {
if (s != m_scale) { if (s != m_scale) {
m_scale = s; m_scale = s;
m_matrixDirty = true; m_matrixDirty = true;
} }
} }
@@ -305,7 +306,7 @@ float Transform::scale() const {
void Transform::setRotation(const QVector3D & r) { void Transform::setRotation(const QVector3D & r) {
if (r != m_eulerRotationAngles) { if (r != m_eulerRotationAngles) {
m_eulerRotationAngles = r; m_eulerRotationAngles = r;
m_matrixDirty = true; m_matrixDirty = true;
} }
} }
@@ -362,17 +363,19 @@ QQuaternion Transform::fromAxisAndAngle(float x, float y, float z, float angle)
} }
QQuaternion Transform::fromAxesAndAngles(const QVector3D & axis1, float angle1, QQuaternion Transform::fromAxesAndAngles(const QVector3D & axis1, float angle1, const QVector3D & axis2, float angle2) {
const QVector3D & axis2, float angle2) {
const QQuaternion q1 = QQuaternion::fromAxisAndAngle(axis1, angle1); const QQuaternion q1 = QQuaternion::fromAxisAndAngle(axis1, angle1);
const QQuaternion q2 = QQuaternion::fromAxisAndAngle(axis2, angle2); const QQuaternion q2 = QQuaternion::fromAxisAndAngle(axis2, angle2);
return q2 * q1; return q2 * q1;
} }
QQuaternion Transform::fromAxesAndAngles(const QVector3D & axis1, float angle1, QQuaternion Transform::fromAxesAndAngles(const QVector3D & axis1,
const QVector3D & axis2, float angle2, float angle1,
const QVector3D & axis3, float angle3) { const QVector3D & axis2,
float angle2,
const QVector3D & axis3,
float angle3) {
const QQuaternion q1 = QQuaternion::fromAxisAndAngle(axis1, angle1); const QQuaternion q1 = QQuaternion::fromAxisAndAngle(axis1, angle1);
const QQuaternion q2 = QQuaternion::fromAxisAndAngle(axis2, angle2); const QQuaternion q2 = QQuaternion::fromAxisAndAngle(axis2, angle2);
const QQuaternion q3 = QQuaternion::fromAxisAndAngle(axis3, angle3); const QQuaternion q3 = QQuaternion::fromAxisAndAngle(axis3, angle3);
@@ -398,16 +401,16 @@ QVector3D Transform::fromDirection(QVector3D d, float pitch) {
QVector3D Transform::fromRotationMatrix(const QMatrix3x3 & m) { QVector3D Transform::fromRotationMatrix(const QMatrix3x3 & m) {
float sy = sqrt(m(0,0) * m(0,0) + m(1,0) * m(1,0)); float sy = sqrt(m(0, 0) * m(0, 0) + m(1, 0) * m(1, 0));
bool singular = sy < 1.E-6; // If bool singular = sy < 1.E-6; // If
float x, y, z; float x, y, z;
if (!singular) { if (!singular) {
x = atan2( m(2,1), m(2,2)); x = atan2(m(2, 1), m(2, 2));
y = atan2(-m(2,0), sy); y = atan2(-m(2, 0), sy);
z = atan2( m(1,0), m(0,0)); z = atan2(m(1, 0), m(0, 0));
} else { } else {
x = atan2(-m(1,2), m(1,1)); x = atan2(-m(1, 2), m(1, 1));
y = atan2(-m(2,0), sy); y = atan2(-m(2, 0), sy);
z = 0.; z = 0.;
} }
return QVector3D(x, y, z) * rad2deg; return QVector3D(x, y, z) * rad2deg;
@@ -419,7 +422,7 @@ QMatrix3x3 Transform::toRotationMatrix(const QVector3D & r) {
if (r.z() != 0.f) m.rotate(r.z(), 0., 0., 1.); if (r.z() != 0.f) m.rotate(r.z(), 0., 0., 1.);
if (r.y() != 0.f) m.rotate(r.y(), 0., 1., 0.); if (r.y() != 0.f) m.rotate(r.y(), 0., 1., 0.);
if (r.x() != 0.f) m.rotate(r.x(), 1., 0., 0.); if (r.x() != 0.f) m.rotate(r.x(), 1., 0., 0.);
return m.toGenericMatrix<3,3>(); return m.toGenericMatrix<3, 3>();
} }
@@ -433,8 +436,20 @@ QMatrix4x4 Transform::rotateAround(const QVector3D & point, float angle, const Q
QMatrix4x4 Transform::rotateFromAxes(const QVector3D & xAxis, const QVector3D & yAxis, const QVector3D & zAxis) { QMatrix4x4 Transform::rotateFromAxes(const QVector3D & xAxis, const QVector3D & yAxis, const QVector3D & zAxis) {
return QMatrix4x4(xAxis.x(), yAxis.x(), zAxis.x(), 0.0f, return QMatrix4x4(xAxis.x(),
xAxis.y(), yAxis.y(), zAxis.y(), 0.0f, yAxis.x(),
xAxis.z(), yAxis.z(), zAxis.z(), 0.0f, zAxis.x(),
0.0f, 0.0f, 0.0f, 1.0f); 0.0f,
xAxis.y(),
yAxis.y(),
zAxis.y(),
0.0f,
xAxis.z(),
yAxis.z(),
zAxis.z(),
0.0f,
0.0f,
0.0f,
0.0f,
1.0f);
} }

View File

@@ -1,35 +1,38 @@
/* /*
QGL Transform QGL Transform
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef GLTRANSFORM_H #ifndef GLTRANSFORM_H
#define GLTRANSFORM_H #define GLTRANSFORM_H
#include "qglengine_core_export.h"
#include <QMatrix4x4> #include <QMatrix4x4>
#include <QQuaternion> #include <QQuaternion>
#include <QVector3D> #include <QVector3D>
#include <chunkstream.h> #include <chunkstream.h>
class Transform { class QGLENGINE_CORE_EXPORT Transform {
friend QDataStream & operator >>(QDataStream & s, Transform & v); friend QDataStream & operator>>(QDataStream & s, Transform & v);
public: public:
Transform(); Transform();
Transform & operator =(const Transform & t); Transform & operator=(const Transform & t);
float scale() const; float scale() const;
QVector3D scale3D() const; QVector3D scale3D() const;
@@ -45,7 +48,7 @@ public:
float rotationY() const; float rotationY() const;
float rotationZ() const; float rotationZ() const;
void setScale(float s) {setScale(QVector3D(s, s, s));} void setScale(float s) { setScale(QVector3D(s, s, s)); }
void setScale(const QVector3D & s); void setScale(const QVector3D & s);
void setScaleX(float s); void setScaleX(float s);
void setScaleY(float s); void setScaleY(float s);
@@ -62,17 +65,15 @@ public:
void setTranslationZ(float t); void setTranslationZ(float t);
void setMatrix(const QMatrix4x4 & matrix); void setMatrix(const QMatrix4x4 & matrix);
void setDirty(bool yes = true) {m_matrixDirty = yes;} void setDirty(bool yes = true) { m_matrixDirty = yes; }
static QQuaternion fromAxisAndAngle(const QVector3D & axis, float angle); static QQuaternion fromAxisAndAngle(const QVector3D & axis, float angle);
static QQuaternion fromAxisAndAngle(float x, float y, float z, float angle); static QQuaternion fromAxisAndAngle(float x, float y, float z, float angle);
static QQuaternion fromAxesAndAngles(const QVector3D & axis1, float angle1, static QQuaternion fromAxesAndAngles(const QVector3D & axis1, float angle1, const QVector3D & axis2, float angle2);
const QVector3D & axis2, float angle2); static QQuaternion
static QQuaternion fromAxesAndAngles(const QVector3D & axis1, float angle1, fromAxesAndAngles(const QVector3D & axis1, float angle1, const QVector3D & axis2, float angle2, const QVector3D & axis3, float angle3);
const QVector3D & axis2, float angle2,
const QVector3D & axis3, float angle3);
static QQuaternion fromAxes(const QVector3D & xAxis, const QVector3D & yAxis, const QVector3D & zAxis); static QQuaternion fromAxes(const QVector3D & xAxis, const QVector3D & yAxis, const QVector3D & zAxis);
static QVector3D fromDirection(QVector3D d, float pitch = 0.f); static QVector3D fromDirection(QVector3D d, float pitch = 0.f);
@@ -91,14 +92,14 @@ protected:
mutable QMatrix4x4 m_matrix, m_matrixWT, m_matrixR, m_matrixS; mutable QMatrix4x4 m_matrix, m_matrixWT, m_matrixR, m_matrixS;
mutable bool m_matrixDirty; mutable bool m_matrixDirty;
}; };
inline QDataStream & operator <<(QDataStream & s, const Transform & v) { inline QDataStream & operator<<(QDataStream & s, const Transform & v) {
s << v.matrix(); return s; s << v.matrix();
return s;
} }
inline QDataStream & operator >>(QDataStream & s, Transform & v) { inline QDataStream & operator>>(QDataStream & s, Transform & v) {
QMatrix4x4 m; QMatrix4x4 m;
s >> m; s >> m;
v.setMatrix(m); v.setMatrix(m);

View File

@@ -1,26 +1,27 @@
/* /*
QGLView Types QGLView Types
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "glcamera.h" #include "glcamera.h"
#include "qglview.h"
#include "gltexture_manager.h" #include "gltexture_manager.h"
#include "qglview.h"
#include <QPainter> #include <QPainter>
#include <QRandomGenerator>
QString readCharsUntilNull(QDataStream & s) { QString readCharsUntilNull(QDataStream & s) {
@@ -37,15 +38,14 @@ QString readCharsUntilNull(QDataStream & s) {
QString findFile(const QString & file, const QStringList & pathes) { QString findFile(const QString & file, const QStringList & pathes) {
QFileInfo fi(QString(file).replace("\\", "/")); QFileInfo fi(QString(file).replace("\\", "/"));
//qDebug() << "search" << file << "in" << pathes; // qDebug() << "search" << file << "in" << pathes;
if (fi.exists()) return fi.absoluteFilePath(); if (fi.exists()) return fi.absoluteFilePath();
QString fn = fi.fileName(); QString fn = fi.fileName();
if (fn.contains("/")) fn = fn.mid(fn.lastIndexOf("/")); if (fn.contains("/")) fn = fn.mid(fn.lastIndexOf("/"));
foreach (QString p, pathes) { foreach(QString p, pathes) {
QFileInfoList fil = QDir(p).entryInfoList(QStringList(fn), QDir::Files | QDir::NoDotAndDotDot); QFileInfoList fil = QDir(p).entryInfoList(QStringList(fn), QDir::Files | QDir::NoDotAndDotDot);
//qDebug() << "findFile" << fn << "in" << p << "->" << fil.size(); // qDebug() << "findFile" << fn << "in" << p << "->" << fil.size();
if (!fil.isEmpty()) if (!fil.isEmpty()) return fil[0].absoluteFilePath();
return fil[0].absoluteFilePath();
} }
return QString(); return QString();
} }
@@ -55,21 +55,28 @@ void glDrawQuad(QOpenGLShaderProgram * prog, QVector4D * corner_dirs, GLfloat x,
glSetPolygonMode(GL_FILL); glSetPolygonMode(GL_FILL);
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
int loc = prog ? prog->attributeLocation("qgl_Color") : -1, // glColor4f(1, 1, 1, 1);
locv = prog ? prog->attributeLocation("qgl_Vertex") : -1, int loc = prog ? prog->attributeLocation("qgl_Color") : -1, locv = prog ? prog->attributeLocation("qgl_Vertex") : -1,
loct = prog ? prog->attributeLocation("qgl_Texture") : -1, loct = prog ? prog->attributeLocation("qgl_Texture") : -1, locc = prog ? prog->attributeLocation("view_corner") : -1;
locc = prog ? prog->attributeLocation("view_corner") : -1;
QOpenGLFunctions * glFuncs = QOpenGLContext::currentContext()->functions(); QOpenGLFunctions * glFuncs = QOpenGLContext::currentContext()->functions();
if (prog) { 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 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 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}; 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}; 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) { if (corner_dirs) {
vcs[0] = corner_dirs[0].x(); vcs[1] = corner_dirs[0].y(); vcs[2] = corner_dirs[0].z(); vcs[0] = corner_dirs[0].x();
vcs[3] = corner_dirs[1].x(); vcs[4] = corner_dirs[1].y(); vcs[5] = corner_dirs[1].z(); vcs[1] = corner_dirs[0].y();
vcs[6] = corner_dirs[2].x(); vcs[7] = corner_dirs[2].y(); vcs[8] = corner_dirs[2].z(); vcs[2] = corner_dirs[0].z();
vcs[9] = corner_dirs[3].x(); vcs[10] = corner_dirs[3].y(); vcs[11] = corner_dirs[3].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_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
@@ -92,10 +99,14 @@ void glDrawQuad(QOpenGLShaderProgram * prog, QVector4D * corner_dirs, GLfloat x,
} else { } else {
glBegin(GL_TRIANGLE_STRIP); glBegin(GL_TRIANGLE_STRIP);
glColor4f(1.f, 1.f, 1.f, 1.f); glColor4f(1.f, 1.f, 1.f, 1.f);
glTexCoord2f(0.f, 0.f); glVertex2f(x, y); glTexCoord2f(0.f, 0.f);
glTexCoord2f(1.f, 0.f); glVertex2f(x+w, y); glVertex2f(x, y);
glTexCoord2f(0.f, 1.f); glVertex2f(x, y+h); glTexCoord2f(1.f, 0.f);
glTexCoord2f(1.f, 1.f); glVertex2f(x+w, y+h); glVertex2f(x + w, y);
glTexCoord2f(0.f, 1.f);
glVertex2f(x, y + h);
glTexCoord2f(1.f, 1.f);
glVertex2f(x + w, y + h);
glEnd(); glEnd();
} }
} }
@@ -140,15 +151,13 @@ void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, int width, int hei
f->glTexImage2D(target, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr); f->glTexImage2D(target, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr);
else { else {
int type = GL_UNSIGNED_BYTE; int type = GL_UNSIGNED_BYTE;
int fmt = GL_RGBA; int fmt = GL_RGBA;
if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGBA32F || format == GL_RGBA16F) if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGBA32F || format == GL_RGBA16F) type = GL_FLOAT;
type = GL_FLOAT; if (format == GL_RGB32F || format == GL_RGB16F || format == GL_RGB8 || format == GL_RGB) fmt = GL_RGB;
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); f->glTexImage2D(target, 0, format, width, height, 0, fmt, type, nullptr);
//qDebug() << "glTexImage2D" << width << height << QString::number(t, 16); // qDebug() << "glTexImage2D" << width << height << QString::number(t, 16);
} }
//qDebug() << QString::number(glGetError(), 16); // qDebug() << QString::number(glGetError(), 16);
} }
@@ -174,7 +183,7 @@ void createGLTexture(QOpenGLExtraFunctions * f, GLuint & tex, const QImage & ima
if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_3D) { if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_3D) {
f->glGenerateMipmap(target); f->glGenerateMipmap(target);
} }
//qDebug() << target << format << tex << im.width() << im.height() << im.bits() << QString::number(glGetError(), 16); // qDebug() << target << format << tex << im.width() << im.height() << im.bits() << QString::number(glGetError(), 16);
} }
@@ -216,14 +225,15 @@ QImage rotateQImageRight(const QImage & im) {
} }
QColor colorFromString(const QString & str) { QColor colorFromString(const QString & str) {
QString s = str.trimmed(); QString s = str.trimmed();
int i = s.indexOf("\t"); int i = s.indexOf("\t");
float r, g, b; float r, g, b;
r = s.left(i).toFloat(); s = s.right(s.length() - i - 1); i = s.indexOf("\t"); r = s.left(i).toFloat();
g = s.left(i).toFloat(); s = s.right(s.length() - i - 1); 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(); b = s.toFloat();
return QColor(r * 255.f, g * 255.f, b * 255.f); return QColor(r * 255.f, g * 255.f, b * 255.f);
} }
@@ -232,9 +242,12 @@ QColor colorFromString(const QString & str) {
QVector3D orthToVector(const QVector3D & v, const float & scale) { QVector3D orthToVector(const QVector3D & v, const float & scale) {
if (v.isNull()) return QVector3D(); if (v.isNull()) return QVector3D();
QVector3D rv, fn, sn; QVector3D rv, fn, sn;
if (v.x() != 0.f) rv.setZ(1.); if (v.x() != 0.f)
else if (v.y() != 0.f) rv.setX(1.); rv.setZ(1.);
else rv.setY(1.); else if (v.y() != 0.f)
rv.setX(1.);
else
rv.setY(1.);
fn = QVector3D::crossProduct(v, rv).normalized(); fn = QVector3D::crossProduct(v, rv).normalized();
sn = QVector3D::crossProduct(v, fn).normalized(); sn = QVector3D::crossProduct(v, fn).normalized();
return fn * urand(scale) + sn * urand(scale); return fn * urand(scale) + sn * urand(scale);
@@ -268,18 +281,22 @@ void lengthenVector(QVector3D & v, const float & l) {
Vector2i::Vector2i(const QString & str) { Vector2i::Vector2i(const QString & str) {
QString s = str.trimmed(); QString s = str.trimmed();
int i = s.indexOf("\t"); int i = s.indexOf("\t");
p0 = s.left(i).toInt(); s = s.right(s.length() - i - 1); p0 = s.left(i).toInt();
p1 = s.toInt(); s = s.right(s.length() - i - 1);
p1 = s.toInt();
} }
Vector3i::Vector3i(const QString & str) { Vector3i::Vector3i(const QString & str) {
QString s = str.trimmed(); QString s = str.trimmed();
int i = s.indexOf("\t"); int i = s.indexOf("\t");
p0 = s.left(i).toInt(); s = s.right(s.length() - i - 1); i = s.indexOf("\t"); p0 = s.left(i).toInt();
p1 = s.left(i).toInt(); s = s.right(s.length() - i - 1); s = s.right(s.length() - i - 1);
p2 = s.toInt(); i = s.indexOf("\t");
p1 = s.left(i).toInt();
s = s.right(s.length() - i - 1);
p2 = s.toInt();
} }
@@ -305,8 +322,6 @@ void glClearFramebuffer(const QColor & color, bool depth) {
} }
Box3D::Box3D(const QVector<QVector3D> & points) { Box3D::Box3D(const QVector<QVector3D> & points) {
x = y = z = width = length = height = angle_z = angle_xy = angle_roll = 0.f; x = y = z = width = length = height = angle_z = angle_xy = angle_roll = 0.f;
if (points.isEmpty()) return; if (points.isEmpty()) return;
@@ -315,13 +330,16 @@ Box3D::Box3D(const QVector<QVector3D> & points) {
iy = ay = points[0].y(); iy = ay = points[0].y();
iz = az = points[0].z(); iz = az = points[0].z();
for (int i = 1; i < points.size(); ++i) { for (int i = 1; i < points.size(); ++i) {
ix = qMin<float>(ix, points[i].x()); ax = qMax<float>(ax, points[i].x()); ix = qMin<float>(ix, points[i].x());
iy = qMin<float>(iy, points[i].y()); ay = qMax<float>(ay, points[i].y()); ax = qMax<float>(ax, points[i].x());
iz = qMin<float>(iz, points[i].z()); az = qMax<float>(az, points[i].z()); 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; x = ix;
y = iy; y = iy;
z = iz; z = iz;
length = ax - ix; length = ax - ix;
width = ay - iy; width = ay - iy;
height = az - iz; height = az - iz;
@@ -331,32 +349,60 @@ Box3D::Box3D(const QVector<QVector3D> & points) {
QVector<QVector3D> Box3D::corners() const { QVector<QVector3D> Box3D::corners() const {
QVector<QVector3D> ret; QVector<QVector3D> ret;
ret << QVector3D(x, y, z) << QVector3D(x, y + width, z) << QVector3D(x, y, z + height) << QVector3D(x, y + width, z + height) 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) << QVector3D(x + length, y + width, z) << QVector3D(x + length, y, z + height)
<< QVector3D(x + length, y, z + height) << QVector3D(x + length, y + width, z + height); << QVector3D(x + length, y + width, z + height);
return ret; return ret;
} }
Box3D & Box3D::operator |=(const Box3D & o) { Box3D & Box3D::operator|=(const Box3D & o) {
if (o.isEmpty()) return *this; if (o.isEmpty()) return *this;
if (isEmpty()) *this = o; if (isEmpty())
*this = o;
else { else {
GLfloat mx = x + length, my = y + width, mz = z + height; 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; 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); x = qMin(x, o.x);
mx = qMax(mx, omx); my = qMax(my, omy); mz = qMax(mz, omz); y = qMin(y, o.y);
length = mx - x; width = my - y; height = mz - z; 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; return *this;
} }
QVector3D vectorFromString(const QString & str) { QVector3D vectorFromString(const QString & str) {
QTextStream s(const_cast<QString*>(&str), QIODevice::ReadOnly); QTextStream s(const_cast<QString *>(&str), QIODevice::ReadOnly);
QVector3D ret; QVector3D ret;
float f(0.f); float f(0.f);
s >> f; ret.setX(f); s >> f;
s >> f; ret.setY(f); ret.setX(f);
s >> f; ret.setZ(f); s >> f;
ret.setY(f);
s >> f;
ret.setZ(f);
return ret; return ret;
} }
QImage generateNoise(QSize sz) {
QImage im(sz, QImage::Format_ARGB32);
QRandomGenerator rg[2] = {1, 2};
uint pcnt = im.sizeInBytes() / sizeof(QRgb);
QRgb * data = (QRgb *)im.bits();
for (uint i = 0; i < pcnt; ++i) {
double r = rg[0].generateDouble();
double a = rg[0].generateDouble() * M_2PI;
double x = r * cos(a) / 2. + 0.5, y = r * sin(a) / 2. + 0.5;
data[i] = qRgba(qRound(x * 256),
qRound(y * 256),
(rg[1].generate() % sz.width()) % 256,
(rg[1].generate() % sz.height()) % 256); // argb GLSL
}
return im;
}

500
src/core/core/gltypes.h Normal file
View File

@@ -0,0 +1,500 @@
/*
QGLView Types
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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 <QColor>
#include <QDataStream>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QImage>
#include <QMatrix4x4>
#include <QMutex>
#include <QOpenGLExtraFunctions>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QVector2D>
#include <QVector3D>
#include <cmath>
#include <float.h>
#include <qopenglext.h>
#ifndef QNX
# include <cmath>
# include <complex>
#else
# include <complex.h>
# include <math.h>
#endif
#include "pimathbase.h"
#include "qglengine_core_export.h"
#include "qglengine_version.h"
#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 T>
inline void piSwap(T & f, T & s) {
T 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;
}
QGLENGINE_CORE_EXPORT QString readCharsUntilNull(QDataStream & s);
QGLENGINE_CORE_EXPORT 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;
}
QGLENGINE_CORE_EXPORT void glEnableDepth();
QGLENGINE_CORE_EXPORT void glDisableDepth();
QGLENGINE_CORE_EXPORT void glClearFramebuffer(const QColor & color = Qt::black, bool depth = true);
QGLENGINE_CORE_EXPORT 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);
QGLENGINE_CORE_EXPORT void createGLTexture(QOpenGLExtraFunctions * f,
GLuint & tex,
int width,
int height,
const GLenum & format = GL_RGBA,
const GLenum & target = GL_TEXTURE_2D);
QGLENGINE_CORE_EXPORT void createGLTexture(QOpenGLExtraFunctions * f,
GLuint & tex,
const QImage & image,
const GLenum & format = GL_RGBA,
const GLenum & target = GL_TEXTURE_2D);
QGLENGINE_CORE_EXPORT QMatrix4x4 glMatrixPerspective(float angle, float aspect, float near_);
QGLENGINE_CORE_EXPORT QImage rotateQImageLeft(const QImage & im);
QGLENGINE_CORE_EXPORT 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 Framebuffer;
class FramebufferMipmap;
class FramebufferEffectBase;
class VertexObject;
class Mesh;
class Scene;
class RendererBase;
class Renderer;
class RendererMaterial;
class RendererService;
class RendererSelection;
enum RenderPass {
rpSolid,
rpTransparent,
};
typedef QList<ObjectBase *> ObjectBaseList;
struct QGLENGINE_CORE_EXPORT 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 QGLENGINE_CORE_EXPORT 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 QGLENGINE_CORE_EXPORT 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;
}
QGLENGINE_CORE_EXPORT QVector3D vectorFromString(const QString & str);
QGLENGINE_CORE_EXPORT 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 void normalizeAngleRad(float & a) {
while (a < 0.)
a += M_2PI;
while (a >= M_2PI)
a -= M_2PI;
}
inline void normalizeAngleDeg360(float & a) {
while (a < 0.)
a += 360.;
while (a >= 360.)
a -= 360.;
}
inline QVector3D projection(const QVector3D & v, const QVector3D & to) {
return to.normalized() * v.length() * cosABV(v, to);
}
QGLENGINE_CORE_EXPORT QVector3D orthToVector(const QVector3D & v, const float & scale = 1.);
QGLENGINE_CORE_EXPORT QVector3D rotateVector(const QVector3D & v, const QVector3D & a);
QGLENGINE_CORE_EXPORT void setVectorLength(QVector3D & v, const float & l);
QGLENGINE_CORE_EXPORT 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;
}
QImage generateNoise(QSize sz);
#endif // GLTYPES_H

View File

@@ -1,39 +1,37 @@
/* /*
QGL VertexObject QGL VertexObject
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "glvertexobject.h" #include "glvertexobject.h"
#include <QOpenGLExtraFunctions>
using namespace QGLEngineShaders; using namespace QGLEngineShaders;
VertexObject::VertexObject(): VertexObject::VertexObject(): buffer_obj(GL_ARRAY_BUFFER, GL_STREAM_DRAW), buffer_sel(GL_ARRAY_BUFFER, GL_STREAM_DRAW) {
buffer_obj (GL_ARRAY_BUFFER, GL_STREAM_DRAW), vao_ = 0;
buffer_sel (GL_ARRAY_BUFFER, GL_STREAM_DRAW) { buffers_binded = false;
vao_ = 0;
buffers_binded = false;
objects_changed = selected_changed = true; objects_changed = selected_changed = true;
} }
VertexObject::~VertexObject() { VertexObject::~VertexObject() {}
}
void VertexObject::init(QOpenGLExtraFunctions * f) { void VertexObject::init(QOpenGLExtraFunctions * f) {
@@ -55,8 +53,17 @@ void VertexObject::destroy(QOpenGLExtraFunctions * f) {
} }
void VertexObject::reinit() {
vao_ = 0;
buffer_obj.reinit();
buffer_sel.reinit();
buffers_binded = false;
objects_changed = selected_changed = true;
}
void VertexObject::bind(QOpenGLExtraFunctions * f) { void VertexObject::bind(QOpenGLExtraFunctions * f) {
//qDebug() << "bind" << target_ << buffer_; // qDebug() << "bind" << target_ << buffer_;
f->glBindVertexArray(vao_); f->glBindVertexArray(vao_);
} }
@@ -104,6 +111,7 @@ void VertexObject::loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar
void VertexObject::draw(QOpenGLExtraFunctions * f, GLenum geom_type, int vert_cout, int obj_count) { void VertexObject::draw(QOpenGLExtraFunctions * f, GLenum geom_type, int vert_cout, int obj_count) {
if (obj_count <= 0) return;
bind(f); bind(f);
f->glDrawElementsInstanced(geom_type, vert_cout, GL_UNSIGNED_INT, 0, obj_count); f->glDrawElementsInstanced(geom_type, vert_cout, GL_UNSIGNED_INT, 0, obj_count);
release(f); release(f);

View File

@@ -0,0 +1,62 @@
/*
QGL VertexObject
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLVERTEXOBJECT_H
#define GLVERTEXOBJECT_H
#include "glbuffer.h"
#include "glshaders_types.h"
class QGLENGINE_CORE_EXPORT VertexObject {
public:
VertexObject();
~VertexObject();
void init(QOpenGLExtraFunctions * f);
void destroy(QOpenGLExtraFunctions * f);
void reinit();
void bind(QOpenGLExtraFunctions * f);
void release(QOpenGLExtraFunctions * f);
void bindBuffers(QOpenGLExtraFunctions * f, Buffer & geom, Buffer & elem, bool force = false);
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);
void draw(QOpenGLExtraFunctions * f, GLenum geom_type, int vert_cout, int obj_count);
GLuint ID() const { return vao_; }
bool isInit() const { return vao_ != 0; }
bool isObjectsChanged() const { return objects_changed; }
bool isSelectionChanged() const { return selected_changed; }
void setObjectsChanged(bool yes = true) { objects_changed = yes; }
void setSelectionChanged(bool yes = true) { selected_changed = yes; }
private:
void loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size);
GLuint vao_;
Buffer buffer_obj, buffer_sel;
bool buffers_binded, objects_changed, selected_changed;
};
#endif // GLVERTEXOBJECT_H

122
src/core/core/hdr.cpp Normal file
View File

@@ -0,0 +1,122 @@
/*
QGL HDR
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hdr_p.h"
#include <QByteArray>
#include <qmath.h>
#define RGBE_DATA_RED 2
#define RGBE_DATA_GREEN 1
#define RGBE_DATA_BLUE 0
/* number of floats per pixel */
#define RGBE_DATA_SIZE 3
void rgbe2float(float * red, float * green, float * blue, uchar rgbe[4]) {
float f;
if (rgbe[3]) {
f = static_cast<float>(ldexp(1.0, rgbe[3] - (int)(128 + 8)));
*red = rgbe[0] * f;
*green = rgbe[1] * f;
*blue = rgbe[2] * f;
} else
*red = *green = *blue = 0.0;
}
/* simple read routine. will not correctly handle run length encoding */
bool RGBE_ReadPixels(QDataStream * fp, float * data, int numpixels) {
uchar rgbe[4];
while (numpixels-- > 0) {
if (fp->readRawData((char *)rgbe, sizeof(rgbe)) < 1) return false;
rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
data += RGBE_DATA_SIZE;
}
return true;
}
bool RGBE_ReadPixels_RLE(QDataStream * fp, float * data, int scanline_width, int num_scanlines) {
uchar rgbe[4], *ptr, *ptr_end;
int i, count;
uchar buf[2];
QByteArray scanline_buffer;
if ((scanline_width < 8) || (scanline_width > 0x7fff)) /* run length encoding is not allowed so read flat*/
return RGBE_ReadPixels(fp, data, scanline_width * num_scanlines);
scanline_buffer.resize(4 * scanline_width);
/* read in each successive scanline */
while (num_scanlines > 0) {
if (fp->readRawData((char *)rgbe, sizeof(rgbe)) < 1) {
return false;
}
if ((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80)) {
/* this file is not run length encoded */
rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
data += RGBE_DATA_SIZE;
return RGBE_ReadPixels(fp, data, scanline_width * num_scanlines - 1);
}
if ((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width) {
return false;
}
ptr = (uchar *)scanline_buffer.data();
/* read each of the four channels for the scanline into the buffer */
for (i = 0; i < 4; i++) {
ptr_end = (uchar *)scanline_buffer.data() + ((i + 1) * scanline_width);
while (ptr < ptr_end) {
if (fp->readRawData((char *)buf, sizeof(buf[0]) * 2) < 1) {
return false;
}
if (buf[0] > 128) {
/* a run of the same value */
count = buf[0] - 128;
if ((count == 0) || (count > ptr_end - ptr)) {
return false;
}
while (count-- > 0)
*ptr++ = buf[1];
} else {
/* a non-run */
count = buf[0];
if ((count == 0) || (count > ptr_end - ptr)) {
return false;
}
*ptr++ = buf[1];
if (--count > 0) {
if (fp->readRawData((char *)ptr, sizeof(*ptr) * count) < 1) {
return false;
}
ptr += count;
}
}
}
}
/* now convert data from buffer into floats */
for (i = 0; i < scanline_width; i++) {
rgbe[0] = scanline_buffer[i];
rgbe[1] = scanline_buffer[i + scanline_width];
rgbe[2] = scanline_buffer[i + 2 * scanline_width];
rgbe[3] = scanline_buffer[i + 3 * scanline_width];
rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe);
data += RGBE_DATA_SIZE;
}
num_scanlines--;
}
return true;
}

26
src/core/core/hdr_p.h Normal file
View File

@@ -0,0 +1,26 @@
/*
QGL HDR
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HDR_P_H
#define HDR_P_H
#include <QDataStream>
bool RGBE_ReadPixels_RLE(QDataStream * fp, float * data, int scanline_width, int num_scanlines);
#endif // HDR_P_H

View File

@@ -0,0 +1,41 @@
/*
Time mesurer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "measurer.h"
#include <QOpenGLFunctions>
#include <QTextStream>
Measurer::Measurer(QString * output): out(output) {}
Measurer::~Measurer() {}
void Measurer::begin(const QString & name) {
n = name;
et.reset();
}
void Measurer::end() {
glFinish();
auto ms = et.elapsed_m();
QTextStream ts(out);
ts << n << ": " << QString::number(ms, 'f', 2) << " ms\n";
}

44
src/core/core/measurer.h Normal file
View File

@@ -0,0 +1,44 @@
/*
Time mesurer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef measurer_H
#define measurer_H
#include "qglengine_core_export.h"
#include <QString>
#include <pitime.h>
class QGLENGINE_CORE_EXPORT Measurer {
friend class ObjectBase;
public:
Measurer(QString * output);
~Measurer();
void begin(const QString & name);
void end();
private:
PITimeMeasurer et;
QString n, *out;
};
#endif

View File

@@ -0,0 +1,30 @@
/*
QGL Framebuffer effect basic
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "parameteredobject.h"
PIValueTree ParameteredObject::parameters() const {
return params;
}
void ParameteredObject::setParameters(const PIValueTree & p) {
params.applyValues(p);
parametersChanged();
}

View File

@@ -0,0 +1,41 @@
/*
QGL Framebuffer effect basic
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef parameteredobject_H
#define parameteredobject_H
#include "qglengine_core_export.h"
#include <QString>
#include <pivaluetree.h>
class QGLENGINE_CORE_EXPORT ParameteredObject {
public:
virtual ~ParameteredObject() {}
PIValueTree parameters() const;
void setParameters(const PIValueTree & p);
protected:
virtual void parametersChanged() {}
PIValueTree params;
};
#endif

View File

@@ -1,41 +1,52 @@
/* /*
QGL Loader Assimp QGL Loader Assimp
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "loader_assimp.h" #include "loader_assimp.h"
#include "glscene.h"
#include "glmesh.h"
#include "glmaterial.h" #include "glmaterial.h"
#include "glmesh.h"
#include "globject.h" #include "globject.h"
#include "glscene.h"
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/material.h>
#include <assimp/mesh.h>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/mesh.h>
#include <assimp/material.h>
QString fromAiString (const aiString & s) {return QString::fromLocal8Bit(s.C_Str());} QString fromAiString(const aiString & s) {
QColor fromAiColor (const aiColor4D & c) {return QColor::fromRgbF(piClamp(c.r, 0.f, 1.f), piClamp(c.g, 0.f, 1.f), piClamp(c.b, 0.f, 1.f));} return QString::fromLocal8Bit(s.C_Str());
QVector3D fromAiVector3D(const aiVector3D & v) {return QVector3D(v.x, v.y, v.z);} }
Vector3i fromAiFace (const aiFace & v) {return Vector3i(v.mIndices[0], v.mIndices[1], v.mIndices[2]);} QColor fromAiColor(const aiColor4D & c) {
QMatrix4x4 fromAiMatrix4D(const aiMatrix4x4 & v) {return QMatrix4x4(v.a1, v.a2, v.a3, v.a4, return QColor::fromRgbF(piClamp(c.r, 0.f, 1.f), piClamp(c.g, 0.f, 1.f), piClamp(c.b, 0.f, 1.f));
v.b1, v.b2, v.b3, v.b4, }
v.c1, v.c2, v.c3, v.c4, QVector3D fromAiVector3D(const aiVector3D & v) {
v.d1, v.d2, v.d3, v.d4);} return QVector3D(v.x, v.y, v.z);
bool isAiMeshTriangles(const aiMesh * m) {return (m->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) == aiPrimitiveType_TRIANGLE;} }
Vector3i fromAiFace(const aiFace & v) {
return Vector3i(v.mIndices[0], v.mIndices[1], v.mIndices[2]);
}
QMatrix4x4 fromAiMatrix4D(const aiMatrix4x4 & v) {
return QMatrix4x4(v.a1, v.a2, v.a3, v.a4, v.b1, v.b2, v.b3, v.b4, v.c1, v.c2, v.c3, v.c4, v.d1, v.d2, v.d3, v.d4);
}
bool isAiMeshTriangles(const aiMesh * m) {
return (m->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) == aiPrimitiveType_TRIANGLE;
}
Mesh * assimpMesh(const aiMesh * m) { Mesh * assimpMesh(const aiMesh * m) {
@@ -44,9 +55,11 @@ Mesh * assimpMesh(const aiMesh * m) {
Mesh * ret = new Mesh(); Mesh * ret = new Mesh();
int vcnt = m->mNumVertices, tcnt = m->mNumFaces; int vcnt = m->mNumVertices, tcnt = m->mNumFaces;
QVector<QVector3D> & v(ret->vertices()); v.resize(vcnt); QVector<QVector3D> & v(ret->vertices());
QVector<QVector2D> & t(ret->texcoords()); t.resize(vcnt); v.resize(vcnt);
QVector< Vector3i> & ind(ret->indicesTriangles()); QVector<QVector2D> & t(ret->texcoords());
t.resize(vcnt);
QVector<Vector3i> & ind(ret->indicesTriangles());
for (int i = 0; i < vcnt; ++i) for (int i = 0; i < vcnt; ++i)
v[i] = fromAiVector3D(m->mVertices[i]); v[i] = fromAiVector3D(m->mVertices[i]);
@@ -72,12 +85,12 @@ Mesh * assimpMesh(const aiMesh * m) {
ind.resize(tcnt); ind.resize(tcnt);
int si = 0; int si = 0;
for (int i = 0; i < tcnt; ++i) { for (int i = 0; i < tcnt; ++i) {
si = i+i+i; si = i + i + i;
ind[i] = Vector3i(si, si+1, si+2); ind[i] = Vector3i(si, si + 1, si + 2);
} }
} }
//qDebug() << "add mesh" << v.size() << ret->normals().size() << ret->texcoords().size() << ret->indices().size(); // qDebug() << "add mesh" << v.size() << ret->normals().size() << ret->texcoords().size() << ret->indices().size();
return ret; return ret;
} }
@@ -86,7 +99,7 @@ Mesh * assimpMesh(const aiMesh * m) {
QColor aiMatColor(const aiMaterial * m, const char * key, uint s0, uint s1, const QColor & def = Qt::white) { QColor aiMatColor(const aiMaterial * m, const char * key, uint s0, uint s1, const QColor & def = Qt::white) {
aiColor4D col; aiColor4D col;
aiReturn r = m->Get(key, s0, s1, col); aiReturn r = m->Get(key, s0, s1, col);
//qDebug() << key << r << col.r << col.g << col.b; // qDebug() << key << r << col.r << col.g << col.b;
if (r != aiReturn_SUCCESS) return def; if (r != aiReturn_SUCCESS) return def;
return fromAiColor(col); return fromAiColor(col);
} }
@@ -98,36 +111,36 @@ float aiMatFloat(const aiMaterial * m, const char * key, uint s0, uint s1, float
} }
QString aiMatString(const aiMaterial * m, const char * key, uint s0, uint s1) { QString aiMatString(const aiMaterial * m, const char * key, uint s0, uint s1) {
aiString p; aiString p;
aiReturn r = const_cast<aiMaterial*>(m)->Get(key, s0, s1, p); aiReturn r = const_cast<aiMaterial *>(m)->Get(key, s0, s1, p);
//qDebug() << "GetTexture" << key << s0 << r << fromAiString(p); // qDebug() << "GetTexture" << key << s0 << r << fromAiString(p);
if (r != aiReturn_SUCCESS) return QString(); if (r != aiReturn_SUCCESS) return QString();
return fromAiString(p); return fromAiString(p);
} }
Material * assimpMaterial(const aiMaterial * m) { Material * assimpMaterial(const aiMaterial * m) {
if (!m) return 0; if (!m) return 0;
Material * ret = new Material(); Material * ret = new Material();
///WARNING: no function GetName() in aiMaterial in stable release /// WARNING: no function GetName() in aiMaterial in stable release
//ret->name = fromAiString(const_cast<aiMaterial*>(m)->GetName()); // ret->name = fromAiString(const_cast<aiMaterial*>(m)->GetName());
aiString name; aiString name;
const_cast<aiMaterial*>(m)->Get(AI_MATKEY_NAME,name); const_cast<aiMaterial *>(m)->Get(AI_MATKEY_NAME, name);
ret->name = fromAiString(name); ret->name = fromAiString(name);
//qDebug() << "mat" << ret->name; // qDebug() << "mat" << ret->name;
//for (int i = 0; i < m->mNumProperties; ++i) { // for (int i = 0; i < m->mNumProperties; ++i) {
// qDebug()<< fromAiString(m->mProperties[i]->mKey);// << "=" << aiMatFloat(m, m->mProperties[i]->mKey.C_Str(), 0, 0); // qDebug()<< fromAiString(m->mProperties[i]->mKey);// << "=" << aiMatFloat(m, m->mProperties[i]->mKey.C_Str(), 0, 0);
//} // }
ret->color_diffuse = aiMatColor(m, AI_MATKEY_COLOR_DIFFUSE); ret->color_diffuse = aiMatColor(m, AI_MATKEY_COLOR_DIFFUSE);
ret->color_emission = aiMatColor(m, AI_MATKEY_COLOR_EMISSIVE); ret->color_emission = aiMatColor(m, AI_MATKEY_COLOR_EMISSIVE);
float shine = aiMatFloat(m, AI_MATKEY_SHININESS, -1.f); float shine = aiMatFloat(m, AI_MATKEY_SHININESS, -1.f);
if (shine >= 0) { if (shine >= 0) {
ret->map_roughness.color_amount = 0.8f - (shine / 100.f * 0.6f); ret->map_roughness.color_amount = 0.8f - (shine / 100.f * 0.6f);
//qDebug() << "shine" << shine; // qDebug() << "shine" << shine;
} }
ret->map_diffuse .bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_DIFFUSE(0)); ret->map_diffuse.bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_DIFFUSE(0));
ret->map_normal .bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_NORMALS(0)); ret->map_normal.bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_NORMALS(0));
//ret->map_metalness.bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_SPECULAR(0)); // ret->map_metalness.bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_SPECULAR(0));
ret->map_roughness.bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_SHININESS(0)); ret->map_roughness.bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_SHININESS(0));
ret->map_emission .bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_EMISSIVE(0)); ret->map_emission.bitmap_path = aiMatString(m, AI_MATKEY_TEXTURE_EMISSIVE(0));
ret->transparency = 1.f - aiMatFloat(m, AI_MATKEY_OPACITY, 1.f); ret->transparency = 1.f - aiMatFloat(m, AI_MATKEY_OPACITY, 1.f);
ret->detectMaps(); ret->detectMaps();
ret->setTypes(); ret->setTypes();
return ret; return ret;
@@ -136,19 +149,17 @@ Material * assimpMaterial(const aiMaterial * m) {
Light * assimpLight(const aiLight * l) { Light * assimpLight(const aiLight * l) {
if (!l) return 0; if (!l) return 0;
if (l->mType != aiLightSource_POINT && l->mType != aiLightSource_SPOT) if (l->mType != aiLightSource_POINT && l->mType != aiLightSource_SPOT) return 0;
return 0;
Light * ret = new Light(); Light * ret = new Light();
ret->setName(fromAiString(l->mName)); ret->setName(fromAiString(l->mName));
ret->setPos(fromAiVector3D(l->mPosition)); ret->setPos(fromAiVector3D(l->mPosition));
ret->setDirection(fromAiVector3D(l->mDirection)); ret->setDirection(fromAiVector3D(l->mDirection));
ret->decay_const = l->mAttenuationConstant ; ret->decay_const = l->mAttenuationConstant;
ret->decay_linear = l->mAttenuationLinear ; ret->decay_linear = l->mAttenuationLinear;
ret->decay_quadratic = l->mAttenuationQuadratic; ret->decay_quadratic = l->mAttenuationQuadratic;
ret->angle_start = l->mAngleInnerCone * rad2deg; ret->angle_start = l->mAngleInnerCone * rad2deg;
ret->angle_end = l->mAngleOuterCone * rad2deg; ret->angle_end = l->mAngleOuterCone * rad2deg;
if (l->mType == aiLightSource_SPOT) if (l->mType == aiLightSource_SPOT) ret->light_type = Light::Cone;
ret->light_type = Light::Cone;
QVector3D col(l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b); QVector3D col(l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b);
ret->intensity = col.length(); ret->intensity = col.length();
col /= ret->intensity; col /= ret->intensity;
@@ -157,25 +168,28 @@ Light * assimpLight(const aiLight * l) {
} }
ObjectBaseList assimpObject(const aiNode * n, const QVector<Mesh * > & meshes, aiMesh ** ai_meshes, ObjectBaseList assimpObject(const aiNode * n,
const QVector<Material*> & materials, const QVector<Mesh *> & meshes,
const QMap<QString, Light * > & light_by_name, QVector<Light*> & out_lights) { aiMesh ** ai_meshes,
const QVector<Material *> & materials,
const QMap<QString, Light *> & light_by_name,
QVector<Light *> & out_lights) {
if (!n) return ObjectBaseList(); if (!n) return ObjectBaseList();
ObjectBaseList ret; ObjectBaseList ret;
ObjectBase * obj = 0; ObjectBase * obj = 0;
QString name = fromAiString(n->mName); QString name = fromAiString(n->mName);
Light * light = light_by_name.value(name, 0); Light * light = light_by_name.value(name, 0);
if (light) { if (light) {
obj = light->clone(); obj = light->clone();
out_lights << (Light*)obj; out_lights << (Light *)obj;
} else } else
obj = new ObjectBase(); obj = new ObjectBase();
obj->setName(name); obj->setName(name);
obj->setMatrix(fromAiMatrix4D(n->mTransformation)); obj->setMatrix(fromAiMatrix4D(n->mTransformation));
ret << obj; ret << obj;
//qDebug() << "add object" << ret << ret->name(); // qDebug() << "add object" << ret << ret->name();
if (!light) { if (!light) {
//qDebug() << name << "has" << n->mNumMeshes << "meshes"; // qDebug() << name << "has" << n->mNumMeshes << "meshes";
for (uint i = 0; i < n->mNumMeshes; ++i) { for (uint i = 0; i < n->mNumMeshes; ++i) {
int mi = n->mMeshes[i]; int mi = n->mMeshes[i];
if (meshes[mi]) { if (meshes[mi]) {
@@ -185,17 +199,16 @@ ObjectBaseList assimpObject(const aiNode * n, const QVector<Mesh * > & meshes, a
} }
obj->setMesh(meshes[mi]); obj->setMesh(meshes[mi]);
int mati = ai_meshes[mi]->mMaterialIndex; int mati = ai_meshes[mi]->mMaterialIndex;
if (mati >= 0 || mati < materials.size()) if (mati >= 0 || mati < materials.size()) obj->setMaterial(materials[mati]);
obj->setMaterial(materials[mati]); // ret->setMesh(meshes[mi]);
//ret->setMesh(meshes[mi]); // qDebug() << "set mesh" << mi << ret->mesh();
//qDebug() << "set mesh" << mi << ret->mesh(); // break;
//break;
} }
} }
} }
for (uint i = 0; i < n->mNumChildren; ++i) { for (uint i = 0; i < n->mNumChildren; ++i) {
ObjectBaseList cl = assimpObject(n->mChildren[i], meshes, ai_meshes, materials, light_by_name, out_lights); ObjectBaseList cl = assimpObject(n->mChildren[i], meshes, ai_meshes, materials, light_by_name, out_lights);
foreach (ObjectBase * c, cl) foreach(ObjectBase * c, cl)
obj->addChild(c); obj->addChild(c);
} }
@@ -207,38 +220,36 @@ Scene * loadScene(const QString & filepath) {
if (filepath.isEmpty()) return 0; if (filepath.isEmpty()) return 0;
qDebug() << "[Loader Assimp] Import" << filepath << "..."; qDebug() << "[Loader Assimp] Import" << filepath << "...";
Assimp::Importer importer; Assimp::Importer importer;
const aiScene * ais = importer.ReadFile(filepath.toUtf8(), aiProcess_Triangulate | const aiScene * ais =
aiProcess_SortByPType | importer.ReadFile(filepath.toUtf8(),
aiProcess_GenUVCoords | aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_GenUVCoords | aiProcess_TransformUVCoords);
aiProcess_TransformUVCoords);
if (!ais) { if (!ais) {
qDebug() << "[Loader Assimp] Error: \"" + QString(importer.GetErrorString()) + "\""; qDebug() << "[Loader Assimp] Error: \"" + QString(importer.GetErrorString()) + "\"";
return 0; return 0;
} }
qDebug() << "[Loader Assimp] Imported" << ais->mNumMeshes << "meshes"; qDebug() << "[Loader Assimp] Imported" << ais->mNumMeshes << "meshes";
QVector<Mesh * > meshes; QVector<Mesh *> meshes;
for (uint i = 0; i < ais->mNumMeshes; ++i) for (uint i = 0; i < ais->mNumMeshes; ++i)
meshes << assimpMesh(ais->mMeshes[i]); meshes << assimpMesh(ais->mMeshes[i]);
QVector<Material * > materials; QVector<Material *> materials;
for (uint i = 0; i < ais->mNumMaterials; ++i) for (uint i = 0; i < ais->mNumMaterials; ++i)
materials << assimpMaterial(ais->mMaterials[i]); materials << assimpMaterial(ais->mMaterials[i]);
QVector<Light * > lights; QVector<Light *> lights;
for (uint i = 0; i < ais->mNumLights; ++i) for (uint i = 0; i < ais->mNumLights; ++i)
lights << assimpLight(ais->mLights[i]); lights << assimpLight(ais->mLights[i]);
QMap<QString, Light * > light_by_name; QMap<QString, Light *> light_by_name;
foreach (Light * l, lights) foreach(Light * l, lights)
if (l) if (l) light_by_name[l->name()] = l;
light_by_name[l->name()] = l;
QVector<Light*> out_lights; QVector<Light *> out_lights;
ObjectBaseList rootl = assimpObject(ais->mRootNode, meshes, ais->mMeshes, materials, light_by_name, out_lights); ObjectBaseList rootl = assimpObject(ais->mRootNode, meshes, ais->mMeshes, materials, light_by_name, out_lights);
if (rootl.isEmpty()) return 0; if (rootl.isEmpty()) return 0;
ObjectBase * root = rootl[0]; ObjectBase * root = rootl[0];
root->transferTransformToChildren(true); root->transferTransformToChildren(true);
ObjectBaseList rcl = root->children(true); ObjectBaseList rcl = root->children(true);
foreach (ObjectBase * c, rcl) { foreach(ObjectBase * c, rcl) {
foreach (Light * l, out_lights) { foreach(Light * l, out_lights) {
if (c->name() == (l->name() + ".Target")) { if (c->name() == (l->name() + ".Target")) {
l->setDistance((l->worldPos() - c->worldPos()).length()); l->setDistance((l->worldPos() - c->worldPos()).length());
delete c; delete c;
@@ -250,7 +261,7 @@ Scene * loadScene(const QString & filepath) {
Scene * scene = new Scene(); Scene * scene = new Scene();
scene->setName(root->name()); scene->setName(root->name());
foreach (ObjectBase * o, root->children()) foreach(ObjectBase * o, root->children())
scene->addObject(o); scene->addObject(o);
lights.removeAll(nullptr); lights.removeAll(nullptr);
qDeleteAll(lights); qDeleteAll(lights);

View File

@@ -0,0 +1,27 @@
/*
QGL Loader Assimp
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOADER_ASSIMP_H
#define LOADER_ASSIMP_H
#include "gltypes.h"
QGLENGINE_CORE_EXPORT Scene * loadScene(const QString & filepath);
QGLENGINE_CORE_EXPORT QStringList supportedFormats();
#endif // LOADER_ASSIMP_H

View File

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

View File

@@ -0,0 +1,29 @@
/*
QGL Loader QGL
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOADER_QGL_H
#define LOADER_QGL_H
#include "gltypes.h"
#include <QFileInfo>
QGLENGINE_CORE_EXPORT Scene * loadFromQGLFile(const QString & filepath);
QGLENGINE_CORE_EXPORT bool saveToQGLFile(const QString & filepath, const Scene * scene);
#endif // LOADER_QGL_H

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
</TS>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
</TS>

2
src/core/lang/update.bat Normal file
View File

@@ -0,0 +1,2 @@
lupdate ../ -no-obsolete -ts qglengine_core_ru.ts
lupdate ../ -no-obsolete -ts qglengine_core_en.ts

View File

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

View File

@@ -0,0 +1,277 @@
/*
QGL TextureManager
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gltexture_manager.h"
#include "gltexturearray.h"
#include "gltypes.h"
QStringList TextureManager::search_pathes(".");
QVector3D colorVector(QRgb c) {
return QVector3D(((uchar *)(&c))[0] / 255.f, ((uchar *)(&c))[1] / 255.f, ((uchar *)(&c))[2] / 255.f);
}
void TextureManager::addSearchPath(const QString & path) {
if (!search_pathes.contains(path)) search_pathes << path;
}
QString TextureManager::findFile(const QString & path) {
return ::findFile(path, search_pathes);
}
/*
GLuint TextureManager::loadTexture(const QString & path, bool is_normal, MapBakeOptions opts) {
QString p = findFile(path);
if (p.isEmpty()) return 0;
uint hash = mapHash(p, is_normal, opts);
int tid = cache_loaded.value(hash, 0);
if (tid > 0) {
qDebug() << "[TextureManager] Found" << path << "as" << tid;
return tid;
}
QImage image(p);
if (is_normal) convertToNormal(image);
applyBakeOption(image, opts);
// qDebug() << p << image.width() << image.height() << image.format() << is_normal;
GLuint tid_ = tid;
createGLTexture(f, tid_, image);
tid = tid_;
if (tid == 0) {
qDebug() << "[TextureManager] Can`t load" << p;
return tid;
}
qDebug() << "[TextureManager] Loaded" << p << "as" << tid;
tex_ids[is_normal ? 1 : 0].insert(p, tid);
tex_im[is_normal ? 1 : 0].insert(p, image);
return tid;
}
*/
QImage TextureManager::loadTextureImage(const QString & path, bool is_normal, MapBakeOptions opts, uint * result_hash) {
if (result_hash) *result_hash = 0;
if (path.isEmpty()) return QImage();
QString p = findFile(path);
if (p.isEmpty()) {
missed << path;
// p = findFile(path);
// if (p.isEmpty()) return QImage();
return QImage();
}
uint hash = mapHash(p, is_normal, opts);
QImage image = cache_image.value(hash);
if (!image.isNull()) {
if (result_hash) *result_hash = hash;
return image;
}
image = QImage(p).convertToFormat(QImage::Format_ARGB32);
if (image.isNull()) return image;
if (is_normal) convertToNormal(image);
applyBakeOption(image, opts);
cache_image[hash] = image;
if (result_hash) *result_hash = hash;
return image;
}
/*
GLuint TextureManager::loadTexture(const QImage & im, bool ownership, bool is_normal, MapBakeOptions opts) {
if (im.isNull()) return 0;
QImage image(im);
if (is_normal) convertToNormal(image);
applyBakeOption(image, opts);
GLuint tid = 0;
createGLTexture(f, tid, im);
if (tid == 0) {
qDebug() << "[TextureManager] Can`t load image";
return tid;
}
qDebug() << "[TextureManager] Loaded image as" << tid;
return tid;
}
void TextureManager::reloadTexture(GLuint tid, const QString & path) {
QString p = findFile(path);
if (p.isEmpty() || (tid == 0)) return;
QImage image(p);
createGLTexture(f, tid, image);
if (tid == 0) {
qDebug() << "[TextureManager] Can`t load" << p;
return;
}
qDebug() << "[TextureManager] Reloaded" << p << "as" << tid;
}
void TextureManager::reloadTexture(GLuint tid, const QImage & im) {
if (im.isNull() || (tid == 0)) return;
QImage image(im);
createGLTexture(f, tid, image);
qDebug() << "[TextureManager] Reloaded" << tid;
}
*/
int TextureManager::textureID(const QString & path, bool is_normal, MapBakeOptions opts) {
return cache_loaded.value(mapHash(findFile(path), is_normal, opts), 0);
}
QImage TextureManager::textureImage(const QString & path, bool is_normal, MapBakeOptions opts) {
return cache_image.value(mapHash(findFile(path), is_normal, opts));
}
void TextureManager::convertToNormal(QImage & im) {
if (im.isNull()) return;
float sum[3] = {0., 0., 0.};
llong a = 0;
const uchar * sd = im.constBits();
for (int i = 0; i < im.height(); i++) {
for (int j = 0; j < im.width(); j++) {
sum[2] += sd[a] / 255.f - 0.5f;
++a;
sum[1] += sd[a] / 255.f - 0.5f;
++a;
sum[0] += sd[a] / 255.f - 0.5f;
++a;
++a;
}
}
float wh = im.width() * im.height();
sum[0] /= wh;
sum[1] /= wh;
sum[2] /= wh;
// qDebug() << sum[0] << sum[1] << sum[2];
if ((qAbs(sum[0]) <= 0.05f) && (qAbs(sum[1]) <= 0.05f) && (sum[2] >= 0.25f)) /// already normal
return;
// qDebug() << "convert to normal";
QImage dim = QImage(im.width(), im.height(), QImage::Format_ARGB32);
int tx, ty, w = im.width(), h = im.height();
a = 0;
uchar * dd = dim.bits();
for (int i = 0; i < im.height(); i++) {
for (int j = 0; j < im.width(); j++) {
tx = j - 1;
tx = tx < 0 ? w + tx : tx % w;
ty = i - 1;
ty = ty < 0 ? h + ty : ty % h;
QVector3D p[3], res;
p[0] = colorVector(im.pixel(j, i));
p[1] = colorVector(im.pixel(j, ty));
p[2] = colorVector(im.pixel(tx, i));
res.setY(piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f));
res.setX(piClamp(0.5f - (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f));
tx = (j + 1) % w;
ty = (i + 1) % h;
p[1] = colorVector(im.pixel(j, ty));
p[2] = colorVector(im.pixel(tx, i));
res.setY(piClamp(0.5f + (p[0].length() - p[1].length()) / 2.f, 0.f, 1.f));
res.setX(piClamp(0.5f - (p[0].length() - p[2].length()) / 2.f, 0.f, 1.f));
res.setZ(1.f);
dd[a] = res.z() * 255;
++a;
dd[a] = res.y() * 255;
++a;
dd[a] = res.x() * 255;
++a;
dd[a] = 255;
++a;
}
}
im = dim;
// im.save("_normal.png");
}
void TextureManager::applyBakeOption(QImage & im, MapBakeOptions opts) {
if (im.isNull()) return;
if (!opts.invert_R && !opts.invert_G && !opts.invert_B) return;
QRgb * data = (QRgb *)im.bits();
uint pixels = im.width() * im.height();
for (uint i = 0; i < pixels; ++i) {
uchar * p = (uchar *)&(data[i]);
if (opts.invert_B) p[0] = 255 - p[0];
if (opts.invert_G) p[1] = 255 - p[1];
if (opts.invert_R) p[2] = 255 - p[2];
}
}
uint TextureManager::mapHash(const QString & path, bool is_normal, MapBakeOptions opts) {
return qHash(path) ^ ((uint)is_normal << 8) ^ opts.hash();
}
/*
bool TextureManager::loadTextures() {
QFileInfoList fil;
foreach(const QString & i, tex_pathes)
loadTexture(i, true);
tex_pathes.clear();
return true;
}
void TextureManager::deleteTextures() {
for (int i = 0; i < 2; ++i) {
QList<GLuint> texs = tex_ids[i].values();
qDebug() << "[TextureManager] Delete" << texs.size() << "textures";
if (!texs.isEmpty()) f->glDeleteTextures(texs.size(), &texs[0]);
tex_ids[i].clear();
tex_im[i].clear();
}
}
void TextureManager::deleteTexture(const QString & name) {
for (int i = 0; i < 2; ++i) {
if (tex_ids[i].contains(name)) {
GLuint id = tex_ids[i][name];
f->glDeleteTextures(1, &id);
tex_ids[i].remove(name);
tex_im[i].remove(name);
}
}
}
*/
void TextureManager::clearImageCache() {
cache_image.clear();
}
void TextureManager::clearMissed() {
missed.clear();
}
void TextureManager::loadToTexture2DArray(Texture2DArray * array, QSize map_size) {
array->resize(f, map_size, texturesCount());
array_layers.clear();
QMapIterator<uint, QImage> it(cache_image);
int cl = -1;
while (it.hasNext()) {
it.next();
array->load(f, it.value(), ++cl);
array_layers[it.key()] = cl;
}
array->mipmaps(f);
emit filesUsed(texturesCount());
}

View File

@@ -0,0 +1,86 @@
/*
QGL TextureManager
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLTEXTUREMANAGER_H
#define GLTEXTUREMANAGER_H
#include "glmaterial.h"
#include "qglengine_core_export.h"
#include <QDir>
#include <QFileInfo>
#include <QImage>
#include <QMap>
#include <QOpenGLExtraFunctions>
class QGLENGINE_CORE_EXPORT TextureManager: public QObject {
Q_OBJECT
public:
TextureManager(QOpenGLExtraFunctions * f_): f(f_) {}
virtual ~TextureManager() {}
// GLuint loadTexture(const QString & path, bool is_normal = false, MapBakeOptions opts = {});
// GLuint loadTexture(const QImage & image, bool ownership = true, bool is_normal = false, MapBakeOptions opts = {});
QImage loadTextureImage(const QString & path, bool is_normal = false, MapBakeOptions opts = {}, uint * result_hash = nullptr);
// void reloadTexture(GLuint tid, const QString & path);
// void reloadTexture(GLuint tid, const QImage & image);
int textureID(const QString & path, bool is_normal = false, MapBakeOptions opts = {});
QImage textureImage(const QString & path, bool is_normal = false, MapBakeOptions opts = {});
QImage textureImage(uint hash) const { return cache_image.value(hash); }
int textureLayer(uint hash) const { return array_layers.value(hash); }
// void addTexture(const QString & path) { tex_pathes << path; }
// bool loadTextures();
// void deleteTextures();
// void deleteTexture(const QString & name);
int texturesCount() const { return cache_image.size(); }
uint texturesHash() const { return qHash(cache_image.keys()); }
void clearImageCache();
void clearMissed();
const QSet<QString> & missedFiles() const { return missed; }
void loadToTexture2DArray(Texture2DArray * array, QSize map_size);
static void addSearchPath(const QString & path);
static void clearSearchPathes() { search_pathes.clear(); }
static QStringList searchPathes() { return search_pathes; }
static void setSearchPathes(const QStringList & pl) { search_pathes = pl; }
static QString findFile(const QString & path);
protected:
static void convertToNormal(QImage & im);
static void applyBakeOption(QImage & im, MapBakeOptions opts);
static uint mapHash(const QString & path, bool is_normal, MapBakeOptions opts);
static QStringList search_pathes;
QOpenGLExtraFunctions * f;
QMap<uint, GLuint> cache_loaded;
QMap<uint, QImage> cache_image;
QMap<uint, int> array_layers;
QSet<QString> missed;
QStringList tex_pathes;
signals:
void loadingDone();
void filesUsed(int);
};
#endif // GLTEXTUREMANAGER_H

View File

@@ -0,0 +1,748 @@
/*
QGL Renderer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include "renderer.h"
#include "ccm_qglengine_core.h"
#include "glmesh.h"
#include "glshaders.h"
#include "gltexture_manager.h"
#include "qglview.h"
#include <QOpenGLExtraFunctions>
#include <picodeinfo.h>
#include <piiostream.h>
#include <piqt.h>
#include <qad_types.h>
using namespace QGLEngineShaders;
Renderer::Renderer(QGLView * view_)
: RendererBase(view_)
, fbo_ds(view_,
QVector<GLenum>() << GL_RGBA16F << GL_RGBA32F << GL_RGBA16F << GL_RGBA16F << GL_RGBA16F << GL_RGBA16F << GL_RGBA32F
<< GL_RGBA16F)
, fbo_out(view_, obrBuffersCount, false, GL_RGBA16F)
, rend_mat(this)
, rend_service(this)
, rend_selection(this)
, tone_proc(this)
, tex_env(view_, 512) {
mat_norm_to_tex_coord.scale(0.5, 0.5);
mat_norm_to_tex_coord.translate(1, 1);
mat_proj_90 = glMatrixPerspective(90., 1., 0.1);
for (int i = 0; i < 6; ++i) {
QMatrix4x4 fvm;
switch (i) {
case 0:
fvm.rotate(-90., QVector3D(0, 1, 0));
fvm.rotate(180., QVector3D(0, 0, 1));
break;
case 1:
fvm.rotate(90., QVector3D(0, 1, 0));
fvm.rotate(180., QVector3D(0, 0, 1));
break;
case 2: fvm.rotate(-90., QVector3D(1, 0, 0)); break;
case 3: fvm.rotate(90., QVector3D(1, 0, 0)); break;
case 4:
fvm.rotate(180., QVector3D(0, 0, 1));
fvm.rotate(180., QVector3D(0, 1, 0));
break;
case 5: fvm.rotate(180., QVector3D(0, 0, 1)); break;
}
mat_faces[i] = fvm;
}
quad = Primitive::plane(2., 2.);
cam_light = new Light();
cam_light->intensity = 0.75;
cam_light->setName("Camera_Light");
cam_light->setCastShadows(false);
shader_files[srSelectionFill] = "selection.glsl";
shader_files[srSelectionHalo] = "selection_halo.glsl";
shader_files[srSelectionApply] = "selection_apply.glsl";
shader_files[srSelectionFrame] = "selection_frame.glsl";
shader_files[srServiceFill] = "service_fill.glsl";
shader_files[srServiceFrame] = "service_frame.glsl";
shader_files[srServiceLine] = "service_line.glsl";
shader_files[srGeometrySolidPass] = "ds_geom.glsl";
shader_files[srGeometryTransparentPass] = "ds_geom.glsl";
shader_files[srLightOmniPass] = "ds_light.glsl";
shader_files[srLightSpotPass] = "ds_light.glsl";
shader_files[srFinalPass] = "ds_final.glsl";
shader_files[srTonemapPass] = "ds_tonemap.glsl";
shader_files[srShadowConePass] = "shadow.glsl";
shader_files[srShadowOmniPass] = "shadow.glsl";
shader_defines[srGeometrySolidPass] << "SOLID";
shader_defines[srLightSpotPass] << "SPOT";
shader_defines[srShadowOmniPass] << "OMNI";
shader_defines[srLightSpotPass] << "SHADOWS";
shader_defines[srLightOmniPass] << "SHADOWS";
PICodeInfo::EnumInfo * obre = PICodeInfo::enumsInfo->value("Renderer::DeferredBufferRole");
if (obre) {
for (auto e: obre->members) {
obr_defines += "#define " + PI2QString(e.name) + " " + QString::number(e.value) + "\n";
}
}
edit_mode = need_init_shaders = true;
camera_light_mode = QGLView::clmAuto;
}
Renderer::~Renderer() {
delete quad;
delete cam_light;
qDeleteAll(shaders.values());
if (shader_fxaa) delete shader_fxaa;
}
void Renderer::init(int width, int height) {
fbo_ds.reinit();
fbo_out.reinit();
quad->reinit();
buffer_materials.reinit();
buffer_lights.reinit();
buffer_lights_pos.reinit();
textures_maps.reinit();
textures_empty.reinit();
shadow_maps_cone.reinit();
shadow_maps_omni.reinit();
depth_maps_cone.reinit();
depth_maps_omni.reinit();
resize(width, height);
rend_mat.init(width, height);
rend_service.init(width, height);
rend_selection.init(width, height);
tone_proc.init();
initQuad(quad);
initTextureArrays();
initCoeffTextures();
markReloadTextures();
tex_env.init();
if (is_grabbing) fbo_out.enablePixelBuffer();
need_init_shaders = true;
}
void Renderer::resize(int width, int height) {
rend_mat.resize(width, height);
rend_service.resize(width, height);
rend_selection.resize(width, height);
fbo_ds.resize(width, height);
fbo_out.resize(width, height);
tone_proc.resize();
}
void Renderer::reloadShaders() {
__reinit_debug = true;
QMapIterator<ShaderRole, QString> it(shader_files);
qDeleteAll(shaders.values());
shaders.clear();
if (shader_fxaa) delete shader_fxaa;
shader_fxaa = nullptr;
if (tone_proc.shader_sum) delete tone_proc.shader_sum;
tone_proc.shader_sum = nullptr;
QString dir = ":/shaders/";
while (it.hasNext()) {
it.next();
loadShadersMulti(shaders[it.key()], dir + it.value(), true, shader_defines.value(it.key()), obr_defines);
}
loadShadersMulti(tone_proc.shader_sum, dir + "sum.glsl", false);
QStringList fxaa_defs;
fxaa_defs << "FXAA_PC 1"
<< "FXAA_GLSL_130 1"
<< "FXAA_QUALITY__PRESET 15";
loadShaders(shader_fxaa, QStringList() << (dir + "fxaa.vert") << (dir + "fxaa.frag"), true, fxaa_defs);
for (auto * e: fb_effects) {
e->reloadShaders();
e->is_loaded = true;
}
need_init_shaders = true;
view->scene()->setLightsChanged();
view->scene()->setTreeStructChanged();
view->scene()->setMaterialsChanged();
}
bool Renderer::bindShader(Renderer::ShaderRole role, QOpenGLShaderProgram ** ret) {
QOpenGLShaderProgram * prog = shaders.value(role);
if (ret) *ret = prog;
if (!prog) return false;
if (!prog->isLinked()) return false;
prog->bind();
return true;
}
bool Renderer::bindShader(QOpenGLShaderProgram * sp) {
if (!sp) return true;
if (!sp->isLinked()) return true;
if (!sp->bind()) return false;
return true;
}
void Renderer::initShaders() {
if (!need_init_shaders) return;
need_init_shaders = false;
QOpenGLShaderProgram * prog = 0;
for (ShaderRole role: {srLightOmniPass, srLightSpotPass}) {
if (!bindShader(role, &prog)) continue;
initUniformBuffer(prog, &buffer_materials, bpMaterials, "QGLMaterialData");
initUniformBuffer(prog, &buffer_lights, bpLightParameters, "QGLLightParameterData");
initUniformBuffer(prog, &buffer_lights_pos, bpLightPositions, "QGLLightPositionData");
for (int i = 0; i <= 5; ++i)
prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i);
prog->setUniformValue("tex_coeff_brdf", trCoeffBRDF);
prog->setUniformValue("tex_env", trEnvironment);
setUniformMaps(prog);
}
if (bindShader(srFinalPass, &prog)) {
prog->setUniformValue("tex_g1", 0);
prog->setUniformValue("tex_s_0", 1);
prog->setUniformValue("tex_s_1", 2);
prog->setUniformValue("tex_t_0", 3);
prog->setUniformValue("tex_t_1", 4);
}
for (ShaderRole role: {srGeometrySolidPass, srGeometryTransparentPass, srShadowConePass, srShadowOmniPass}) {
if (!bindShader(role, &prog)) continue;
initUniformBuffer(prog, &buffer_materials, bpMaterials, "QGLMaterialData");
setUniformMaps(prog);
}
if (bindShader(srTonemapPass, &prog)) {
prog->setUniformValue("tex_0", 0);
prog->setUniformValue("tex_sum", 1);
}
}
void Renderer::releaseShader() {
view->glUseProgram(0);
}
QVector<int> Renderer::getFreePlanes(int count) {
prev_write_plane = cur_write_plane;
QVector<int> ret;
bool output_done = false;
const int total_count = 4;
for (int i = 0; i < total_count; ++i) {
int plane = obrGeneral0 + i;
if (prev_write_plane == plane) continue;
if (!output_done) {
fbo_out.setWriteBuffer(plane);
cur_write_plane = plane;
output_done = true;
continue;
}
ret << plane;
if (ret.size() == count) break;
}
return ret;
}
void Renderer::fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass) {
cur_objects_.resize(ol.size());
for (int i = 0; i < ol.size(); ++i) {
Object & so(cur_objects_[i]);
ObjectBase * o = ol[i];
if (o->material()) {
so.material = o->material()->_index;
so.color = QVector4D(1, 1, 1, 1);
} else {
so.material = 0;
so.color = QColor2QVector(o->color());
}
so.object_id = o->id();
so.flags = 0;
so.f_accept_light = o->isAcceptLight();
so.f_accept_fog = o->isAcceptFog();
so.f_accept_cast_shadow = o->isCastShadows();
so.f_accept_rec_shadow = o->isReceiveShadows();
o->worldTransform().transposed().copyDataTo(so.modelmatrix);
o->textureGLMatrix().copyDataTo(so.texturematrix);
// qDebug() << "load obj" << o->name() << o->textureMatrix() << tmat;
}
// qDebug() << "fillObjectsBuffer" << ol.size();
}
void Renderer::renderObjects(Scene & scene, RenderPass pass) {
QOpenGLExtraFunctions * f = view;
QMapIterator<Mesh *, ObjectBaseList> it(scene.geometries_used[pass]);
bool emit_pos_change = false;
while (it.hasNext()) {
it.next();
Mesh * mesh = it.key();
if (mesh->isObjectsChanged(pass)) {
mesh->setObjectsChanged(pass, false);
emit_pos_change = true;
fillObjectsBuffer(it.value(), pass);
// qDebug() << "loadObjects" << pass << cur_objects_.size();
mesh->loadObjects(f, cur_objects_, pass);
}
if (mesh->isSelectionChanged(pass) && edit_mode) {
mesh->setSelectionChanged(pass, false);
fillSelectionsBuffer(rend_selection.cur_selections_, it.value());
// qDebug() << "fillSelectionsBuffer" << pass << rend_selection.cur_selections_.size();
mesh->loadSelections(f, rend_selection.cur_selections_, pass);
}
// qDebug() << "draw" << pass << it.value().size();
mesh->draw(f, it.value().size(), pass);
}
if (emit_pos_change) emit view->objectsPositionChanged();
}
void Renderer::renderLight(int first_wr_buff, bool clear_only) {
QOpenGLShaderProgram * prog = 0;
Camera * cam = view->camera();
view->glActiveTexture(GL_TEXTURE0 + trCoeffBRDF);
view->glBindTexture(GL_TEXTURE_2D, tex_coeff[0]);
// tex_env.bind((int)Renderer::dbrBuffersCount + 1);
typedef QPair<Renderer::ShaderRole, Light::Type> PassPair;
QVector<PassPair> passes;
passes << PassPair(srLightOmniPass, Light::Omni) << PassPair(srLightSpotPass, Light::Cone);
QColor back = view->fogColor();
back.setAlpha(0);
foreach(PassPair pass, passes) {
if (bindShader(pass.first, &prog)) {
/*if (pass.second == Light::Cone) {
auto & cone_ll(cur_lights[pass.second]);
for (int i = 0; i < cone_ll.size(); ++i) {
Light * l = cone_ll[i];
// l->shadow_map.bindDepthTexture(mtShadowCone + i);
l->shadow_map.bindColorTexture(0, mtShadowCone + i);
}
}*/
fbo_out.setWriteBuffer(first_wr_buff + pass.second);
glClearFramebuffer(back, false);
if (clear_only) continue;
setUniformCamera(prog, cam);
setUniformViewCorners(prog, cam);
prog->setUniformValue("lights_start", lights_start[pass.second]);
prog->setUniformValue("lights_count", (int)cur_lights[pass.second].size());
prog->setUniformValue("fog_color", view->fogColor());
prog->setUniformValue("fog_decay", qMax(view->fogDecay(), 0.001f));
prog->setUniformValue("fog_density", view->fogDensity());
prog->setUniformValue("view_mat", cam->viewMatrix().inverted().toGenericMatrix<3, 3>());
if (shadows_enabled) {
prog->setUniformValue("shadow_size", view->shadow_map_size);
prog->setUniformValue("noise_size", noise_size);
prog->setUniformValue("soft_shadows_enabled", view->soft_shadows);
prog->setUniformValue("soft_shadows_samples", view->soft_shadows_samples);
prog->setUniformValue("soft_shadows_quality", view->soft_shadows_quality);
prog->setUniformValue("tex_shadows_cone", (int)tarShadowsCone);
prog->setUniformValue("tex_shadows_omni", (int)tarShadowsOmni);
prog->setUniformValue("tex_depths_cone", (int)tarDepthsCone);
prog->setUniformValue("tex_depths_omni", (int)tarDepthsOmni);
GLenum filter = view->softShadows() ? GL_NEAREST : GL_LINEAR;
shadow_maps_cone.bind(view, tarShadowsCone);
view->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, filter);
view->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, filter);
shadow_maps_omni.bind(view, tarShadowsOmni);
view->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, filter);
view->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, filter);
depth_maps_cone.bind(view, tarDepthsCone);
depth_maps_omni.bind(view, tarDepthsOmni);
}
renderQuad(prog, quad, cam);
}
}
}
void Renderer::renderConeShadows() {
QOpenGLExtraFunctions * f = view;
QOpenGLShaderProgram * prog = 0;
if (bindShader(srShadowConePass, &prog)) {
glEnableDepth();
textures_empty.bind(f, tarEmpty);
textures_maps.bind(f, tarMaps);
auto cone_ll = cur_lights.value(Light::Cone);
if (shadow_maps_cone.resize(f, view->shadow_map_size, cone_ll.size())) {
f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
f->glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
}
depth_maps_cone.resize(f, view->shadow_map_size, cone_ll.size());
for (int i = 0; i < cone_ll.size(); ++i) {
Light * l = cone_ll[i];
QMatrix4x4 pm = glMatrixPerspective(l->angle_end, 1., 0.1), om, vm;
om.translate(-l->worldAim());
vm.translate(0., 0., -l->distance());
// vm.rotate(-roll_, 0., 0., 1.);
QMatrix4x4 pmat = l->worldTransform();
pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.;
vm *= pmat.inverted();
auto vpm = pm * (vm * om);
if (l->isCastShadows()) {
prog->setUniformValue("qgl_ViewProjMatrix", vpm);
renderConeShadow(i, l);
}
l->shadow_matrix = mat_norm_to_tex_coord * vpm * mat_camera_fullview_inv;
}
}
}
void Renderer::renderOmniShadows() {
QOpenGLExtraFunctions * f = view;
QOpenGLShaderProgram * prog = 0;
if (bindShader(srShadowOmniPass, &prog)) {
glEnableDepth();
textures_empty.bind(f, tarEmpty);
textures_maps.bind(f, tarMaps);
auto omni_ll = cur_lights.value(Light::Omni);
if (shadow_maps_omni.resize(f, view->shadow_map_size, omni_ll.size())) {
f->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
f->glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
}
depth_maps_omni.resize(f, view->shadow_map_size, omni_ll.size());
for (int i = 0; i < omni_ll.size(); ++i) {
Light * l = omni_ll[i];
QMatrix4x4 om;
om.translate(-l->worldPos());
// vm.translate(0., 0., -l->distance());
// vm.rotate(-roll_, 0., 0., 1.);
if (l->isCastShadows()) {
renderOmniShadow(i, l, prog, om);
}
// l->shadow_matrix = mat_norm_to_tex_coord * vpm * mat_camera_fullview_inv;
}
}
}
void Renderer::renderConeShadow(int index, Light * light) {
Scene & scene(*(view->scene()));
bool force_resize = false;
if (!light->shadow_map.isInit()) {
light->shadow_map.reinit(view);
force_resize = true;
}
light->shadow_map.resize(view->shadow_map_size, force_resize);
light->shadow_map.bind();
view->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadow_maps_cone.ID(), 0, index);
view->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, depth_maps_cone.ID(), 0, index);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClearFramebuffer();
renderObjects(scene, rpSolid);
light->shadow_map.release();
}
void Renderer::renderOmniShadow(int index, Light * light, QOpenGLShaderProgram * prog, QMatrix4x4 om) {
Scene & scene(*(view->scene()));
bool force_resize = false;
if (!light->shadow_map.isInit()) {
light->shadow_map.reinit(view);
force_resize = true;
}
light->shadow_map.resize(view->shadow_map_size, force_resize);
light->shadow_map.bind();
for (int i = 0; i < 6; ++i) {
QMatrix4x4 vm = mat_proj_90 * mat_faces[i] * om;
prog->setUniformValue("qgl_ViewProjMatrix", vm);
view->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadow_maps_omni.ID(), 0, index * 6 + i);
view->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, depth_maps_omni.ID(), 0, index * 6 + i);
// static GLenum faces[6] = {GL_COLOR_ATTACHMENT0,
// GL_COLOR_ATTACHMENT1,
// GL_COLOR_ATTACHMENT2,
// GL_COLOR_ATTACHMENT3,
// GL_COLOR_ATTACHMENT4,
// GL_COLOR_ATTACHMENT5};
// view->glDrawBuffers(6, faces);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClearFramebuffer();
renderObjects(scene, rpSolid);
}
light->shadow_map.release();
}
void Renderer::renderScene() {
timings.clear();
Measurer phase(&timings);
phase.begin("init");
initShaders();
tex_env.load();
QOpenGLExtraFunctions * f = view;
Scene & scene(*(view->scene()));
Camera * cam = view->camera();
QOpenGLShaderProgram * prog = 0;
bool scene_changed = scene.prepare();
cur_lights = scene.lights_used;
mat_camera_fullview_inv = cam->fullViewMatrix().inverted();
scene.destroyUnused(f);
phase.end();
/// reload materials on change
phase.begin("scene reload");
if (scene_changed || scene.need_reload_materials) {
rend_selection.generateObjectsID(scene);
reloadMaterials(scene);
if (edit_mode) recreateMaterialThumbnails();
emit view->materialsChanged();
}
phase.end();
/// material thumbnails
phase.begin("materials");
if (edit_mode && !scene_changed) {
rend_mat.procQueue();
}
phase.end();
if (shadows_enabled) {
/// cone shadows and shadow matrix
phase.begin("shadows cone");
renderConeShadows();
phase.end();
/// omni shadows and shadow matrix
phase.begin("shadows omni");
renderOmniShadows();
phase.end();
}
/// lights
phase.begin("lights prepare");
bool use_camlight = (camera_light_mode == QGLView::clmOn);
if ((camera_light_mode == QGLView::clmAuto) && cur_lights.isEmpty()) {
use_camlight = true;
}
if (use_camlight) {
cur_lights[Light::Omni] << cam_light;
cam_light->setPos(cam->pos());
}
if (scene.lights_changed) {
scene.lights_changed = false;
reloadLightsParameters(cur_lights);
}
reloadLightsPositions(cam);
phase.end();
/// selection
phase.begin("selection");
if (edit_mode) {
rend_selection.renderSelection(scene);
}
phase.end();
/// solid geometry pass
phase.begin("geometry solid");
fbo_ds.bind();
glEnableDepth();
glClearFramebuffer();
if (bindShader(srGeometrySolidPass, &prog)) {
setUniformCamera(prog, cam);
textures_empty.bind(f, tarEmpty);
textures_maps.bind(f, tarMaps);
prog->setUniformValue("out_index_normal", dbrNormalZSolid);
prog->setUniformValue("out_index_metal", dbrMetalRoughReflectFlagsSolid);
glPolygonMode(GL_FRONT_AND_BACK, view->renderMode());
renderObjects(scene, rpSolid);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
// fbo_ds.blit(dbrNormalZ, fbo_ds.id(), dbrNormalZSolid, fbo_ds.rect(), fbo_ds.rect());
// fbo_ds.blit(dbrMetalRoughReflectFlags, fbo_ds.id(), dbrMetalRoughReflectFlagsSolid, fbo_ds.rect(), fbo_ds.rect());
fbo_ds.release();
phase.end();
/// lighting passes
phase.begin("... light");
fbo_out.bind();
fbo_ds.bindColorTextures({dbrDiffuse, dbrNormalZSolid, dbrMetalRoughReflectFlagsSolid, dbrEmission, dbrSpeedBitangXY, dbrGeoNormal});
renderLight(obrSolidOmni, scene.geometries_used[rpSolid].isEmpty());
phase.end();
/// transparent geometry pass
phase.begin("geometry trans");
fbo_ds.bind();
glEnableDepth();
fbo_ds.setWriteBuffers({0, 1, 2, 3, 4});
glClearFramebuffer(Qt::black, false);
fbo_ds.setWriteBuffers();
if (bindShader(srGeometryTransparentPass, &prog)) {
setUniformCamera(prog, cam);
textures_empty.bind(f, tarEmpty);
textures_maps.bind(f, tarMaps);
prog->setUniformValue("out_index_normal", dbrNormalZ);
prog->setUniformValue("out_index_metal", dbrMetalRoughReflectFlags);
glPolygonMode(GL_FRONT_AND_BACK, view->renderMode());
renderObjects(scene, rpTransparent);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
fbo_ds.release();
phase.end();
/// lighting passes
phase.begin("... light");
fbo_out.bind();
fbo_ds.bindColorTextures({dbrDiffuse, dbrNormalZ, dbrMetalRoughReflectFlags, dbrEmission, dbrSpeedBitangXY, dbrGeoNormal});
renderLight(obrTransparentOmni, scene.geometries_used[rpTransparent].isEmpty());
phase.end();
/// blending layers
phase.begin("blending");
if (bindShader(srFinalPass, &prog)) {
fbo_out.bindColorTexture(obrSolidOmni, 1);
fbo_out.bindColorTexture(obrSolidSpot, 2);
fbo_out.bindColorTexture(obrTransparentOmni, 3);
fbo_out.bindColorTexture(obrTransparentSpot, 4);
fbo_out.setWriteBuffer(obrLighting);
renderQuad(prog, quad);
}
phase.end();
fbo_out.bind();
cur_write_plane = obrLighting;
/// tonemapping
phase.begin("tonemap");
tone_proc.process();
auto free = getFreePlanes(0);
if (bindShader(srTonemapPass, &prog)) {
prog->setUniformValue("gamma", gamma_);
prog->setUniformValue("frame_max", tone_proc.frameMax());
// qDebug() << tone_proc.frameMax();
fbo_out.bindColorTexture(prev_write_plane, 0);
renderQuad(prog, quad);
} else {
fbo_out.blit(prev_write_plane, fbo_out.id(), cur_write_plane, fbo_out.rect(), fbo_out.rect());
}
phase.end();
/// FXAA
phase.begin("fxaa");
if (view->FXAA_) {
prog = shader_fxaa;
if (bindShader(prog)) {
auto free = getFreePlanes(0);
setUniformCamera(prog, 0, true, fbo_out.size());
fbo_out.bindColorTexture(prev_write_plane);
renderQuad(prog, quad, 0, false);
}
}
phase.end();
/// custom effects
for (auto * e: fb_effects) {
if (!e->isEnabled()) continue;
phase.begin("fb effect " + e->name());
e->reloadShadersInternal();
e->drawInternal();
phase.end();
}
fbo_out.release();
/// apply hovers and selection frame
phase.begin("service");
if (edit_mode) {
rend_selection.drawSelection(fbo_out, cur_write_plane);
rend_service.renderService();
} else {
fbo_out.blit(cur_write_plane, 0, 0, fbo_out.rect(), QRect(QPoint(), view->pixelSize()));
}
phase.end();
/// grab framebuffer
phase.begin("grab");
if (is_grabbing) {
fbo_out.queryImage(0);
last_img = fbo_out.getImage().mirrored();
// qDebug() << last_img.size();
}
phase.end();
/*
static QOpenGLShaderProgram * tprog = nullptr;
if (tprog && __reinit_debug) {
delete tprog;
tprog = nullptr;
}
if (!tprog) {
loadShadersMulti(tprog, "./shaders/debug.glsl");
tprog->bind();
tprog->setUniformValue("tex_cone", (int)tarShadowsCone);
tprog->setUniformValue("tex_omni", (int)tarShadowsOmni);
tprog->setUniformValue("dep_cone", (int)tarDepthsCone);
tprog->setUniformValue("dep_omni", (int)tarDepthsOmni);
QMatrix4x4 mat;
double sz = 0.33;
mat.translate(sz - 1, sz - 1);
mat.scale(sz, sz);
tprog->setUniformValue("qgl_ViewProjMatrix", mat);
}
__reinit_debug = false;
tprog->bind();
shadow_maps_cone.bind(f, tarShadowsCone);
shadow_maps_omni.bind(f, tarShadowsOmni);
depth_maps_cone.bind(f, tarDepthsCone);
depth_maps_omni.bind(f, tarDepthsOmni);
quad->draw(f, 1);
*/
}
void Renderer::setCameraLightMode(int m) {
camera_light_mode = m;
view->scene()->setLightsChanged();
}
void Renderer::setGrabImage(bool on) {
is_grabbing = on;
// fbo_out.enablePixelBuffer();
}
void Renderer::addFramebufferEffect(FramebufferEffectBase * e) {
e->r = this;
fb_effects << e;
}
void Renderer::setSadowsEnabled(bool on) {
shader_defines[srLightSpotPass].removeAll("SHADOWS");
shader_defines[srLightOmniPass].removeAll("SHADOWS");
if (on) {
shader_defines[srLightSpotPass] << "SHADOWS";
shader_defines[srLightOmniPass] << "SHADOWS";
}
shadows_enabled = on;
reloadShaders();
}

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