diff options
235 files changed, 18578 insertions, 8679 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b64f7b8afd..de01be1d299 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -497,11 +497,10 @@ endif() # We default options to whatever default standard in the current compiler. if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11)) set(_c11_init ON) - set(_cxx11_init ON) else() set(_c11_init OFF) - set(_cxx11_init OFF) endif() +set(_cxx11_init ON) option(WITH_C11 "Build with C11 standard enabled, for development use only!" ${_c11_init}) mark_as_advanced(WITH_C11) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index ecb1cf87511..be983ebff4a 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -25,7 +25,7 @@ ARGS=$( \ getopt \ -o s:i:t:h \ ---long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-build,no-confirm,use-cxx11,\ +--long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-build,no-confirm,\ with-all,with-opencollada,\ ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\ force-all,force-python,force-numpy,force-boost,\ @@ -104,11 +104,6 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS: --no-confirm Disable any interaction with user (suitable for automated run). - --use-cxx11 - Build all libraries in cpp11 'mode' (will be mandatory soon in blender2.8 branch). - NOTE: If your compiler is gcc-6.0 or above, you probably *want* to enable this option (since it's default - standard starting from this version). - --with-all By default, a number of optional and not-so-often needed libraries are not installed. This option will try to install them, at the cost of potential conflicts (depending on @@ -287,7 +282,7 @@ SUDO="sudo" NO_BUILD=false NO_CONFIRM=false -USE_CXX11=false +USE_CXX11=true # Mandatory in blender2.8 PYTHON_VERSION="3.5.2" PYTHON_VERSION_MIN="3.5" @@ -499,9 +494,6 @@ while true; do --no-confirm) NO_CONFIRM=true; shift; continue ;; - --use-cxx11) - USE_CXX11=true; shift; continue - ;; --with-all) WITH_ALL=true; shift; continue ;; @@ -793,7 +785,7 @@ FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" ) CXXFLAGS_BACK=$CXXFLAGS if [ "$USE_CXX11" = true ]; then - WARNING "You are trying to use c++11, this *should* go smoothely with any very recent distribution + WARNING "C++11 is now mandatory for blender2.8, this *should* go smoothly with any very recent distribution. However, if you are experiencing linking errors (also when building Blender itself), please try the following: * Re-run this script with `--build-all --force-all` options. * Ensure your gcc version is at the very least 4.8, if possible you should really rather use gcc-5.1 or above. diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 3f7730efbb0..acca6414852 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1594,6 +1594,7 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): row.prop(rd, "simplify_subdivision", text="Viewport") row.prop(rd, "simplify_subdivision_render", text="Render") + col = layout.column(align=True) col.label(text="Child Particles") row = col.row(align=True) diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h index dd49b81b561..8186eaa759d 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.h +++ b/intern/ghost/intern/GHOST_ContextCGL.h @@ -134,6 +134,8 @@ private: /** The OpenGL drawing context */ NSOpenGLContext *m_openGLContext; + bool m_coreProfile; + //static CGLEWContext *s_cglewContext; const bool m_debug; diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm index 03c45f9945b..64db70197bb 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.mm +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -63,6 +63,23 @@ GHOST_ContextCGL::GHOST_ContextCGL( m_debug(contextFlags) { assert(openGLView != nil); + + // for now be very strict about OpenGL version requested + switch (contextMajorVersion) { + case 2: + assert(contextMinorVersion == 1); + assert(contextProfileMask == 0); + m_coreProfile = false; + break; + case 3: + // Apple didn't implement 3.0 or 3.1 + assert(contextMinorVersion == 2); + assert(contextProfileMask == GL_CONTEXT_CORE_PROFILE_BIT); + m_coreProfile = true; + break; + default: + assert(false); + } } @@ -170,6 +187,7 @@ GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext() static void makeAttribList( std::vector<NSOpenGLPixelFormatAttribute>& attribs, + bool coreProfile, bool stereoVisual, int numOfAASamples, bool needAlpha, @@ -178,6 +196,9 @@ static void makeAttribList( { attribs.clear(); + attribs.push_back(NSOpenGLPFAOpenGLProfile); + attribs.push_back(coreProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy); + // Pixel Format Attributes for the windowed NSOpenGLContext attribs.push_back(NSOpenGLPFADoubleBuffer); @@ -190,8 +211,7 @@ static void makeAttribList( attribs.push_back(NSOpenGLPFANoRecovery); } - /* Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway */ - //attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); + attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); // for automatic GPU switching attribs.push_back(NSOpenGLPFADepthSize); attribs.push_back((NSOpenGLPixelFormatAttribute) 32); @@ -263,7 +283,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() NSOpenGLPixelFormat *pixelFormat; // TODO: keep pixel format for subsequent windows/contexts instead of recreating each time - makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL); + makeAttribList(attribs, m_coreProfile, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL); pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; @@ -274,7 +294,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() // (Now that I think about it, does WGL really require the code that it has for finding a lesser match?) attribs.clear(); - makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil, softwareGL); + makeAttribList(attribs, m_coreProfile, m_stereoVisual, 0, needAlpha, needStencil, softwareGL); pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; } @@ -316,7 +336,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() [m_openGLContext release]; // create software GL context - makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL); + makeAttribList(attribs, m_coreProfile, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL); pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext]; [pixelFormat release]; diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index 9ac61db4041..60cdce83602 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -255,9 +255,6 @@ const bool GLXEW_ARB_create_context_robustness = if (m_contextMajorVersion != 0) { attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; attribs[i++] = m_contextMajorVersion; - } - - if (m_contextMinorVersion != 0) { attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; attribs[i++] = m_contextMinorVersion; } @@ -300,8 +297,8 @@ const bool GLXEW_ARB_create_context_robustness = } } else { - /* Create legacy context */ - m_context = glXCreateContext(m_display, m_visualInfo, s_sharedContext, True); + /* Don't create legacy context */ + fprintf(stderr, "Warning! GLX_ARB_create_context not available.\n"); } GHOST_TSuccess success; @@ -328,8 +325,14 @@ const bool GLXEW_ARB_create_context_robustness = version = glGetString(GL_VERSION); - if (!version || version[0] < '2' || ((version[0] == '2') && (version[2] < '1'))) { - fprintf(stderr, "Error! Blender requires OpenGL 2.1 to run. Try updating your drivers.\n"); +#if 0 // enable this when Blender switches to 3.3 core profile + if (!version || version[0] < '3' || ((version[0] == '3') && (version[2] < '3'))) { + fprintf(stderr, "Error! Blender requires OpenGL 3.3 to run. Try updating your drivers.\n"); +#else + // with Mesa, the closest thing to 3.3 compatibility profile is 3.0 + if (!version || version[0] < '3') { + fprintf(stderr, "Error! Blender requires OpenGL 3.0 (soon 3.3) to run. Try updating your drivers.\n"); +#endif fflush(stderr); /* ugly, but we get crashes unless a whole bunch of systems are patched. */ exit(0); diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index 64ee692797b..39ef63fa723 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -962,7 +962,7 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[2] == '1') { MessageBox(m_hWnd, "Your system does not use 3D hardware acceleration.\n" - "Blender requires a graphics driver with OpenGL 2.1 support.\n\n" + "Blender requires a graphics driver with OpenGL 3.3 support.\n\n" "This may be caused by:\n" "* A missing or faulty graphics driver installation.\n" " Blender needs a graphics card driver to work correctly.\n" @@ -973,8 +973,8 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() MB_OK | MB_ICONERROR); exit(0); } - else if (version[0] < '2' || (version[0] == '2' && version[2] < '1')) { - MessageBox(m_hWnd, "Blender requires a graphics driver with OpenGL 2.1 support.\n\n" + else if (version[0] < '3' || (version[0] == '3' && version[2] < '3')) { + MessageBox(m_hWnd, "Blender requires a graphics driver with OpenGL 3.3 support.\n\n" "The program will now close.", "Blender - Unsupported Graphics Driver!", MB_OK | MB_ICONERROR); diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h index 580b4dcb82f..99efcc5ebd7 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.h +++ b/intern/ghost/intern/GHOST_ContextWGL.h @@ -46,14 +46,6 @@ extern "C" WGLEWContext *wglewContext; #endif -#ifndef GHOST_OPENGL_WGL_CONTEXT_FLAGS -# ifdef WITH_GPU_DEBUG -# define GHOST_OPENGL_WGL_CONTEXT_FLAGS WGL_CONTEXT_DEBUG_BIT_ARB -# else -# define GHOST_OPENGL_WGL_CONTEXT_FLAGS 0 -# endif -#endif - #ifndef GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY #define GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY 0 #endif diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 97615dcea96..b0feb11a6af 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -1086,82 +1086,23 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { -#if !defined(WITH_GL_EGL) -#if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextCGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - GL_CONTEXT_CORE_PROFILE_BIT, - 3, 2, - GHOST_OPENGL_CGL_CONTEXT_FLAGS, - GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_ES20) GHOST_Context *context = new GHOST_ContextCGL( m_wantStereoVisual, m_wantNumOfAASamples, m_window, m_openGLView, - CGL_CONTEXT_ES2_PROFILE_BIT_EXT, - 2, 0, - GHOST_OPENGL_CGL_CONTEXT_FLAGS, - GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextCGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - 0, // profile bit - 0, 0, - m_debug_context, - GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); -#else -# error -#endif - -#else #if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + GL_CONTEXT_CORE_PROFILE_BIT, 3, 2, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - 0, // profile bit - 2, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_ES_API); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - 0, // profile bit - 0, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); #else -# error + 0, // no profile bit + 2, 1, #endif + GHOST_OPENGL_CGL_CONTEXT_FLAGS, + GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); -#endif if (context->initializeDrawingContext()) return context; else diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 7d80aa43a40..58aa0b87045 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -610,97 +610,37 @@ GHOST_TSuccess GHOST_WindowWin32::invalidate() GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { -#if !defined(WITH_GL_EGL) + const int profile_mask = #if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextWGL( - m_wantStereoVisual, - m_wantAlphaBackground, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - 3, 2, - GHOST_OPENGL_WGL_CONTEXT_FLAGS, - GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextWGL( - m_wantStereoVisual, - m_wantAlphaBackground, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - WGL_CONTEXT_ES2_PROFILE_BIT_EXT, - 2, 0, - GHOST_OPENGL_WGL_CONTEXT_FLAGS, - GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); + WGL_CONTEXT_CORE_PROFILE_BIT_ARB; #elif defined(WITH_GL_PROFILE_COMPAT) + WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; +#else +# error // must specify either core or compat at build time +#endif + GHOST_Context *context = new GHOST_ContextWGL( m_wantStereoVisual, m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, -#if 1 - 0, // profile bit - 2, 1, // GL version requested + profile_mask, +#if 0 + 3, 3, // specific GL version requested + // AMD gives us exactly this version + // NVIDIA gives at least this version <-- desired behavior #else - // switch to this for Blender 2.8 development - WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - 3, 2, + 2, 1, // any GL version >= 2.1 (hopefully the latest) + // we check later to ensure it's >= 3.3 on Windows + // TODO(merwin): fix properly! + // 2.1 ignores the profile bit & is incompatible with core profile + // query version of initial dummy context, request that + profile + debug #endif (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); -#else -# error -#endif - -#else -#if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - 3, 2, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - 0, // profile bit - 2, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_ES_API); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, -#if 1 - 0, // profile bit - 2, 1, // GL version requested -#else - // switch to this for Blender 2.8 development - EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, - 3, 2, -#endif - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else -# error -#endif - -#endif if (context->initializeDrawingContext()) return context; else diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 47fbe1256b1..992200a0b09 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -1314,33 +1314,24 @@ GHOST_WindowX11:: GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { -#if !defined(WITH_GL_EGL) + // During development: + // try 3.3 compatibility profile + // fall back to 3.0 if needed + // + // Final Blender 2.8: + // try 3.3 core profile + // no fallbacks + + const int profile_mask = #if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextGLX( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - m_visualInfo, - (GLXFBConfig)m_fbconfig, - GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 3, 2, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextGLX( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - m_visualInfo, - (GLXFBConfig)m_fbconfig, - GLX_CONTEXT_ES2_PROFILE_BIT_EXT, - 2, 0, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); + GLX_CONTEXT_CORE_PROFILE_BIT_ARB; #elif defined(WITH_GL_PROFILE_COMPAT) + GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; +#else +# error // must specify either core or compat at build time +#endif + GHOST_Context *context = new GHOST_ContextGLX( m_wantStereoVisual, m_wantNumOfAASamples, @@ -1348,58 +1339,34 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_display, m_visualInfo, (GLXFBConfig)m_fbconfig, - 0, // profile bit - 0, 0, + profile_mask, + 3, 3, GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); -#else -# error -#endif -#else - -#if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - 3, 2, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - 0, // profile bit - 2, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_ES_API); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - 0, // profile bit - 0, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else -# error -#endif - -#endif if (context->initializeDrawingContext()) return context; - else + else { delete context; + + // since that failed try 3.0 (mostly for Mesa, which doesn't implement compatibility profile) + context = new GHOST_ContextGLX( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_display, + m_visualInfo, + (GLXFBConfig)m_fbconfig, + 0, // no profile bit + 3, 0, + GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); + + if (context->initializeDrawingContext()) + return context; + else + delete context; + } } return NULL; diff --git a/release/darwin/blender.app/Contents/Info.plist b/release/darwin/blender.app/Contents/Info.plist index 0649a2075cd..36cb5d2ccaf 100644 --- a/release/darwin/blender.app/Contents/Info.plist +++ b/release/darwin/blender.app/Contents/Info.plist @@ -2,6 +2,8 @@ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> + <key>LSMinimumSystemVersion</key> + <string>10.7.0</string> <key>CFBundleDocumentTypes</key> <array> <dict> @@ -47,5 +49,7 @@ <string>NSApplication</string> <key>NSHighResolutionCapable</key> <true/> + <key>NSSupportsAutomaticGraphicsSwitching</key> + <true/> </dict> </plist> diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py index 3ebf2691b4c..54581c9276d 100644 --- a/release/scripts/startup/bl_ui/properties_physics_cloth.py +++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py @@ -64,6 +64,8 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel): split = layout.split(percentage=0.25) + col = split.column() + split.label(text="Presets:") sub = split.row(align=True) sub.menu("CLOTH_MT_presets", text=bpy.types.CLOTH_MT_presets.bl_label) diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 780dc4cf982..d77113ef7fc 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -40,7 +40,7 @@ class INFO_HT_header(Header): layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous") layout.separator() else: - layout.template_ID(context.window, "screen", new="screen.new", unlink="screen.delete") + layout.template_ID_preview(context.window, "screen", new="screen.new", unlink="screen.delete", rows=2, cols=6) layout.template_ID(context.screen, "scene", new="scene.new", unlink="scene.delete") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 55fa2c28011..2798a2fd0d0 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -710,7 +710,6 @@ class VIEW3D_MT_select_particle(Menu): layout = self.layout layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") layout.separator() @@ -3120,6 +3119,47 @@ class VIEW3D_MT_edit_gpencil_interpolate(Menu): # ********** Panel ********** +class VIEW3D_PT_viewport_debug(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_label = "Modern Viewport" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + view = context.space_data + return (view) + + def draw_header(self, context): + view = context.space_data + self.layout.prop(view, "use_modern_viewport", text="") + + def draw(self, context): + layout = self.layout + view = context.space_data + + layout.active = view.use_modern_viewport + + col = layout.column() + col.label(text="Placeholder for debugging options") + col.separator() + + row = col.row() + row.active = not view.show_combined_depth + row.prop(view, "show_scene_depth") + row = col.row() + row.active = not view.show_scene_depth + row.prop(view, "show_combined_depth") + + row = col.row(align=True) + row.active = view.show_scene_depth or view.show_combined_depth + row.prop(view, "debug_near") + row.prop(view, "debug_far") + + col.label(text="Background:") + col.row(align=True).prop(view, "debug_background", expand=True) + + class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -3233,7 +3273,7 @@ class VIEW3D_PT_view3d_display(Panel): @classmethod def poll(cls, context): view = context.space_data - return (view) + return (view) and not view.use_modern_viewport def draw(self, context): layout = self.layout @@ -3333,6 +3373,11 @@ class VIEW3D_PT_view3d_shading(Panel): bl_region_type = 'UI' bl_label = "Shading" + @classmethod + def poll(cls, context): + view = context.space_data + return (view) and not view.use_modern_viewport + def draw(self, context): layout = self.layout diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 1f38d64924c..3da0434687c 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -34,6 +34,9 @@ #include "BLI_compiler_attrs.h" +/* enable this only if needed (unused circa 2016) */ +#define BLF_BLUR_ENABLE 0 + struct rctf; struct ColorManagedDisplay; struct ResultBLF; @@ -144,7 +147,10 @@ void BLF_rotation(int fontid, float angle); void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax); void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax); void BLF_wordwrap(int fontid, int wrap_width); + +#if BLF_BLUR_ENABLE void BLF_blur(int fontid, int size); +#endif void BLF_enable(int fontid, int option); void BLF_disable(int fontid, int option); diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 132a0ec3808..1ce4753cc39 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -56,7 +56,9 @@ #include "IMB_colormanagement.h" #ifndef BLF_STANDALONE -#include "GPU_basic_shader.h" +#include "GPU_shader.h" +#include "GPU_matrix.h" +#include "GPU_immediate.h" #endif #include "blf_internal_types.h" @@ -453,6 +455,7 @@ void BLF_size(int fontid, int size, int dpi) } } +#if BLF_BLUR_ENABLE void BLF_blur(int fontid, int size) { FontBLF *font = blf_get(fontid); @@ -461,6 +464,7 @@ void BLF_blur(int fontid, int size) font->blur = size; } } +#endif void BLF_draw_default(float x, float y, float z, const char *str, size_t len) { @@ -490,7 +494,7 @@ void BLF_rotation_default(float angle) } } -static void blf_draw_gl__start(FontBLF *font, GLint *mode) +static void blf_draw_gl__start(FontBLF *font) { /* * The pixmap alignment hack is handle @@ -500,52 +504,48 @@ static void blf_draw_gl__start(FontBLF *font, GLint *mode) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#ifndef BLF_STANDALONE - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); -#endif - - /* Save the current matrix mode. */ - glGetIntegerv(GL_MATRIX_MODE, mode); - - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadIdentity(); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); + gpuMatrixBegin3D_legacy(); if (font->flags & BLF_MATRIX) - glMultMatrixf(font->m); + gpuMultMatrix3D((float (*)[4])font->m); - glTranslate3fv(font->pos); + gpuTranslate3fv(font->pos); if (font->flags & BLF_ASPECT) - glScalef(font->aspect[0], font->aspect[1], font->aspect[2]); + gpuScale3fv(font->aspect); if (font->flags & BLF_ROTATION) /* radians -> degrees */ - glRotatef(font->angle * (float)(180.0 / M_PI), 0.0f, 0.0f, 1.0f); + gpuRotateAxis(RAD2DEG(font->angle), 'Z'); + + float temp_color[4]; + glGetFloatv(GL_CURRENT_COLOR, temp_color); /* TODO(merwin): new BLF_color function? */ + rgba_float_to_uchar(font->color, temp_color); + +#ifndef BLF_STANDALONE + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + BLI_assert(pos == BLF_POS_ID); + BLI_assert(texCoord == BLF_COORD_ID); + BLI_assert(color == BLF_COLOR_ID); - if (font->shadow || font->blur) - glGetFloatv(GL_CURRENT_COLOR, font->orig_col); + immBindBuiltinProgram(GPU_SHADER_TEXT); +#endif /* always bind the texture for the first glyph */ font->tex_bind_state = -1; } -static void blf_draw_gl__end(GLint mode) +static void blf_draw_gl__end(void) { - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - if (mode != GL_MODELVIEW) - glMatrixMode(mode); + gpuMatrixEnd(); #ifndef BLF_STANDALONE - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immUnbindProgram(); #endif + glDisable(GL_BLEND); } @@ -554,23 +554,26 @@ void BLF_draw_ex( struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); - GLint mode; BLF_RESULT_CHECK_INIT(r_info); if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); if (font->flags & BLF_WORD_WRAP) { blf_font_draw__wrap(font, str, len, r_info); } else { blf_font_draw(font, str, len, r_info); } - blf_draw_gl__end(mode); + blf_draw_gl__end(); } } void BLF_draw(int fontid, const char *str, size_t len) { + if (len == 0 || str[0] == '\0') { + return; + } + BLF_draw_ex(fontid, str, len, NULL); } @@ -579,12 +582,11 @@ void BLF_draw_ascii_ex( struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); - GLint mode; BLF_RESULT_CHECK_INIT(r_info); if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); if (font->flags & BLF_WORD_WRAP) { /* use non-ascii draw function for word-wrap */ blf_font_draw__wrap(font, str, len, r_info); @@ -592,24 +594,31 @@ void BLF_draw_ascii_ex( else { blf_font_draw_ascii(font, str, len, r_info); } - blf_draw_gl__end(mode); + blf_draw_gl__end(); } } void BLF_draw_ascii(int fontid, const char *str, size_t len) { + if (len == 0 || str[0] == '\0') { + return; + } + BLF_draw_ascii_ex(fontid, str, len, NULL); } int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) { + if (len == 0 || str[0] == '\0') { + return 0; + } + FontBLF *font = blf_get(fontid); - GLint mode; int columns = 0; if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); columns = blf_font_draw_mono(font, str, len, cwidth); - blf_draw_gl__end(mode); + blf_draw_gl__end(); } return columns; @@ -855,7 +864,7 @@ void BLF_shadow(int fontid, int level, const float rgba[4]) if (font) { font->shadow = level; - copy_v4_v4(font->shadow_col, rgba); + rgba_float_to_uchar(font->shadow_color, rgba); } } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 44a1d08f1fd..71350a0f8dc 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -58,6 +58,8 @@ #include "BIF_gl.h" #include "BLF_api.h" +#include "GPU_immediate.h" + #include "blf_internal_types.h" #include "blf_internal.h" @@ -172,6 +174,23 @@ static void blf_font_ensure_ascii_table(FontBLF *font) } \ } (void)0 +static unsigned verts_needed(const FontBLF *font, const char *str, size_t len) +{ + unsigned length = (unsigned)((len == INT_MAX) ? strlen(str) : len); + unsigned quad_ct = 1; + + if (font->flags & BLF_SHADOW) { + if (font->shadow == 0) + quad_ct += 1; + if (font->shadow <= 4) + quad_ct += 9; /* 3x3 kernel */ + else + quad_ct += 25; /* 5x5 kernel */ + } + + return length * quad_ct * 4; +} + static void blf_font_draw_ex( FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y) @@ -187,6 +206,9 @@ static void blf_font_draw_ex( blf_font_ensure_ascii_table(font); + immBeginAtMost(GL_QUADS, verts_needed(font, str, len)); + /* at most because some glyphs might be clipped & not drawn */ + while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -204,6 +226,8 @@ static void blf_font_draw_ex( g_prev = g; } + immEnd(); + if (r_info) { r_info->lines = 1; r_info->width = pen_x; @@ -229,6 +253,8 @@ static void blf_font_draw_ascii_ex( blf_font_ensure_ascii_table(font); + immBeginAtMost(GL_QUADS, verts_needed(font, str, len)); + while ((c = *(str++)) && len--) { BLI_assert(c < 128); if ((g = glyph_ascii_table[c]) == NULL) @@ -243,6 +269,8 @@ static void blf_font_draw_ascii_ex( g_prev = g; } + immEnd(); + if (r_info) { r_info->lines = 1; r_info->width = pen_x; @@ -265,6 +293,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) blf_font_ensure_ascii_table(font); + immBeginAtMost(GL_QUADS, verts_needed(font, str, len)); + while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -284,6 +314,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) pen_x += cwidth * col; } + immEnd(); + return columns; } @@ -922,7 +954,9 @@ static void blf_font_fill(FontBLF *font) font->size = 0; BLI_listbase_clear(&font->cache); font->glyph_cache = NULL; +#if BLF_BLUR_ENABLE font->blur = 0; +#endif font->max_tex_size = -1; font->buf_info.fbuf = NULL; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index aa7d539538b..b1bab13f3ae 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -56,7 +56,7 @@ #include "BLF_api.h" #ifndef BLF_STANDALONE -#include "GPU_basic_shader.h" +#include "GPU_immediate.h" #endif #include "blf_internal_types.h" @@ -182,17 +182,6 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - -#ifndef BLF_STANDALONE - /* needed since basic shader doesn't support alpha-only textures, - * while we could add support this is only used in a few places - * (an alternative could be to have a simple shader for BLF). */ - if (GLEW_ARB_texture_swizzle && GPU_basic_shader_use_glsl_get()) { - GLint swizzle_mask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask); - } -#endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL); } @@ -326,73 +315,73 @@ void blf_glyph_free(GlyphBLF *g) MEM_freeN(g); } -static void blf_texture_draw(float uv[2][2], float dx, float y1, float dx1, float y2) +static void blf_texture_draw(const unsigned char color[4], float uv[2][2], float dx, float y1, float dx1, float y2) { - glBegin(GL_QUADS); - glTexCoord2f(uv[0][0], uv[0][1]); - glVertex2f(dx, y1); - - glTexCoord2f(uv[0][0], uv[1][1]); - glVertex2f(dx, y2); - - glTexCoord2f(uv[1][0], uv[1][1]); - glVertex2f(dx1, y2); - - glTexCoord2f(uv[1][0], uv[0][1]); - glVertex2f(dx1, y1); - glEnd(); + immAttrib2f(BLF_COORD_ID, uv[0][0], uv[0][1]); + immSkipAttrib(BLF_COLOR_ID); /* skip color of most vertices */ + immVertex2f(BLF_POS_ID, dx, y1); + + immAttrib2f(BLF_COORD_ID, uv[0][0], uv[1][1]); + immSkipAttrib(BLF_COLOR_ID); + immVertex2f(BLF_POS_ID, dx, y2); + + immAttrib2f(BLF_COORD_ID, uv[1][0], uv[1][1]); + immSkipAttrib(BLF_COLOR_ID); + immVertex2f(BLF_POS_ID, dx1, y2); + + immAttrib2f(BLF_COORD_ID, uv[1][0], uv[0][1]); + immAttrib4ubv(BLF_COLOR_ID, color); /* set color of provoking vertex */ + immVertex2f(BLF_POS_ID, dx1, y1); } -static void blf_texture5_draw(const float shadow_col[4], float uv[2][2], float x1, float y1, float x2, float y2) +static void blf_texture5_draw(const unsigned char color_in[4], float uv[2][2], float x1, float y1, float x2, float y2) { const float soft[25] = {1 / 60.0f, 1 / 60.0f, 2 / 60.0f, 1 / 60.0f, 1 / 60.0f, 1 / 60.0f, 3 / 60.0f, 5 / 60.0f, 3 / 60.0f, 1 / 60.0f, 2 / 60.0f, 5 / 60.0f, 8 / 60.0f, 5 / 60.0f, 2 / 60.0f, 1 / 60.0f, 3 / 60.0f, 5 / 60.0f, 3 / 60.0f, 1 / 60.0f, 1 / 60.0f, 1 / 60.0f, 2 / 60.0f, 1 / 60.0f, 1 / 60.0f}; - + const float *fp = soft; - float color[4]; + unsigned char color[4]; float dx, dy; - color[0] = shadow_col[0]; - color[1] = shadow_col[1]; - color[2] = shadow_col[2]; - + color[0] = color_in[0]; + color[1] = color_in[1]; + color[2] = color_in[2]; + + const float alpha_in = (1 / 255.0f) * color_in[3]; + for (dx = -2; dx < 3; dx++) { for (dy = -2; dy < 3; dy++, fp++) { - color[3] = *(fp) * shadow_col[3]; - glColor4fv(color); - blf_texture_draw(uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); + color[3] = FTOCHAR(*fp * alpha_in); + blf_texture_draw(color, uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); } } - - glColor4fv(color); } -static void blf_texture3_draw(const float shadow_col[4], float uv[2][2], float x1, float y1, float x2, float y2) +static void blf_texture3_draw(const unsigned char color_in[4], float uv[2][2], float x1, float y1, float x2, float y2) { const float soft[9] = {1 / 16.0f, 2 / 16.0f, 1 / 16.0f, 2 / 16.0f, 4 / 16.0f, 2 / 16.0f, 1 / 16.0f, 2 / 16.0f, 1 / 16.0f}; const float *fp = soft; - float color[4]; + unsigned char color[4]; float dx, dy; - color[0] = shadow_col[0]; - color[1] = shadow_col[1]; - color[2] = shadow_col[2]; + color[0] = color_in[0]; + color[1] = color_in[1]; + color[2] = color_in[2]; + + const float alpha_in = (1 / 255.0f) * color_in[3]; for (dx = -1; dx < 2; dx++) { for (dy = -1; dy < 2; dy++, fp++) { - color[3] = *(fp) * shadow_col[3]; - glColor4fv(color); - blf_texture_draw(uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); + color[3] = FTOCHAR(*fp * alpha_in); + blf_texture_draw(color, uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); } } - - glColor4fv(color); } static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) @@ -486,39 +475,37 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = g->tex)); } + /* TODO: blur & shadow in shader, single quad per glyph */ + if (font->flags & BLF_SHADOW) { rctf rect_ofs; blf_glyph_calc_rect(&rect_ofs, g, x + (float)font->shadow_x, y + (float)font->shadow_y); - switch (font->shadow) { - case 3: - blf_texture3_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; - case 5: - blf_texture5_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; - default: - glColor4fv(font->shadow_col); - blf_texture_draw(g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; + if (font->shadow == 0) { + blf_texture_draw(font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + } + else if (font->shadow <= 4) { + blf_texture3_draw(font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + } + else { + blf_texture5_draw(font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); } - - glColor4fv(font->orig_col); } +#if BLF_BLUR_ENABLE switch (font->blur) { case 3: - blf_texture3_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + blf_texture3_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; case 5: - blf_texture5_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + blf_texture5_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; default: - blf_texture_draw(g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - break; + blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); } - - return; +#else + blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); +#endif } diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index d9d758ce548..ba17e050399 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -37,6 +37,11 @@ struct GlyphBLF; struct GlyphCacheBLF; struct rctf; +/* vertex attribute IDs (fixed IDs so we don't have to pass them around) */ +#define BLF_POS_ID 0 +#define BLF_COORD_ID 1 +#define BLF_COLOR_ID 2 + unsigned int blf_next_p2(unsigned int x); unsigned int blf_hash(unsigned int val); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 0fac576a8cc..9164a02b2cc 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -175,8 +175,10 @@ typedef struct FontBLF { /* angle in radians. */ float angle; +#if 0 /* BLF_BLUR_ENABLE */ /* blur: 3 or 5 large kernel */ int blur; +#endif /* shadow level. */ int shadow; @@ -186,10 +188,10 @@ typedef struct FontBLF { int shadow_y; /* shadow color. */ - float shadow_col[4]; + unsigned char shadow_color[4]; - /* store color here when drawing shadow or blur. */ - float orig_col[4]; + /* main text color. */ + unsigned char color[4]; /* Multiplied this matrix with the current one before * draw the text! see blf_draw__start. diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 789bc8df7e5..059f7309cf5 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -145,6 +145,10 @@ typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index); typedef DMDrawOption (*DMSetDrawOptionsMappedTex)(void *userData, int origindex, int mat_nr); typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTexPoly *mtexpoly, const bool has_vcol, int matnr); +/* Cleanup callback type */ +typedef void (*DMCleanupBatchCache)(void *batchCache); +void DM_set_batch_cleanup_callback(DMCleanupBatchCache); + typedef enum DMDrawFlag { DM_DRAW_USE_COLORS = (1 << 0), DM_DRAW_ALWAYS_SMOOTH = (1 << 1), @@ -183,6 +187,7 @@ struct DerivedMesh { int deformedOnly; /* set by modifier stack if only deformed from original */ BVHCache *bvhCache; struct GPUDrawObject *drawObject; + void *batchCache; DerivedMeshType type; float auto_bump_scale; DMDirtyFlag dirty; diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 14e978b23f2..010810ad0cc 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -49,6 +49,7 @@ struct bScreen; struct uiLayout; struct uiList; struct wmKeyConfig; +struct wmManipulatorMap; struct wmNotifier; struct wmWindow; struct wmWindowManager; @@ -96,6 +97,9 @@ typedef struct SpaceType { /* on startup, define dropboxes for spacetype+regions */ void (*dropboxes)(void); + /* initialize manipulator-map-types and manipulator-group-types with the region */ + void (*manipulators)(void); + /* return context data */ int (*context)(const struct bContext *, const char *, struct bContextDataResult *); @@ -284,6 +288,8 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar); void BKE_screen_area_free(struct ScrArea *sa); +/* Manipulator-maps of a region need to be freed with the region. Uses callback to avoid low-level call. */ +void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *)); struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type); struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 1f937d837b4..fb0087aefac 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -260,6 +260,12 @@ static CustomData *dm_getPolyCData(DerivedMesh *dm) return &dm->polyData; } +static DMCleanupBatchCache cleanupBatchCache = NULL; +void DM_set_batch_cleanup_callback(DMCleanupBatchCache func) +{ + cleanupBatchCache = func; +} + /** * Utility function to initialize a DerivedMesh's function pointers to * the default implementation (for those functions which have a default) @@ -317,7 +323,9 @@ void DM_init( dm->numPolyData = numPolys; DM_init_funcs(dm); - + + dm->batchCache = NULL; /* necessary? dm->drawObject is not set to NULL yet it works fine */ + dm->needsFree = 1; dm->auto_bump_scale = -1.0f; dm->dirty = 0; @@ -377,6 +385,10 @@ int DM_release(DerivedMesh *dm) if (dm->needsFree) { bvhcache_free(&dm->bvhCache); GPU_drawobject_free(dm); + if (dm->batchCache && cleanupBatchCache) { + cleanupBatchCache(dm->batchCache); + dm->batchCache = NULL; + } CustomData_free(&dm->vertData, dm->numVertData); CustomData_free(&dm->edgeData, dm->numEdgeData); CustomData_free(&dm->faceData, dm->numTessFaceData); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 28ef3f6f248..162525c7cd5 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -478,7 +478,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived return; } - if (!can_simulate) return; /* if on second frame, write cache for first frame */ diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 4c01bfd35f2..9d927d04b2a 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -950,7 +950,6 @@ static const char *data_mode_strings[] = { "weightpaint", "vertexpaint", "imagepaint", - "particlemode", "objectmode", NULL }; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 66070923153..1daf999e4a9 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -5562,8 +5562,6 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats); /* Apply brush on the surface depending on it's collision type */ - /* Particle brush: */ - if (brush->collision == MOD_DPAINT_COL_PSYS) { if (brush->psys && brush->psys->part && ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) && psys_check_enabled(brushObj, brush->psys, G.is_rendering)) @@ -5573,9 +5571,8 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su BKE_scene_frame_get(scene), ADT_RECALC_ANIM); dynamicPaint_paintParticles(surface, brush->psys, brush, timescale); } - } /* Object center distance: */ - else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { + if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { dynamicPaint_paintSinglePoint(surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale); } /* Mesh volume/proximity: */ diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 7669c4ba112..70cf0d5a445 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -42,6 +42,7 @@ #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" #include "DNA_brush_types.h" @@ -252,6 +253,7 @@ PreviewImage **BKE_previewimg_id_get_p(ID *id) ID_PRV_CASE(ID_OB, Object); ID_PRV_CASE(ID_GR, Group); ID_PRV_CASE(ID_SCE, Scene); + ID_PRV_CASE(ID_SCR, bScreen); #undef ID_PRV_CASE } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 65f37d0a5b1..038504040d7 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1208,41 +1208,41 @@ void BKE_main_free(Main *mainvar) /* errors freeing ID's can be hard to track down, * enable this so valgrind will give the line number in its error log */ switch (a) { - case 0: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 1: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 2: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 3: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 4: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 5: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 6: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 7: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 8: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 9: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 10: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 11: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 12: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 13: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 14: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 15: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 16: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 17: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 18: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 19: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 20: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 21: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 22: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 23: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 24: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 25: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 26: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 27: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 28: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 29: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 30: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 31: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 32: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 33: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 34: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 0: BKE_libblock_free_ex(mainvar, id, false); break; + case 1: BKE_libblock_free_ex(mainvar, id, false); break; + case 2: BKE_libblock_free_ex(mainvar, id, false); break; + case 3: BKE_libblock_free_ex(mainvar, id, false); break; + case 4: BKE_libblock_free_ex(mainvar, id, false); break; + case 5: BKE_libblock_free_ex(mainvar, id, false); break; + case 6: BKE_libblock_free_ex(mainvar, id, false); break; + case 7: BKE_libblock_free_ex(mainvar, id, false); break; + case 8: BKE_libblock_free_ex(mainvar, id, false); break; + case 9: BKE_libblock_free_ex(mainvar, id, false); break; + case 10: BKE_libblock_free_ex(mainvar, id, false); break; + case 11: BKE_libblock_free_ex(mainvar, id, false); break; + case 12: BKE_libblock_free_ex(mainvar, id, false); break; + case 13: BKE_libblock_free_ex(mainvar, id, false); break; + case 14: BKE_libblock_free_ex(mainvar, id, false); break; + case 15: BKE_libblock_free_ex(mainvar, id, false); break; + case 16: BKE_libblock_free_ex(mainvar, id, false); break; + case 17: BKE_libblock_free_ex(mainvar, id, false); break; + case 18: BKE_libblock_free_ex(mainvar, id, false); break; + case 19: BKE_libblock_free_ex(mainvar, id, false); break; + case 20: BKE_libblock_free_ex(mainvar, id, false); break; + case 21: BKE_libblock_free_ex(mainvar, id, false); break; + case 22: BKE_libblock_free_ex(mainvar, id, false); break; + case 23: BKE_libblock_free_ex(mainvar, id, false); break; + case 24: BKE_libblock_free_ex(mainvar, id, false); break; + case 25: BKE_libblock_free_ex(mainvar, id, false); break; + case 26: BKE_libblock_free_ex(mainvar, id, false); break; + case 27: BKE_libblock_free_ex(mainvar, id, false); break; + case 28: BKE_libblock_free_ex(mainvar, id, false); break; + case 29: BKE_libblock_free_ex(mainvar, id, false); break; + case 30: BKE_libblock_free_ex(mainvar, id, false); break; + case 31: BKE_libblock_free_ex(mainvar, id, false); break; + case 32: BKE_libblock_free_ex(mainvar, id, false); break; + case 33: BKE_libblock_free_ex(mainvar, id, false); break; + case 34: BKE_libblock_free_ex(mainvar, id, false); break; default: BLI_assert(0); break; diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index fa75c906fb1..bfc26fcac0f 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -63,7 +63,6 @@ #include "DNA_world_types.h" #include "BLI_utildefines.h" -#include "BLI_listbase.h" #include "BLI_ghash.h" #include "BLI_linklist_stack.h" @@ -405,7 +404,6 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP); CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP); CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP); - library_foreach_paint(&data, &toolsett->imapaint.paint); CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_USER); CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_USER); @@ -945,7 +943,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id /* Could be the following, but simpler to just always say 'yes' here. */ #if 0 return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */ - ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC + ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC /* + constraints, modifiers and game logic ID types... */); #else return true; diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index b5f34a29ebb..6f86c68dc07 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1589,7 +1589,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) } /* advance simulation, we can only step one frame forward */ - if (can_simulate) { + if (ctime == rbw->ltime + 1) { /* write cache for first frame when on second frame */ if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { BKE_ptcache_write(&pid, startframe); diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 857bd5447c8..c5d00d63b6d 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -50,6 +50,7 @@ #include "BLI_utildefines.h" #include "BLI_rect.h" +#include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_screen.h" @@ -180,6 +181,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) BLI_listbase_clear(&newar->panels_category_active); BLI_listbase_clear(&newar->ui_lists); newar->swinid = 0; + newar->manipulator_map = NULL; newar->regiontimer = NULL; /* use optional regiondata callback */ @@ -288,6 +290,17 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID } } + +/** + * Avoid bad-level calls to #WM_manipulatormap_delete. + */ +static void (*region_free_manipulatormap_callback)(struct wmManipulatorMap *) = NULL; + +void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *)) +{ + region_free_manipulatormap_callback = callback; +} + /* not region itself */ void BKE_area_region_free(SpaceType *st, ARegion *ar) { @@ -337,6 +350,8 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) MEM_freeN(uilst->properties); } } + + region_free_manipulatormap_callback(ar->manipulator_map); BLI_freelistN(&ar->ui_lists); BLI_freelistN(&ar->ui_previews); BLI_freelistN(&ar->panels_category); @@ -380,6 +395,8 @@ void BKE_screen_free(bScreen *sc) BLI_freelistN(&sc->vertbase); BLI_freelistN(&sc->edgebase); BLI_freelistN(&sc->areabase); + + BKE_previewimg_free(&sc->preview); } /* for depsgraph */ diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 03cf33083da..660107eb2e6 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -3650,7 +3650,6 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i float dtime, timescale; int framedelta, framenr, startframe, endframe; int cache_result; - cache= sb->pointcache; framenr= (int)cfra; @@ -3719,7 +3718,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i } /* try to read from cache */ - bool can_simulate = (framenr == sb->last_frame+1) && !(cache->flag & PTCACHE_BAKED); + bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED); cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate); diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h index 5e6b1256d30..c7abe6192f7 100644 --- a/source/blender/blenlib/BLI_math_color.h +++ b/source/blender/blenlib/BLI_math_color.h @@ -142,6 +142,7 @@ MINLINE void float_to_byte_dither_v3(unsigned char b[3], const float f[3], float rgba_char_args_set(col, (r) * 255, (g) * 255, (b) * 255, (a) * 255) MINLINE void rgba_char_args_set(char col[4], const char r, const char g, const char b, const char a); +MINLINE void rgba_float_args_set(float col[4], const float r, const float g, const float b, const float a); MINLINE void rgba_char_args_test_set(char col[4], const char r, const char g, const char b, const char a); MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack); diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index d0dfad2a02f..029f6872b04 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -46,31 +46,43 @@ void unit_m2(float R[2][2]); void unit_m3(float R[3][3]); void unit_m4(float R[4][4]); -void copy_m2_m2(float R[2][2], float A[2][2]); -void copy_m3_m3(float R[3][3], float A[3][3]); -void copy_m4_m4(float R[4][4], float A[4][4]); -void copy_m3_m4(float R[3][3], float A[4][4]); -void copy_m4_m3(float R[4][4], float A[3][3]); +void copy_m2_m2(float R[2][2], const float A[2][2]); +void copy_m3_m3(float R[3][3], const float A[3][3]); +void copy_m4_m4(float R[4][4], const float A[4][4]); +void copy_m3_m4(float R[3][3], const float A[4][4]); +void copy_m4_m3(float R[4][4], const float A[3][3]); /* double->float */ -void copy_m3_m3d(float R[3][3], double A[3][3]); +void copy_m3_m3d(float R[3][3], const double A[3][3]); void swap_m3m3(float A[3][3], float B[3][3]); void swap_m4m4(float A[4][4], float B[4][4]); /******************************** Arithmetic *********************************/ -void add_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]); -void add_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]); +void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]); +void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]); -void sub_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]); -void sub_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]); +void sub_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]); +void sub_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]); -void mul_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]); -void mul_m4_m3m4(float R[4][4], float A[3][3], float B[4][4]); -void mul_m4_m4m3(float R[4][4], float A[4][4], float B[3][3]); -void mul_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]); -void mul_m3_m3m4(float R[3][3], float A[4][4], float B[3][3]); +void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]); +void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4]); +void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3]); +void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]); +void mul_m3_m3m4(float R[3][3], const float A[4][4], const float B[3][3]); + +/* special matrix multiplies + * uniq: R <-- AB, R is neither A nor B + * pre: R <-- AR + * post: R <-- RB + */ +void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]); +void mul_m3_m3_pre(float R[3][3], const float A[3][3]); +void mul_m3_m3_post(float R[3][3], const float B[3][3]); +void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4]); +void mul_m4_m4_pre(float R[4][4], const float A[4][4]); +void mul_m4_m4_post(float R[4][4], const float B[4][4]); /* mul_m3_series */ void _va_mul_m3_series_3(float R[3][3], float M1[3][3], float M2[3][3]) ATTR_NONNULL(); @@ -100,27 +112,28 @@ void _va_mul_m4_series_9(float R[4][4], float M1[4][4], float M2[4][4], float M3 #define mul_m3_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m3_series_, __VA_ARGS__) #define mul_m4_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m4_series_, __VA_ARGS__) -void mul_m4_v3(float M[4][4], float r[3]); -void mul_v3_m4v3(float r[3], float M[4][4], const float v[3]); -void mul_v2_m4v3(float r[2], float M[4][4], const float v[3]); -void mul_v2_m2v2(float r[2], float M[2][2], const float v[2]); -void mul_m2v2(float M[2][2], float v[2]); -void mul_mat3_m4_v3(float M[4][4], float r[3]); -void mul_v3_mat3_m4v3(float r[3], float M[4][4], const float v[3]); -void mul_m4_v4(float M[4][4], float r[4]); -void mul_v4_m4v4(float r[4], float M[4][4], const float v[4]); -void mul_project_m4_v3(float M[4][4], float vec[3]); -void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]); -void mul_v2_project_m4_v3(float r[2], float M[4][4], const float vec[3]); - -void mul_m3_v2(float m[3][3], float r[2]); -void mul_v2_m3v2(float r[2], float m[3][3], float v[2]); -void mul_m3_v3(float M[3][3], float r[3]); -void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]); -void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]); -void mul_transposed_m3_v3(float M[3][3], float r[3]); -void mul_transposed_mat3_m4_v3(float M[4][4], float r[3]); -void mul_m3_v3_double(float M[3][3], double r[3]); +void mul_m4_v3(const float M[4][4], float r[3]); +void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3]); +void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]); +void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]); +void mul_m2v2(const float M[2][2], float v[2]); +void mul_mat3_m4_v3(const float M[4][4], float r[3]); +void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]); +void mul_m4_v4(const float M[4][4], float r[4]); +void mul_v4_m4v4(float r[4], const float M[4][4], const float v[4]); +void mul_v4_m4v3(float r[4], const float M[4][4], const float v[3]); /* v has implicit w = 1.0f */ +void mul_project_m4_v3(const float M[4][4], float vec[3]); +void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3]); +void mul_v2_project_m4_v3(float r[2], const float M[4][4], const float vec[3]); + +void mul_m3_v2(const float m[3][3], float r[2]); +void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2]); +void mul_m3_v3(const float M[3][3], float r[3]); +void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3]); +void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3]); +void mul_transposed_m3_v3(const float M[3][3], float r[3]); +void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]); +void mul_m3_v3_double(const float M[3][3], double r[3]); void mul_m3_fl(float R[3][3], float f); void mul_m4_fl(float R[4][4], float f); @@ -131,102 +144,102 @@ void negate_mat3_m4(float R[4][4]); void negate_m4(float R[4][4]); bool invert_m3_ex(float m[3][3], const float epsilon); -bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon); +bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon); bool invert_m3(float R[3][3]); -bool invert_m3_m3(float R[3][3], float A[3][3]); +bool invert_m3_m3(float R[3][3], const float A[3][3]); bool invert_m4(float R[4][4]); -bool invert_m4_m4(float R[4][4], float A[4][4]); +bool invert_m4_m4(float R[4][4], const float A[4][4]); /* double arithmetic (mixed float/double) */ -void mul_m4_v4d(float M[4][4], double r[4]); -void mul_v4d_m4v4d(double r[4], float M[4][4], double v[4]); +void mul_m4_v4d(const float M[4][4], double r[4]); +void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]); /* double matrix functions (no mixing types) */ -void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]); -void mul_m3_v3_db(double M[3][3], double r[3]); +void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]); +void mul_m3_v3_db(const double M[3][3], double r[3]); /****************************** Linear Algebra *******************************/ void transpose_m3(float R[3][3]); -void transpose_m3_m3(float R[3][3], float A[3][3]); -void transpose_m3_m4(float R[3][3], float A[4][4]); +void transpose_m3_m3(float R[3][3], const float A[3][3]); +void transpose_m3_m4(float R[3][3], const float A[4][4]); void transpose_m4(float R[4][4]); -void transpose_m4_m4(float R[4][4], float A[4][4]); +void transpose_m4_m4(float R[4][4], const float A[4][4]); -int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit); +int compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit); void normalize_m3_ex(float R[3][3], float r_scale[3]) ATTR_NONNULL(); void normalize_m3(float R[3][3]) ATTR_NONNULL(); -void normalize_m3_m3_ex(float R[3][3], float A[3][3], float r_scale[3]) ATTR_NONNULL(); -void normalize_m3_m3(float R[3][3], float A[3][3]) ATTR_NONNULL(); +void normalize_m3_m3_ex(float R[3][3], const float A[3][3], float r_scale[3]) ATTR_NONNULL(); +void normalize_m3_m3(float R[3][3], const float A[3][3]) ATTR_NONNULL(); void normalize_m4_ex(float R[4][4], float r_scale[3]) ATTR_NONNULL(); void normalize_m4(float R[4][4]) ATTR_NONNULL(); -void normalize_m4_m4_ex(float R[4][4], float A[4][4], float r_scale[3]) ATTR_NONNULL(); -void normalize_m4_m4(float R[4][4], float A[4][4]) ATTR_NONNULL(); +void normalize_m4_m4_ex(float R[4][4], const float A[4][4], float r_scale[3]) ATTR_NONNULL(); +void normalize_m4_m4(float R[4][4],const float A[4][4]) ATTR_NONNULL(); void orthogonalize_m3(float R[3][3], int axis); void orthogonalize_m4(float R[4][4], int axis); -bool is_orthogonal_m3(float mat[3][3]); -bool is_orthogonal_m4(float mat[4][4]); -bool is_orthonormal_m3(float mat[3][3]); -bool is_orthonormal_m4(float mat[4][4]); +bool is_orthogonal_m3(const float mat[3][3]); +bool is_orthogonal_m4(const float mat[4][4]); +bool is_orthonormal_m3(const float mat[3][3]); +bool is_orthonormal_m4(const float mat[4][4]); -bool is_uniform_scaled_m3(float mat[3][3]); -bool is_uniform_scaled_m4(float m[4][4]); +bool is_uniform_scaled_m3(const float mat[3][3]); +bool is_uniform_scaled_m4(const float m[4][4]); /* Note: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix! * Nowadays 'adjoint' usually refers to the conjugate transpose, * which for real-valued matrices is simply the transpose. */ -void adjoint_m2_m2(float R[2][2], float A[2][2]); -void adjoint_m3_m3(float R[3][3], float A[3][3]); -void adjoint_m4_m4(float R[4][4], float A[4][4]); +void adjoint_m2_m2(float R[2][2], const float A[2][2]); +void adjoint_m3_m3(float R[3][3], const float A[3][3]); +void adjoint_m4_m4(float R[4][4], const float A[4][4]); float determinant_m2(float a, float b, float c, float d); float determinant_m3(float a, float b, float c, float d, float e, float f, float g, float h, float i); -float determinant_m3_array(float m[3][3]); -float determinant_m4(float A[4][4]); +float determinant_m3_array(const float m[3][3]); +float determinant_m4(const float A[4][4]); #define PSEUDOINVERSE_EPSILON 1e-8f void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]); -void pseudoinverse_m4_m4(float Ainv[4][4], float A[4][4], float epsilon); -void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon); +void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon); +void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon); -bool has_zero_axis_m4(float matrix[4][4]); +bool has_zero_axis_m4(const float matrix[4][4]); -void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]); +void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]); /****************************** Transformations ******************************/ void scale_m3_fl(float R[3][3], float scale); void scale_m4_fl(float R[4][4], float scale); -float mat3_to_scale(float M[3][3]); -float mat4_to_scale(float M[4][4]); +float mat3_to_scale(const float M[3][3]); +float mat4_to_scale(const float M[4][4]); void size_to_mat3(float R[3][3], const float size[3]); void size_to_mat4(float R[4][4], const float size[3]); -void mat3_to_size(float r[3], float M[3][3]); -void mat4_to_size(float r[3], float M[4][4]); +void mat3_to_size(float r[3], const float M[3][3]); +void mat4_to_size(float r[3], const float M[4][4]); void translate_m4(float mat[4][4], float tx, float ty, float tz); void rotate_m4(float mat[4][4], const char axis, const float angle); void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); -void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]); -void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wmat[4][4]); -void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4]); -void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4]); +void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]); +void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]); +void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]); +void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4]); -void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]); +void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]); void loc_eul_size_to_mat4(float R[4][4], const float loc[3], const float eul[3], const float size[3]); @@ -237,20 +250,20 @@ void loc_quat_size_to_mat4(float R[4][4], void loc_axisangle_size_to_mat4(float R[4][4], const float loc[3], const float axis[4], const float angle, const float size[3]); -void blend_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t); -void blend_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t); +void blend_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t); +void blend_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t); -void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t); -void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t); +void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t); +void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t); -bool is_negative_m3(float mat[3][3]); -bool is_negative_m4(float mat[4][4]); +bool is_negative_m3(const float mat[3][3]); +bool is_negative_m4(const float mat[4][4]); -bool is_zero_m3(float mat[3][3]); -bool is_zero_m4(float mat[4][4]); +bool is_zero_m3(const float mat[3][3]); +bool is_zero_m4(const float mat[4][4]); -bool equals_m3m3(float mat1[3][3], float mat2[3][3]); -bool equals_m4m4(float mat1[4][4], float mat2[4][4]); +bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]); +bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]); /* SpaceTransform helper */ typedef struct SpaceTransform { @@ -259,8 +272,8 @@ typedef struct SpaceTransform { } SpaceTransform; -void BLI_space_transform_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]); -void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]); +void BLI_space_transform_from_matrices(struct SpaceTransform *data, const float local[4][4], const float target[4][4]); +void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, const float local[4][4], const float target[4][4]); void BLI_space_transform_apply(const struct SpaceTransform *data, float co[3]); void BLI_space_transform_invert(const struct SpaceTransform *data, float co[3]); void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float no[3]); @@ -271,8 +284,8 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float /*********************************** Other ***********************************/ -void print_m3(const char *str, float M[3][3]); -void print_m4(const char *str, float M[4][4]); +void print_m3(const char *str, const float M[3][3]); +void print_m4(const char *str, const float M[4][4]); #define print_m3_id(M) print_m3(STRINGIFY(M), M) #define print_m4_id(M) print_m4(STRINGIFY(M), M) diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index d15fe1a95dc..f5beda0f13e 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -304,6 +304,7 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]); void ortho_v3_v3(float out[3], const float v[3]); void ortho_v2_v2(float out[2], const float v[2]); void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]); +void rotate_v2_v2fl(float r[2], const float p[2], const float angle); void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle); void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle); diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index 01a805a09b6..bc3a1ee3e90 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -239,6 +239,14 @@ MINLINE void rgba_char_args_set(char col[4], const char r, const char g, const c col[3] = a; } +MINLINE void rgba_float_args_set(float col[4], const float r, const float g, const float b, const float a) +{ + col[0] = r; + col[1] = g; + col[2] = b; + col[3] = a; +} + MINLINE void rgba_char_args_test_set(char col[4], const char r, const char g, const char b, const char a) { if (col[3] == 0) { diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 9a60c670ec7..50b92f5a383 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -74,23 +74,23 @@ void unit_m4(float m[4][4]) m[3][0] = m[3][1] = m[3][2] = 0.0f; } -void copy_m2_m2(float m1[2][2], float m2[2][2]) +void copy_m2_m2(float m1[2][2], const float m2[2][2]) { memcpy(m1, m2, sizeof(float[2][2])); } -void copy_m3_m3(float m1[3][3], float m2[3][3]) +void copy_m3_m3(float m1[3][3], const float m2[3][3]) { /* destination comes first: */ memcpy(m1, m2, sizeof(float[3][3])); } -void copy_m4_m4(float m1[4][4], float m2[4][4]) +void copy_m4_m4(float m1[4][4], const float m2[4][4]) { memcpy(m1, m2, sizeof(float[4][4])); } -void copy_m3_m4(float m1[3][3], float m2[4][4]) +void copy_m3_m4(float m1[3][3], const float m2[4][4]) { m1[0][0] = m2[0][0]; m1[0][1] = m2[0][1]; @@ -105,7 +105,7 @@ void copy_m3_m4(float m1[3][3], float m2[4][4]) m1[2][2] = m2[2][2]; } -void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */ +void copy_m4_m3(float m1[4][4], const float m2[3][3]) /* no clear */ { m1[0][0] = m2[0][0]; m1[0][1] = m2[0][1]; @@ -131,7 +131,7 @@ void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */ } -void copy_m3_m3d(float R[3][3], double A[3][3]) +void copy_m3_m3d(float R[3][3], const double A[3][3]) { /* Keep it stupid simple for better data flow in CPU. */ R[0][0] = (float)A[0][0]; @@ -177,64 +177,107 @@ void swap_m4m4(float m1[4][4], float m2[4][4]) /******************************** Arithmetic *********************************/ -void mul_m4_m4m4(float m1[4][4], float m3_[4][4], float m2_[4][4]) +void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]) { - float m2[4][4], m3[4][4]; + if (A == R) + mul_m4_m4_post(R, B); + else if (B == R) + mul_m4_m4_pre(R, A); + else + mul_m4_m4m4_uniq(R, A, B); +} - /* copy so it works when m1 is the same pointer as m2 or m3 */ - copy_m4_m4(m2, m2_); - copy_m4_m4(m3, m3_); +void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4]) +{ + BLI_assert(R != A && R != B); - /* matrix product: m1[j][k] = m2[j][i].m3[i][k] */ - m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] + m2[0][2] * m3[2][0] + m2[0][3] * m3[3][0]; - m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] + m2[0][2] * m3[2][1] + m2[0][3] * m3[3][1]; - m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] + m2[0][2] * m3[2][2] + m2[0][3] * m3[3][2]; - m1[0][3] = m2[0][0] * m3[0][3] + m2[0][1] * m3[1][3] + m2[0][2] * m3[2][3] + m2[0][3] * m3[3][3]; + /* matrix product: R[j][k] = A[j][i] . B[i][k] */ + R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0]; + R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1]; + R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2] + B[0][3] * A[3][2]; + R[0][3] = B[0][0] * A[0][3] + B[0][1] * A[1][3] + B[0][2] * A[2][3] + B[0][3] * A[3][3]; - m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] + m2[1][2] * m3[2][0] + m2[1][3] * m3[3][0]; - m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] + m2[1][2] * m3[2][1] + m2[1][3] * m3[3][1]; - m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] + m2[1][2] * m3[2][2] + m2[1][3] * m3[3][2]; - m1[1][3] = m2[1][0] * m3[0][3] + m2[1][1] * m3[1][3] + m2[1][2] * m3[2][3] + m2[1][3] * m3[3][3]; + R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0] + B[1][3] * A[3][0]; + R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1] + B[1][3] * A[3][1]; + R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2] + B[1][3] * A[3][2]; + R[1][3] = B[1][0] * A[0][3] + B[1][1] * A[1][3] + B[1][2] * A[2][3] + B[1][3] * A[3][3]; - m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] + m2[2][2] * m3[2][0] + m2[2][3] * m3[3][0]; - m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] + m2[2][2] * m3[2][1] + m2[2][3] * m3[3][1]; - m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2] + m2[2][3] * m3[3][2]; - m1[2][3] = m2[2][0] * m3[0][3] + m2[2][1] * m3[1][3] + m2[2][2] * m3[2][3] + m2[2][3] * m3[3][3]; + R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0] + B[2][3] * A[3][0]; + R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1] + B[2][3] * A[3][1]; + R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2] + B[2][3] * A[3][2]; + R[2][3] = B[2][0] * A[0][3] + B[2][1] * A[1][3] + B[2][2] * A[2][3] + B[2][3] * A[3][3]; - m1[3][0] = m2[3][0] * m3[0][0] + m2[3][1] * m3[1][0] + m2[3][2] * m3[2][0] + m2[3][3] * m3[3][0]; - m1[3][1] = m2[3][0] * m3[0][1] + m2[3][1] * m3[1][1] + m2[3][2] * m3[2][1] + m2[3][3] * m3[3][1]; - m1[3][2] = m2[3][0] * m3[0][2] + m2[3][1] * m3[1][2] + m2[3][2] * m3[2][2] + m2[3][3] * m3[3][2]; - m1[3][3] = m2[3][0] * m3[0][3] + m2[3][1] * m3[1][3] + m2[3][2] * m3[2][3] + m2[3][3] * m3[3][3]; + R[3][0] = B[3][0] * A[0][0] + B[3][1] * A[1][0] + B[3][2] * A[2][0] + B[3][3] * A[3][0]; + R[3][1] = B[3][0] * A[0][1] + B[3][1] * A[1][1] + B[3][2] * A[2][1] + B[3][3] * A[3][1]; + R[3][2] = B[3][0] * A[0][2] + B[3][1] * A[1][2] + B[3][2] * A[2][2] + B[3][3] * A[3][2]; + R[3][3] = B[3][0] * A[0][3] + B[3][1] * A[1][3] + B[3][2] * A[2][3] + B[3][3] * A[3][3]; +} +void mul_m4_m4_pre(float R[4][4], const float A[4][4]) +{ + BLI_assert(A != R); + float B[4][4]; + copy_m4_m4(B, R); + mul_m4_m4m4_uniq(R, A, B); } -void mul_m3_m3m3(float m1[3][3], float m3_[3][3], float m2_[3][3]) +void mul_m4_m4_post(float R[4][4], const float B[4][4]) { - float m2[3][3], m3[3][3]; + BLI_assert(B != R); + float A[4][4]; + copy_m4_m4(A, R); + mul_m4_m4m4_uniq(R, A, B); +} - /* copy so it works when m1 is the same pointer as m2 or m3 */ - copy_m3_m3(m2, m2_); - copy_m3_m3(m3, m3_); +void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]) +{ + if (A == R) + mul_m3_m3_post(R, B); + else if (B == R) + mul_m3_m3_pre(R, A); + else + mul_m3_m3m3_uniq(R, A, B); +} - /* m1[i][j] = m2[i][k] * m3[k][j], args are flipped! */ - m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] + m2[0][2] * m3[2][0]; - m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] + m2[0][2] * m3[2][1]; - m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] + m2[0][2] * m3[2][2]; +void mul_m3_m3_pre(float R[3][3], const float A[3][3]) +{ + BLI_assert(A != R); + float B[3][3]; + copy_m3_m3(B, R); + mul_m3_m3m3_uniq(R, A, B); +} - m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] + m2[1][2] * m3[2][0]; - m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] + m2[1][2] * m3[2][1]; - m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] + m2[1][2] * m3[2][2]; +void mul_m3_m3_post(float R[3][3], const float B[3][3]) +{ + BLI_assert(B != R); + float A[3][3]; + copy_m3_m3(A, R); + mul_m3_m3m3_uniq(R, A, B); +} - m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] + m2[2][2] * m3[2][0]; - m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] + m2[2][2] * m3[2][1]; - m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2]; +void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]) +{ + BLI_assert(R != A && R != B); + + R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0]; + R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1]; + R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2]; + + R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0]; + R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1]; + R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2]; + + R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0]; + R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1]; + R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2]; } -void mul_m4_m4m3(float m1[4][4], float m3_[4][4], float m2_[3][3]) +void mul_m4_m4m3(float m1[4][4], const float m3_[4][4], const float m2_[3][3]) { float m2[3][3], m3[4][4]; /* copy so it works when m1 is the same pointer as m2 or m3 */ + /* TODO: avoid copying when matrices are different */ copy_m3_m3(m2, m2_); copy_m4_m4(m3, m3_); @@ -250,11 +293,12 @@ void mul_m4_m4m3(float m1[4][4], float m3_[4][4], float m2_[3][3]) } /* m1 = m2 * m3, ignore the elements on the 4th row/column of m3 */ -void mul_m3_m3m4(float m1[3][3], float m3_[4][4], float m2_[3][3]) +void mul_m3_m3m4(float m1[3][3], const float m3_[4][4], const float m2_[3][3]) { float m2[3][3], m3[4][4]; /* copy so it works when m1 is the same pointer as m2 or m3 */ + /* TODO: avoid copying when matrices are different */ copy_m3_m3(m2, m2_); copy_m4_m4(m3, m3_); @@ -272,11 +316,12 @@ void mul_m3_m3m4(float m1[3][3], float m3_[4][4], float m2_[3][3]) m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2]; } -void mul_m4_m3m4(float m1[4][4], float m3_[3][3], float m2_[4][4]) +void mul_m4_m3m4(float m1[4][4], const float m3_[3][3], const float m2_[4][4]) { float m2[4][4], m3[3][3]; /* copy so it works when m1 is the same pointer as m2 or m3 */ + /* TODO: avoid copying when matrices are different */ copy_m4_m4(m2, m2_); copy_m3_m3(m3, m3_); @@ -434,7 +479,7 @@ void _va_mul_m4_series_9( } /** \} */ -void mul_v2_m3v2(float r[2], float m[3][3], float v[2]) +void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2]) { float temp[3], warped[3]; @@ -447,12 +492,12 @@ void mul_v2_m3v2(float r[2], float m[3][3], float v[2]) r[1] = warped[1] / warped[2]; } -void mul_m3_v2(float m[3][3], float r[2]) +void mul_m3_v2(const float m[3][3], float r[2]) { mul_v2_m3v2(r, m, r); } -void mul_m4_v3(float mat[4][4], float vec[3]) +void mul_m4_v3(const float mat[4][4], float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -462,7 +507,7 @@ void mul_m4_v3(float mat[4][4], float vec[3]) vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2]; } -void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3]) +void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -472,7 +517,7 @@ void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3]) r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2]; } -void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3]) +void mul_v2_m4v3(float r[2], const float mat[4][4], const float vec[3]) { const float x = vec[0]; @@ -480,7 +525,7 @@ void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3]) r[1] = x * mat[0][1] + vec[1] * mat[1][1] + mat[2][1] * vec[2] + mat[3][1]; } -void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2]) +void mul_v2_m2v2(float r[2], const float mat[2][2], const float vec[2]) { const float x = vec[0]; @@ -488,13 +533,13 @@ void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2]) r[1] = mat[0][1] * x + mat[1][1] * vec[1]; } -void mul_m2v2(float mat[2][2], float vec[2]) +void mul_m2v2(const float mat[2][2], float vec[2]) { mul_v2_m2v2(vec, mat, vec); } /* same as mul_m4_v3() but doesnt apply translation component */ -void mul_mat3_m4_v3(float mat[4][4], float vec[3]) +void mul_mat3_m4_v3(const float mat[4][4], float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -504,7 +549,7 @@ void mul_mat3_m4_v3(float mat[4][4], float vec[3]) vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2]; } -void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3]) +void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -514,7 +559,7 @@ void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3]) r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2]; } -void mul_project_m4_v3(float mat[4][4], float vec[3]) +void mul_project_m4_v3(const float mat[4][4], float vec[3]) { /* absolute value to not flip the frustum upside down behind the camera */ const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); @@ -525,7 +570,7 @@ void mul_project_m4_v3(float mat[4][4], float vec[3]) vec[2] /= w; } -void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]) +void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3]) { const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); mul_v3_m4v3(r, mat, vec); @@ -535,7 +580,7 @@ void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]) r[2] /= w; } -void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3]) +void mul_v2_project_m4_v3(float r[2], const float mat[4][4], const float vec[3]) { const float w = fabsf(mul_project_m4_v3_zfac(mat, vec)); mul_v2_m4v3(r, mat, vec); @@ -544,7 +589,7 @@ void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3]) r[1] /= w; } -void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4]) +void mul_v4_m4v4(float r[4], const float mat[4][4], const float v[4]) { const float x = v[0]; const float y = v[1]; @@ -556,12 +601,12 @@ void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4]) r[3] = x * mat[0][3] + y * mat[1][3] + z * mat[2][3] + mat[3][3] * v[3]; } -void mul_m4_v4(float mat[4][4], float r[4]) +void mul_m4_v4(const float mat[4][4], float r[4]) { mul_v4_m4v4(r, mat, r); } -void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4]) +void mul_v4d_m4v4d(double r[4], const float mat[4][4], const double v[4]) { const double x = v[0]; const double y = v[1]; @@ -573,12 +618,21 @@ void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4]) r[3] = x * (double)mat[0][3] + y * (double)mat[1][3] + z * (double)mat[2][3] + (double)mat[3][3] * v[3]; } -void mul_m4_v4d(float mat[4][4], double r[4]) +void mul_m4_v4d(const float mat[4][4], double r[4]) { mul_v4d_m4v4d(r, mat, r); } -void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]) +void mul_v4_m4v3(float r[4], const float M[4][4], const float v[3]) +{ + /* v has implicit w = 1.0f */ + r[0] = v[0] * M[0][0] + v[1] * M[1][0] + M[2][0] * v[2] + M[3][0]; + r[1] = v[0] * M[0][1] + v[1] * M[1][1] + M[2][1] * v[2] + M[3][1]; + r[2] = v[0] * M[0][2] + v[1] * M[1][2] + M[2][2] * v[2] + M[3][2]; + r[3] = v[0] * M[0][3] + v[1] * M[1][3] + M[2][3] * v[2] + M[3][3]; +} + +void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3]) { BLI_assert(r != a); @@ -587,7 +641,7 @@ void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]) r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; } -void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]) +void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]) { BLI_assert(r != a); @@ -596,7 +650,7 @@ void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]) r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; } -void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]) +void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3]) { BLI_assert(r != a); @@ -604,17 +658,17 @@ void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]) r[1] = M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2]; } -void mul_m3_v3(float M[3][3], float r[3]) +void mul_m3_v3(const float M[3][3], float r[3]) { mul_v3_m3v3(r, M, (const float[3]){UNPACK3(r)}); } -void mul_m3_v3_db(double M[3][3], double r[3]) +void mul_m3_v3_db(const double M[3][3], double r[3]) { mul_v3_m3v3_db(r, M, (const double[3]){UNPACK3(r)}); } -void mul_transposed_m3_v3(float mat[3][3], float vec[3]) +void mul_transposed_m3_v3(const float mat[3][3], float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -624,7 +678,7 @@ void mul_transposed_m3_v3(float mat[3][3], float vec[3]) vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2]; } -void mul_transposed_mat3_m4_v3(float mat[4][4], float vec[3]) +void mul_transposed_mat3_m4_v3(const float mat[4][4], float vec[3]) { const float x = vec[0]; const float y = vec[1]; @@ -688,7 +742,7 @@ void negate_m4(float m[4][4]) m[i][j] *= -1.0f; } -void mul_m3_v3_double(float mat[3][3], double vec[3]) +void mul_m3_v3_double(const float mat[3][3], double vec[3]) { const double x = vec[0]; const double y = vec[1]; @@ -698,7 +752,7 @@ void mul_m3_v3_double(float mat[3][3], double vec[3]) vec[2] = x * (double)mat[0][2] + y * (double)mat[1][2] + (double)mat[2][2] * vec[2]; } -void add_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3]) +void add_m3_m3m3(float m1[3][3], const float m2[3][3], const float m3[3][3]) { int i, j; @@ -707,7 +761,7 @@ void add_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3]) m1[i][j] = m2[i][j] + m3[i][j]; } -void add_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4]) +void add_m4_m4m4(float m1[4][4], const float m2[4][4], const float m3[4][4]) { int i, j; @@ -716,7 +770,7 @@ void add_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4]) m1[i][j] = m2[i][j] + m3[i][j]; } -void sub_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3]) +void sub_m3_m3m3(float m1[3][3], const float m2[3][3], const float m3[3][3]) { int i, j; @@ -725,7 +779,7 @@ void sub_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3]) m1[i][j] = m2[i][j] - m3[i][j]; } -void sub_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4]) +void sub_m4_m4m4(float m1[4][4], const float m2[4][4], const float m3[4][4]) { int i, j; @@ -734,7 +788,7 @@ void sub_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4]) m1[i][j] = m2[i][j] - m3[i][j]; } -float determinant_m3_array(float m[3][3]) +float determinant_m3_array(const float m[3][3]) { return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) + @@ -750,7 +804,7 @@ bool invert_m3_ex(float m[3][3], const float epsilon) return success; } -bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon) +bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon) { float det; int a, b; @@ -786,7 +840,7 @@ bool invert_m3(float m[3][3]) return success; } -bool invert_m3_m3(float m1[3][3], float m2[3][3]) +bool invert_m3_m3(float m1[3][3], const float m2[3][3]) { float det; int a, b; @@ -830,7 +884,7 @@ bool invert_m4(float m[4][4]) * Mark Segal - 1992 */ -bool invert_m4_m4(float inverse[4][4], float mat[4][4]) +bool invert_m4_m4(float inverse[4][4], const float mat[4][4]) { int i, j, k; double temp; @@ -908,7 +962,7 @@ void transpose_m3(float mat[3][3]) mat[2][1] = t; } -void transpose_m3_m3(float rmat[3][3], float mat[3][3]) +void transpose_m3_m3(float rmat[3][3], const float mat[3][3]) { BLI_assert(rmat != mat); @@ -924,7 +978,7 @@ void transpose_m3_m3(float rmat[3][3], float mat[3][3]) } /* seems obscure but in-fact a common operation */ -void transpose_m3_m4(float rmat[3][3], float mat[4][4]) +void transpose_m3_m4(float rmat[3][3], const float mat[4][4]) { BLI_assert(&rmat[0][0] != &mat[0][0]); @@ -965,7 +1019,7 @@ void transpose_m4(float mat[4][4]) mat[3][2] = t; } -void transpose_m4_m4(float rmat[4][4], float mat[4][4]) +void transpose_m4_m4(float rmat[4][4], const float mat[4][4]) { BLI_assert(rmat != mat); @@ -987,7 +1041,8 @@ void transpose_m4_m4(float rmat[4][4], float mat[4][4]) rmat[3][3] = mat[3][3]; } -int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit) +/* TODO: return bool */ +int compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit) { if (compare_v4v4(mat1[0], mat2[0], limit)) if (compare_v4v4(mat1[1], mat2[1], limit)) @@ -1165,7 +1220,7 @@ void orthogonalize_m4(float mat[4][4], int axis) mul_v3_fl(mat[2], size[2]); } -bool is_orthogonal_m3(float m[3][3]) +bool is_orthogonal_m3(const float m[3][3]) { int i, j; @@ -1179,7 +1234,7 @@ bool is_orthogonal_m3(float m[3][3]) return true; } -bool is_orthogonal_m4(float m[4][4]) +bool is_orthogonal_m4(const float m[4][4]) { int i, j; @@ -1194,7 +1249,7 @@ bool is_orthogonal_m4(float m[4][4]) return true; } -bool is_orthonormal_m3(float m[3][3]) +bool is_orthonormal_m3(const float m[3][3]) { if (is_orthogonal_m3(m)) { int i; @@ -1209,7 +1264,7 @@ bool is_orthonormal_m3(float m[3][3]) return false; } -bool is_orthonormal_m4(float m[4][4]) +bool is_orthonormal_m4(const float m[4][4]) { if (is_orthogonal_m4(m)) { int i; @@ -1224,7 +1279,7 @@ bool is_orthonormal_m4(float m[4][4]) return false; } -bool is_uniform_scaled_m3(float m[3][3]) +bool is_uniform_scaled_m3(const float m[3][3]) { const float eps = 1e-7f; float t[3][3]; @@ -1252,7 +1307,7 @@ bool is_uniform_scaled_m3(float m[3][3]) return false; } -bool is_uniform_scaled_m4(float m[4][4]) +bool is_uniform_scaled_m4(const float m[4][4]) { float t[3][3]; copy_m3_m4(t, m); @@ -1274,14 +1329,14 @@ void normalize_m3(float mat[3][3]) } } -void normalize_m3_m3_ex(float rmat[3][3], float mat[3][3], float r_scale[3]) +void normalize_m3_m3_ex(float rmat[3][3], const float mat[3][3], float r_scale[3]) { int i; for (i = 0; i < 3; i++) { r_scale[i] = normalize_v3_v3(rmat[i], mat[i]); } } -void normalize_m3_m3(float rmat[3][3], float mat[3][3]) +void normalize_m3_m3(float rmat[3][3], const float mat[3][3]) { int i; for (i = 0; i < 3; i++) { @@ -1310,7 +1365,7 @@ void normalize_m4(float mat[4][4]) } } -void normalize_m4_m4_ex(float rmat[4][4], float mat[4][4], float r_scale[3]) +void normalize_m4_m4_ex(float rmat[4][4], const float mat[4][4], float r_scale[3]) { int i; for (i = 0; i < 3; i++) { @@ -1319,7 +1374,7 @@ void normalize_m4_m4_ex(float rmat[4][4], float mat[4][4], float r_scale[3]) } copy_v4_v4(rmat[3], mat[3]); } -void normalize_m4_m4(float rmat[4][4], float mat[4][4]) +void normalize_m4_m4(float rmat[4][4], const float mat[4][4]) { int i; for (i = 0; i < 3; i++) { @@ -1329,7 +1384,7 @@ void normalize_m4_m4(float rmat[4][4], float mat[4][4]) copy_v4_v4(rmat[3], mat[3]); } -void adjoint_m2_m2(float m1[2][2], float m[2][2]) +void adjoint_m2_m2(float m1[2][2], const float m[2][2]) { BLI_assert(m1 != m); m1[0][0] = m[1][1]; @@ -1338,7 +1393,7 @@ void adjoint_m2_m2(float m1[2][2], float m[2][2]) m1[1][1] = m[0][0]; } -void adjoint_m3_m3(float m1[3][3], float m[3][3]) +void adjoint_m3_m3(float m1[3][3], const float m[3][3]) { BLI_assert(m1 != m); m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1]; @@ -1354,7 +1409,7 @@ void adjoint_m3_m3(float m1[3][3], float m[3][3]) m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0]; } -void adjoint_m4_m4(float out[4][4], float in[4][4]) /* out = ADJ(in) */ +void adjoint_m4_m4(float out[4][4], const float in[4][4]) /* out = ADJ(in) */ { float a1, a2, a3, a4, b1, b2, b3, b4; float c1, c2, c3, c4, d1, d2, d3, d4; @@ -1420,7 +1475,7 @@ float determinant_m3(float a1, float a2, float a3, return ans; } -float determinant_m4(float m[4][4]) +float determinant_m4(const float m[4][4]) { float ans; float a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4; @@ -1488,14 +1543,14 @@ void size_to_mat4(float mat[4][4], const float size[3]) mat[3][3] = 1.0f; } -void mat3_to_size(float size[3], float mat[3][3]) +void mat3_to_size(float size[3], const float mat[3][3]) { size[0] = len_v3(mat[0]); size[1] = len_v3(mat[1]); size[2] = len_v3(mat[2]); } -void mat4_to_size(float size[3], float mat[4][4]) +void mat4_to_size(float size[3], const float mat[4][4]) { size[0] = len_v3(mat[0]); size[1] = len_v3(mat[1]); @@ -1505,7 +1560,7 @@ void mat4_to_size(float size[3], float mat[4][4]) /* this gets the average scale of a matrix, only use when your scaling * data that has no idea of scale axis, examples are bone-envelope-radius * and curve radius */ -float mat3_to_scale(float mat[3][3]) +float mat3_to_scale(const float mat[3][3]) { /* unit length vector */ float unit_vec[3]; @@ -1514,7 +1569,7 @@ float mat3_to_scale(float mat[3][3]) return len_v3(unit_vec); } -float mat4_to_scale(float mat[4][4]) +float mat4_to_scale(const float mat[4][4]) { /* unit length vector */ float unit_vec[3]; @@ -1523,7 +1578,7 @@ float mat4_to_scale(float mat[4][4]) return len_v3(unit_vec); } -void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]) +void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]) { /* keep rot as a 3x3 matrix, the caller can convert into a quat or euler */ size[0] = normalize_v3_v3(rot[0], mat3[0]); @@ -1535,7 +1590,7 @@ void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]) } } -void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wmat[4][4]) +void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]) { float mat3[3][3]; /* wmat -> 3x3 */ @@ -1546,7 +1601,7 @@ void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wm copy_v3_v3(loc, wmat[3]); } -void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4]) +void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]) { float mat3[3][3]; float mat3_n[3][3]; /* normalized mat3 */ @@ -1564,7 +1619,7 @@ void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4]) copy_v3_v3(loc, wmat[3]); } -void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4]) +void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4]) { float rot[3][3]; mat4_to_loc_rot_size(loc, rot, size, wmat); @@ -1581,7 +1636,7 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4] * See https://en.wikipedia.org/wiki/Polar_decomposition for more. */ #ifndef MATH_STANDALONE -void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]) +void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]) { /* From svd decomposition (M = WSV*), we have: * U = WV* @@ -1625,6 +1680,7 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz) mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]); } +/* TODO: enum for axis? */ /** * Rotate a matrix in-place. * @@ -1688,7 +1744,7 @@ void transform_pivot_set_m4(float mat[4][4], const float pivot[3]) mul_m4_m4m4(mat, mat, tmat); } -void blend_m3_m3m3(float out[3][3], float dst[3][3], float src[3][3], const float srcweight) +void blend_m3_m3m3(float out[3][3], const float dst[3][3], const float src[3][3], const float srcweight) { float srot[3][3], drot[3][3]; float squat[4], dquat[4], fquat[4]; @@ -1711,7 +1767,7 @@ void blend_m3_m3m3(float out[3][3], float dst[3][3], float src[3][3], const floa mul_m3_m3m3(out, rmat, smat); } -void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const float srcweight) +void blend_m4_m4m4(float out[4][4], const float dst[4][4], const float src[4][4], const float srcweight) { float sloc[3], dloc[3], floc[3]; float srot[3][3], drot[3][3]; @@ -1749,7 +1805,7 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa * @param B the intput matrix which is totally effective with \a t = 1.0. * @param t the interpolation factor. */ -void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t) +void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t) { /* 'Rotation' component ('U' part of polar decomposition, the closest orthogonal matrix to M3 rot/scale * transformation matrix), spherically interpolated. */ @@ -1784,7 +1840,7 @@ void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t) * @param B the intput matrix which is totally effective with \a t = 1.0. * @param t the interpolation factor. */ -void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t) +void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t) { float A3[3][3], B3[3][3], R3[3][3]; @@ -1805,27 +1861,27 @@ void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t) } #endif /* MATH_STANDALONE */ -bool is_negative_m3(float mat[3][3]) +bool is_negative_m3(const float mat[3][3]) { float vec[3]; cross_v3_v3v3(vec, mat[0], mat[1]); return (dot_v3v3(vec, mat[2]) < 0.0f); } -bool is_negative_m4(float mat[4][4]) +bool is_negative_m4(const float mat[4][4]) { float vec[3]; cross_v3_v3v3(vec, mat[0], mat[1]); return (dot_v3v3(vec, mat[2]) < 0.0f); } -bool is_zero_m3(float mat[3][3]) +bool is_zero_m3(const float mat[3][3]) { return (is_zero_v3(mat[0]) && is_zero_v3(mat[1]) && is_zero_v3(mat[2])); } -bool is_zero_m4(float mat[4][4]) +bool is_zero_m4(const float mat[4][4]) { return (is_zero_v4(mat[0]) && is_zero_v4(mat[1]) && @@ -1833,14 +1889,14 @@ bool is_zero_m4(float mat[4][4]) is_zero_v4(mat[3])); } -bool equals_m3m3(float mat1[3][3], float mat2[3][3]) +bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]) { return (equals_v3v3(mat1[0], mat2[0]) && equals_v3v3(mat1[1], mat2[1]) && equals_v3v3(mat1[2], mat2[2])); } -bool equals_m4m4(float mat1[4][4], float mat2[4][4]) +bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]) { return (equals_v4v4(mat1[0], mat2[0]) && equals_v4v4(mat1[1], mat2[1]) && @@ -1931,7 +1987,7 @@ void loc_axisangle_size_to_mat4(float mat[4][4], const float loc[3], const float /*********************************** Other ***********************************/ -void print_m3(const char *str, float m[3][3]) +void print_m3(const char *str, const float m[3][3]) { printf("%s\n", str); printf("%f %f %f\n", m[0][0], m[1][0], m[2][0]); @@ -1940,7 +1996,7 @@ void print_m3(const char *str, float m[3][3]) printf("\n"); } -void print_m4(const char *str, float m[4][4]) +void print_m4(const char *str, const float m[4][4]) { printf("%s\n", str); printf("%f %f %f %f\n", m[0][0], m[1][0], m[2][0], m[3][0]); @@ -2394,7 +2450,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4]) } } -void pseudoinverse_m4_m4(float Ainv[4][4], float A_[4][4], float epsilon) +void pseudoinverse_m4_m4(float Ainv[4][4], const float A_[4][4], float epsilon) { /* compute Moore-Penrose pseudo inverse of matrix, singular values * below epsilon are ignored for stability (truncated SVD) */ @@ -2415,7 +2471,7 @@ void pseudoinverse_m4_m4(float Ainv[4][4], float A_[4][4], float epsilon) mul_m4_series(Ainv, U, Wm, V); } -void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon) +void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon) { /* try regular inverse when possible, otherwise fall back to slow svd */ if (!invert_m3_m3(Ainv, A)) { @@ -2427,14 +2483,14 @@ void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon) } } -bool has_zero_axis_m4(float matrix[4][4]) +bool has_zero_axis_m4(const float matrix[4][4]) { return len_squared_v3(matrix[0]) < FLT_EPSILON || len_squared_v3(matrix[1]) < FLT_EPSILON || len_squared_v3(matrix[2]) < FLT_EPSILON; } -void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]) +void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]) { if (!invert_m4_m4(Ainv, A)) { float Atemp[4][4]; @@ -2482,7 +2538,7 @@ void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]) * this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z) * where (x', y', z') are the coordinates of P' in target space such that it keeps (X, Y, Z) coordinates in global space. */ -void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4]) +void BLI_space_transform_from_matrices(SpaceTransform *data, const float local[4][4], const float target[4][4]) { float itarget[4][4]; invert_m4_m4(itarget, target); @@ -2500,7 +2556,7 @@ void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4], * this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z) * where (X', Y', Z') are the coordinates of p' in global space such that it keeps (x, y, z) coordinates in target space. */ -void BLI_space_transform_global_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4]) +void BLI_space_transform_global_from_matrices(SpaceTransform *data, const float local[4][4], const float target[4][4]) { float ilocal[4][4]; invert_m4_m4(ilocal, local); diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 95d5c9fde87..90e39da5d46 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -772,6 +772,20 @@ void ortho_v2_v2(float out[2], const float v[2]) } /** + * Rotate a point \a p by \a angle around origin (0, 0) + */ +void rotate_v2_v2fl(float r[2], const float p[2], const float angle) +{ + const float co = cosf(angle); + const float si = sinf(angle); + + BLI_assert(r != p); + + r[0] = co * p[0] - si * p[1]; + r[1] = si * p[0] + co * p[1]; +} + +/** * Rotate a point \a p by \a angle around an arbitrary unit length \a axis. * http://local.wasp.uwa.edu.au/~pbourke/geometry/ */ diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c index 3b6ab99ae86..ef1df479f13 100644 --- a/source/blender/blenlib/intern/scanfill_utils.c +++ b/source/blender/blenlib/intern/scanfill_utils.c @@ -95,20 +95,6 @@ void BLI_scanfill_obj_dump(ScanFillContext *sf_ctx) } #endif -#if 0 -void BLI_scanfill_view3d_dump(ScanFillContext *sf_ctx) -{ - ScanFillEdge *eed; - - bl_debug_draw_quad_clear(); - bl_debug_color_set(0x0000ff); - - for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { - bl_debug_draw_edge_add(eed->v1->co, eed->v2->co); - } -} -#endif - static ListBase *edge_isect_ls_ensure(GHash *isect_hash, ScanFillEdge *eed) { ListBase *e_ls; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a63b9ed7d19..0e1861abcf1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6910,6 +6910,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) rv3d->sms = NULL; rv3d->smooth_timer = NULL; rv3d->compositor = NULL; + rv3d->viewport = NULL; } } } @@ -6926,6 +6927,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) ar->type = NULL; ar->swap = 0; ar->do_draw = 0; + ar->manipulator_map = NULL; ar->regiontimer = NULL; memset(&ar->drawrct, 0, sizeof(ar->drawrct)); } @@ -6972,6 +6974,8 @@ static bool direct_link_screen(FileData *fd, bScreen *sc) sc->mainwin = sc->subwinactive= 0; /* indices */ sc->swap = 0; + sc->preview = direct_link_preview_image(fd, sc->preview); + /* edges */ for (se = sc->edgebase.first; se; se = se->next) { se->v1 = newdataadr(fd, se->v1); @@ -9358,7 +9362,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) expand_doit(fd, mainvar, ob->proxy); if (ob->proxy_group) expand_doit(fd, mainvar, ob->proxy_group); - + for (psys = ob->particlesystem.first; psys; psys = psys->next) expand_doit(fd, mainvar, psys->part); diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 88c583b827e..ea654ad6906 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1492,4 +1492,27 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + { + if (!DNA_struct_elem_find(fd->filesdna, "View3DDebug", "char", "background")) { + bScreen *screen; + + for (screen = main->screen.first; screen; screen = screen->id.next) { + ScrArea *sa; + for (sa = screen->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + + for (sl = sa->spacedata.first; sl; sl = sl->next) { + switch (sl->spacetype) { + case SPACE_VIEW3D: + { + View3D *v3d = (View3D *)sl; + v3d->debug.background = V3D_DEBUG_BACKGROUND_NONE; + } + } + } + } + } + } + } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ad1999c0bc7..27db83055bb 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1721,6 +1721,8 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) SmokeModifierData *smd = (SmokeModifierData *)md; if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { + writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); + if (smd->domain) { write_pointcaches(wd, &(smd->domain->ptcaches[0])); @@ -1734,11 +1736,8 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) if (smd->domain->coba) { writestruct(wd, DATA, ColorBand, 1, smd->domain->coba); } - } - writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); - if (smd->domain) { /* cleanup the fake pointcache */ BKE_ptcache_free_list(&smd->domain->ptcaches[1]); smd->domain->point_cache[1] = NULL; @@ -3007,6 +3006,8 @@ static void write_screens(WriteData *wd, ListBase *scrbase) writestruct(wd, ID_SCRN, bScreen, 1, sc); write_iddata(wd, &sc->id); + write_previews(wd, sc->preview); + /* direct data */ for (sv = sc->vertbase.first; sv; sv = sv->next) { writestruct(wd, DATA, ScrVert, 1, sv); diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 58234ddf3bd..2b38af80fc9 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -81,12 +81,6 @@ /* use accelerated overlap check */ #define USE_BVH -// #define USE_BOOLEAN_RAYCAST_DRAW - -#ifdef USE_BOOLEAN_RAYCAST_DRAW -/* insert bl_debug_draw_quad_clear... here */ -#endif - // #define USE_DUMP static void tri_v3_scale( @@ -1006,10 +1000,6 @@ bool BM_mesh_intersect( int i_a, i_b; #endif -#ifdef USE_BOOLEAN_RAYCAST_DRAW - bl_debug_draw_quad_clear(); -#endif - s.bm = bm; s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__); @@ -1607,17 +1597,6 @@ bool BM_mesh_intersect( do_flip = (side == 0); break; } - -#ifdef USE_BOOLEAN_RAYCAST_DRAW - { - unsigned int colors[4] = {0x00000000, 0xffffffff, 0xff000000, 0x0000ff}; - float co_other[3] = {UNPACK3(co)}; - co_other[0] += 1000.0f; - bl_debug_color_set(colors[(hits & 1) == 1]); - bl_debug_draw_edge_add(co, co_other); - } -#endif - } if (do_remove) { diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index e8ed03666a6..a9df68beb36 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -74,7 +74,9 @@ extern "C" { * design of those areas is more clear we'll do the same legacy code here. * - sergey - */ +#if 0 #define DEPSGRAPH_USE_LEGACY_TAGGING +#endif namespace { diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt new file mode 100644 index 00000000000..60449ebc600 --- /dev/null +++ b/source/blender/draw/CMakeLists.txt @@ -0,0 +1,62 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2016, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Blender Institute +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + intern + nodes + operations + ../blenkernel + ../blenlib + ../blentranslation + ../imbuf + ../makesdna + ../makesrna + ../windowmanager + ../nodes + ../nodes/composite + ../nodes/intern + ../render/extern/include + ../render/intern/include + ../../../extern/clew/include + ../../../intern/guardedalloc + ../../../intern/atomic +) + +set(INC_SYS + +) + +set(SRC + DRW_defines.h + +) + +list(APPEND INC +) + +endif() + +blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/draw/DRW_defines.h b/source/blender/draw/DRW_defines.h new file mode 100644 index 00000000000..212c39e203b --- /dev/null +++ b/source/blender/draw/DRW_defines.h @@ -0,0 +1,25 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +#ifndef __DRW_DEFINES_H__ +#define __DRW_DEFINES_H__ + +#endif /* __DRW_DEFINES_H__ */ diff --git a/source/blender/draw/DRW_engines.h b/source/blender/draw/DRW_engines.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/source/blender/draw/DRW_engines.h diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 57302c18a88..f05932db1b2 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -119,11 +119,10 @@ static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, floa /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } @@ -421,14 +420,13 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); /* rounded corners on LHS only * - top and bottom * - special hack: make the top a bit higher, since we are first... */ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT); - UI_draw_roundbox_gl_mode(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } /* name for summary entries */ @@ -814,11 +812,10 @@ static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } /* name for group entries */ @@ -1071,11 +1068,10 @@ static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, floa /* set backdrop drawing color */ acf->get_backdrop_color(ac, ale, color); - glColor3fv(color); - /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ + /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5, color, 1.0f); } /* name for nla controls expander entries */ @@ -2002,83 +1998,6 @@ static bAnimChannelType ACF_DSWOR = acf_dswor_setting_ptr /* pointer for setting */ }; -/* Particle Expander ------------------------------------------- */ - -// TODO: just get this from RNA? -static int acf_dspart_icon(bAnimListElem *UNUSED(ale)) -{ - return ICON_PARTICLE_DATA; -} - -/* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) -{ - /* clear extra return data first */ - *neg = false; - - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return PART_DS_EXPAND; - - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; - - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; - - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; - - default: /* unsupported */ - return 0; - } -} - -/* get pointer to the setting */ -static void *acf_dspart_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) -{ - ParticleSettings *part = (ParticleSettings *)ale->data; - - /* clear extra return data first */ - *type = 0; - - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(part->flag, type); - - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (part->adt) - return GET_ACF_FLAG_PTR(part->adt->flag, type); - return NULL; - - default: /* unsupported */ - return NULL; - } -} - -/* particle expander type define */ -static bAnimChannelType ACF_DSPART = -{ - "Particle Data Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_generic_dataexpand_color, /* backdrop color */ - acf_generic_dataexpand_backdrop, /* backdrop */ - acf_generic_indention_1, /* indent level */ - acf_generic_basic_offset, /* offset */ - - acf_generic_idblock_name, /* name */ - acf_generic_idblock_name_prop, /* name prop */ - acf_dspart_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dspart_setting_flag, /* flag for setting */ - acf_dspart_setting_ptr /* pointer for setting */ -}; - /* MetaBall Expander ------------------------------------------- */ // TODO: just get this from RNA? @@ -3420,24 +3339,20 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y */ nla_action_get_color(adt, (bAction *)ale->data, color); - if (adt && (adt->flag & ADT_NLA_EDIT_ON)) { - /* Yes, the color vector has 4 components, BUT we only want to be using 3 of them! */ - glColor3fv(color); - } - else { - float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f; - glColor4f(color[0], color[1], color[2], alpha); - } - - /* only on top left corner, to show that this channel sits on top of the preceding ones + if (adt && (adt->flag & ADT_NLA_EDIT_ON)) + color[3] = 1.0f; + else + color[3] = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f; + + /* only on top left corner, to show that this channel sits on top of the preceding ones * while still linking into the action line strip to the right */ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT); - + /* draw slightly shifted up vertically to look like it has more separation from other channels, * but we then need to slightly shorten it so that it doesn't look like it overlaps */ - UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8); + UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8, color); } /* name for nla action entries */ @@ -3580,7 +3495,6 @@ static void ANIM_init_channel_typeinfo_data(void) animchannelTypeInfo[type++] = &ACF_DSSKEY; /* ShapeKey Channel */ animchannelTypeInfo[type++] = &ACF_DSWOR; /* World Channel */ animchannelTypeInfo[type++] = &ACF_DSNTREE; /* NodeTree Channel */ - animchannelTypeInfo[type++] = &ACF_DSPART; /* Particle Channel */ animchannelTypeInfo[type++] = &ACF_DSMBALL; /* MetaBall Channel */ animchannelTypeInfo[type++] = &ACF_DSARM; /* Armature Channel */ animchannelTypeInfo[type++] = &ACF_DSMESH; /* Mesh Channel */ diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 33e44d73894..58b9b8eba91 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -62,6 +62,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "GPU_immediate.h" + /* *************************************************** */ /* CURRENT FRAME DRAWING */ @@ -95,9 +97,16 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const x = cfra * xscale; y = 0.9f * U.widget_unit; + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* draw green box around/behind text */ - UI_ThemeColorShade(TH_CFRAME, 0); - glRectf(x, y, x + slen, y + 0.75f * U.widget_unit); + immUniformThemeColorShade(TH_CFRAME, 0); + + immRectf(pos, x, y, x + slen, y + 0.75f * U.widget_unit); + immUnbindProgram(); /* draw current frame number - black text */ UI_ThemeColor(TH_TEXT); @@ -112,17 +121,23 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag) { Scene *scene = CTX_data_scene(C); - /* Draw a light green line to indicate current frame */ - UI_ThemeColor(TH_CFRAME); - const float x = (float)(scene->r.cfra * scene->r.framelen); glLineWidth((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0); - glBegin(GL_LINES); - glVertex2f(x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */ - glVertex2f(x, v2d->cur.ymax); - glEnd(); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* Draw a light green line to indicate current frame */ + immUniformThemeColor(TH_CFRAME); + + immBegin(GL_LINES, 2); + immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */ + immVertex2f(pos, x, v2d->cur.ymax); + immEnd(); + immUnbindProgram(); /* Draw current frame number in a little box */ if (flag & DRAWCFRA_SHOW_NUMBOX) { @@ -144,17 +159,24 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width) if (PRVRANGEON) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); + /* only draw two separate 'curtains' if there's no overlap between them */ if (PSFRA < PEFRA + end_frame_width) { - glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); - glRectf((float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); + immRectf(pos, (float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } else { - glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } - + + immUnbindProgram(); + glDisable(GL_BLEND); } } diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 9da3c3ee088..d09d441d71b 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -60,9 +60,11 @@ #include "WM_api.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_draw.h" + #include "ED_gpencil.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -94,97 +96,194 @@ typedef enum eDrawStrokeFlags { /* thickness above which we should use special drawing */ #define GP_DRAWTHICKNESS_SPECIAL 3 +/* conversion utility (float --> normalized unsigned byte) */ +#define F2UB(x) (unsigned char)(255.0f * x) + /* ----- Tool Buffer Drawing ------ */ -/* helper function to set color of buffer point */ -static void gp_set_tpoint_color(tGPspoint *pt, float ink[4]) +/* helper functions to set color of buffer point */ + +static void gp_set_tpoint_varying_color(const tGPspoint *pt, const float ink[4], unsigned attrib_id) { float alpha = ink[3] * pt->strength; CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); - glColor4f(ink[0], ink[1], ink[2], alpha); + immAttrib4ub(attrib_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha)); } -/* helper function to set color of point */ -static void gp_set_point_color(bGPDspoint *pt, float ink[4]) +static void gp_set_point_uniform_color(const bGPDspoint *pt, const float ink[4]) { float alpha = ink[3] * pt->strength; CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); - glColor4f(ink[0], ink[1], ink[2], alpha); + immUniform4f("color", ink[0], ink[1], ink[2], alpha); } -/* helper function to set color and point */ -static void gp_set_color_and_tpoint(tGPspoint *pt, float ink[4]) +static void gp_set_point_varying_color(const bGPDspoint *pt, const float ink[4], unsigned attrib_id) { - gp_set_tpoint_color(pt, ink); - glVertex2iv(&pt->x); + float alpha = ink[3] * pt->strength; + CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); + immAttrib4ub(attrib_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha)); +} + +/* draw fills for buffer stroke */ +static void gp_draw_stroke_buffer_fill(const tGPspoint *points, int totpoints, float ink[4]) +{ + if (totpoints < 3) { + return; + } + int tot_triangles = totpoints - 2; + /* allocate memory for temporary areas */ + unsigned int(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, "GP Stroke buffer temp triangulation"); + float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, "GP Stroke buffer temp 2d points"); + + /* Convert points to array and triangulate + * Here a cache is not used because while drawing the information changes all the time, so the cache + * would be recalculated constantly, so it is better to do direct calculation for each function call + */ + for (int i = 0; i < totpoints; i++) { + const tGPspoint *pt = &points[i]; + points2d[i][0] = pt->x; + points2d[i][1] = pt->y; + } + BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)totpoints, 0, (unsigned int(*)[3])tmp_triangles); + + /* draw triangulation data */ + if (tot_triangles > 0) { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + /* Draw all triangles for filling the polygon */ + immBegin(GL_TRIANGLES, tot_triangles * 3); + /* TODO: use batch instead of immediate mode, to share vertices */ + + const tGPspoint *pt; + for (int i = 0; i < tot_triangles; i++) { + /* vertex 1 */ + pt = &points[tmp_triangles[i][0]]; + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); + /* vertex 2 */ + pt = &points[tmp_triangles[i][1]]; + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); + /* vertex 3 */ + pt = &points[tmp_triangles[i][2]]; + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); + } + + immEnd(); + immUnbindProgram(); + } + + /* clear memory */ + if (tmp_triangles) { + MEM_freeN(tmp_triangles); + } + if (points2d) { + MEM_freeN(points2d); + } } /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ -static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickness, - short dflag, short sflag, float ink[4]) +static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short thickness, + short dflag, short sflag, float ink[4], float fill_ink[4]) { - tGPspoint *pt; - int i; - + int draw_points = 0; + /* error checking */ if ((points == NULL) || (totpoints <= 0)) return; - + /* check if buffer can be drawn */ if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D)) return; - + + if (sflag & GP_STROKE_ERASER) { + /* don't draw stroke at all! */ + return; + } + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + const tGPspoint *pt = points; + if (totpoints == 1) { /* if drawing a single point, draw it larger */ glPointSize((float)(thickness + 2) * points->pressure); - glBegin(GL_POINTS); - - gp_set_color_and_tpoint(points, ink); - glEnd(); - } - else if (sflag & GP_STROKE_ERASER) { - /* don't draw stroke at all! */ + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR); + immBegin(GL_POINTS, 1); + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); } else { float oldpressure = points[0].pressure; - + /* draw stroke curve */ if (G.debug & G_DEBUG) setlinestyle(2); - + glLineWidth(max_ff(oldpressure * thickness, 1.0)); - glBegin(GL_LINE_STRIP); - - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + immBeginAtMost(GL_LINE_STRIP, totpoints); + + /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */ + + for (int i = 0; i < totpoints; i++, pt++) { /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) */ if (fabsf(pt->pressure - oldpressure) > 0.2f) { - glEnd(); + /* need to have 2 points to avoid immEnd assert error */ + if (draw_points < 2) { + gp_set_tpoint_varying_color(pt - 1, ink, color); + immVertex2iv(pos, &(pt - 1)->x); + } + + immEnd(); + draw_points = 0; + glLineWidth(max_ff(pt->pressure * thickness, 1.0f)); - glBegin(GL_LINE_STRIP); - + immBeginAtMost(GL_LINE_STRIP, totpoints - i + 1); + /* need to roll-back one point to ensure that there are no gaps in the stroke */ if (i != 0) { - gp_set_color_and_tpoint((pt - 1), ink); + gp_set_tpoint_varying_color(pt - 1, ink, color); + immVertex2iv(pos, &(pt - 1)->x); + ++draw_points; } - - /* now the point we want... */ - gp_set_color_and_tpoint(pt, ink); - - oldpressure = pt->pressure; - } - else { - gp_set_color_and_tpoint(pt, ink); + + oldpressure = pt->pressure; /* reset our threshold */ } + + /* now the point we want */ + gp_set_tpoint_varying_color(pt, ink, color); + immVertex2iv(pos, &pt->x); + ++draw_points; + } + /* need to have 2 points to avoid immEnd assert error */ + if (draw_points < 2) { + gp_set_tpoint_varying_color(pt - 1, ink, color); + immVertex2iv(pos, &(pt - 1)->x); } - glEnd(); if (G.debug & G_DEBUG) setlinestyle(0); } + + immEnd(); + immUnbindProgram(); + + // draw fill + if (fill_ink[3] > GPENCIL_ALPHA_OPACITY_THRESH) { + gp_draw_stroke_buffer_fill(points, totpoints, fill_ink); + } } /* --------- 2D Stroke Drawing Helpers --------- */ /* change in parameter list */ -static void gp_calc_2d_stroke_fxy(float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2]) +static void gp_calc_2d_stroke_fxy(const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2]) { if (sflag & GP_STROKE_2DSPACE) { r_co[0] = pt[0]; @@ -210,203 +309,141 @@ static void gp_calc_2d_stroke_fxy(float pt[3], short sflag, int offsx, int offsy /* draw a 2D buffer stroke in "volumetric" style * NOTE: the stroke buffer doesn't have any coordinate offsets/transforms */ -static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness, - short dflag, short UNUSED(sflag), float ink[4]) +static void gp_draw_stroke_volumetric_buffer(const tGPspoint *points, int totpoints, short thickness, + short dflag, const float ink[4]) { - GLUquadricObj *qobj = gluNewQuadric(); - float modelview[4][4]; - - tGPspoint *pt; - int i; - /* error checking */ if ((points == NULL) || (totpoints <= 0)) return; - + /* check if buffer can be drawn */ if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D)) return; - - /* get basic matrix - should be camera space (i.e "identity") */ - glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview); - - /* draw points */ - glPushMatrix(); - - for (i = 0, pt = points; i < totpoints; i++, pt++) { - /* set the transformed position */ - // TODO: scale should change based on zoom level, which requires proper translation mult too! - modelview[3][0] = pt->x; - modelview[3][1] = pt->y; - - glLoadMatrixf((float *)modelview); - - /* draw the disk using the current state... */ - gp_set_tpoint_color(pt, ink); - gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); - - - modelview[3][0] = modelview[3][1] = 0.0f; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned size = add_attrib(format, "size", GL_FLOAT, 1, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + GPU_enable_program_point_size(); + immBegin(GL_POINTS, totpoints); + + const tGPspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { + gp_set_tpoint_varying_color(pt, ink, color); + immAttrib1f(size, pt->pressure * thickness); /* TODO: scale based on view transform (zoom level) */ + immVertex2f(pos, pt->x, pt->y); } - glPopMatrix(); - gluDeleteQuadric(qobj); + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); } /* draw a 2D strokes in "volumetric" style */ -static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness, - short dflag, short sflag, +static void gp_draw_stroke_volumetric_2d(const bGPDspoint *points, int totpoints, short thickness, + short UNUSED(dflag), short sflag, int offsx, int offsy, int winx, int winy, - float diff_mat[4][4], float ink[4]) + const float diff_mat[4][4], const float ink[4]) { - GLUquadricObj *qobj = gluNewQuadric(); - float modelview[4][4]; - float baseloc[3]; - float scalefac = 1.0f; - - bGPDspoint *pt; - int i; - float fpt[3]; - - /* HACK: We need a scale factor for the drawing in the image editor, - * which seems to use 1 unit as it's maximum size, whereas everything - * else assumes 1 unit = 1 pixel. Otherwise, we only get a massive blob. - */ - if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) { - scalefac = 0.001f; - } - - /* get basic matrix */ - glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview); - copy_v3_v3(baseloc, modelview[3]); - - /* draw points */ - glPushMatrix(); - - for (i = 0, pt = points; i < totpoints; i++, pt++) { - /* color of point */ - gp_set_point_color(pt, ink); - - /* set the transformed position */ + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned size = add_attrib(format, "size", GL_FLOAT, 1, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + GPU_enable_program_point_size(); + immBegin(GL_POINTS, totpoints); + + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { + /* transform position to 2D */ float co[2]; - + float fpt[3]; + mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co); - translate_m4(modelview, co[0], co[1], 0.0f); - - glLoadMatrixf((float *)modelview); - - /* draw the disk using the current state... */ - gluDisk(qobj, 0.0, pt->pressure * thickness * scalefac, 32, 1); - - /* restore matrix */ - copy_v3_v3(modelview[3], baseloc); + + gp_set_point_varying_color(pt, ink, color); + immAttrib1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */ + immVertex2f(pos, co[0], co[1]); } - - glPopMatrix(); - gluDeleteQuadric(qobj); + + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); } /* draw a 3D stroke in "volumetric" style */ static void gp_draw_stroke_volumetric_3d( - bGPDspoint *points, int totpoints, short thickness, - short UNUSED(dflag), short UNUSED(sflag), float diff_mat[4][4], float ink[4]) + const bGPDspoint *points, int totpoints, short thickness, + const float ink[4]) { - GLUquadricObj *qobj = gluNewQuadric(); - - float base_modelview[4][4], modelview[4][4]; - float base_loc[3]; - - bGPDspoint *pt; - int i; - float fpt[3]; - - /* Get the basic modelview matrix we use for performing calculations */ - glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview); - copy_v3_v3(base_loc, base_modelview[3]); - - /* Create the basic view-aligned billboard matrix we're going to actually draw qobj with: - * - We need to knock out the rotation so that we are - * simply left with a camera-facing billboard - * - The scale factors here are chosen so that the thickness - * is relatively reasonable. Otherwise, it gets far too - * large! - */ - scale_m4_fl(modelview, 0.1f); - - /* draw each point as a disk... */ - glPushMatrix(); - - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { - /* color of point */ - gp_set_point_color(pt, ink); - - mul_v3_m4v3(fpt, diff_mat, &pt->x); - - /* apply translation to base_modelview, so that the translated point is put in the right place */ - translate_m4(base_modelview, fpt[0], fpt[1], fpt[2]); - - /* copy the translation component to the billboard matrix we're going to use, - * then reset the base matrix to the original values so that we can do the same - * for the next point without accumulation/pollution effects - */ - copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */ - copy_v3_v3(base_modelview[3], base_loc); /* restore */ - - /* apply our billboard matrix for drawing... */ - glLoadMatrixf((float *)modelview); - - /* draw the disk using the current state... */ - gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned size = add_attrib(format, "size", GL_FLOAT, 1, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + GPU_enable_program_point_size(); + immBegin(GL_POINTS, totpoints); + + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints && pt; i++, pt++) { + gp_set_point_varying_color(pt, ink, color); + immAttrib1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */ + immVertex3fv(pos, &pt->x); /* we can adjust size in vertex shader based on view/projection! */ } - - glPopMatrix(); - gluDeleteQuadric(qobj); + + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); } /* --------------- Stroke Fills ----------------- */ /* Get points of stroke always flat to view not affected by camera view or view position */ -static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction) +static void gp_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction) { - bGPDspoint *pt0 = &points[0]; - bGPDspoint *pt1 = &points[1]; - bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; - + const bGPDspoint *pt0 = &points[0]; + const bGPDspoint *pt1 = &points[1]; + const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; + float locx[3]; float locy[3]; float loc3[3]; float normal[3]; - + /* local X axis (p0 -> p1) */ sub_v3_v3v3(locx, &pt1->x, &pt0->x); - + /* point vector at 3/4 */ sub_v3_v3v3(loc3, &pt3->x, &pt0->x); - + /* vector orthogonal to polygon plane */ cross_v3_v3v3(normal, locx, loc3); - + /* local Y axis (cross to normal/x axis) */ cross_v3_v3v3(locy, normal, locx); - + /* Normalize vectors */ normalize_v3(locx); normalize_v3(locy); - + /* Get all points in local space */ for (int i = 0; i < totpoints; i++) { - bGPDspoint *pt = &points[i]; + const bGPDspoint *pt = &points[i]; float loc[3]; - + /* Get local space using first point as origin */ sub_v3_v3v3(loc, &pt->x, &pt0->x); - + points2d[i][0] = dot_v3v3(loc, locx); points2d[i][1] = dot_v3v3(loc, locy); } - + /* Concave (-1), Convex (1), or Autodetect (0)? */ *r_direction = (int)locy[2]; } @@ -416,14 +453,14 @@ static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d static void gp_triangulate_stroke_fill(bGPDstroke *gps) { BLI_assert(gps->totpoints >= 3); - + /* allocate memory for temporary areas */ gps->tot_triangles = gps->totpoints - 2; unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation"); float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points"); - + int direction = 0; - + /* convert to 2d and triangulate */ gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles); @@ -438,7 +475,7 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) else { gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles); } - + for (int i = 0; i < gps->tot_triangles; i++) { bGPDtriangle *stroke_triangle = &gps->triangles[i]; stroke_triangle->v1 = tmp_triangles[i][0]; @@ -450,15 +487,15 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) /* No triangles needed - Free anything allocated previously */ if (gps->triangles) MEM_freeN(gps->triangles); - + gps->triangles = NULL; } - + /* disable recalculation flag */ if (gps->flag & GP_STROKE_RECALC_CACHES) { gps->flag &= ~GP_STROKE_RECALC_CACHES; } - + /* clear memory */ if (tmp_triangles) MEM_freeN(tmp_triangles); if (points2d) MEM_freeN(points2d); @@ -468,42 +505,55 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) /* draw fills for shapes */ static void gp_draw_stroke_fill( bGPdata *gpd, bGPDstroke *gps, - int offsx, int offsy, int winx, int winy, float diff_mat[4][4]) + int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4]) { - bGPDpalettecolor *palcolor; - int i; float fpt[3]; BLI_assert(gps->totpoints >= 3); - palcolor = ED_gpencil_stroke_getcolor(gpd, gps); + bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); /* Triangulation fill if high quality flag is enabled */ if (palcolor->flag & PC_COLOR_HQ_FILL) { - bGPDtriangle *stroke_triangle; - bGPDspoint *pt; - /* Calculate triangles cache for filling area (must be done only after changes) */ if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { gp_triangulate_stroke_fill(gps); } - /* Draw all triangles for filling the polygon (cache must be calculated before) */ BLI_assert(gps->tot_triangles >= 1); - glBegin(GL_TRIANGLES); - for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) { + + unsigned pos; + if (gps->flag & GP_STROKE_3DSPACE) { + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + } + else { + pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + } + + immUniformColor4fv(color); + + /* Draw all triangles for filling the polygon (cache must be calculated before) */ + immBegin(GL_TRIANGLES, gps->tot_triangles * 3); + /* TODO: use batch instead of immediate mode, to share vertices */ + + bGPDtriangle *stroke_triangle = gps->triangles; + bGPDspoint *pt; + + for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { if (gps->flag & GP_STROKE_3DSPACE) { /* vertex 1 */ pt = &gps->points[stroke_triangle->v1]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); + immVertex3fv(pos, fpt); /* vertex 2 */ pt = &gps->points[stroke_triangle->v2]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); + immVertex3fv(pos, fpt); /* vertex 3 */ pt = &gps->points[stroke_triangle->v3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); + immVertex3fv(pos, fpt); } else { float co[2]; @@ -511,21 +561,25 @@ static void gp_draw_stroke_fill( pt = &gps->points[stroke_triangle->v1]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + immVertex2fv(pos, co); /* vertex 2 */ pt = &gps->points[stroke_triangle->v2]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + immVertex2fv(pos, co); /* vertex 3 */ pt = &gps->points[stroke_triangle->v3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + immVertex2fv(pos, co); } } - glEnd(); + + immEnd(); + immUnbindProgram(); } + +#if 0 /* convert to modern GL only if needed */ else { /* As an initial implementation, we use the OpenGL filled polygon drawing * here since it's the easiest option to implement for this case. It does @@ -537,10 +591,10 @@ static void gp_draw_stroke_fill( * created using old versions of Blender which may have depended on the artifacts * the old fills created. */ - bGPDspoint *pt; + bGPDspoint *pt = gps->points; glBegin(GL_POLYGON); - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + for (int i = 0; i < gps->totpoints; i++, pt++) { if (gps->flag & GP_STROKE_3DSPACE) { mul_v3_m4v3(fpt, diff_mat, &pt->x); glVertex3fv(fpt); @@ -555,159 +609,186 @@ static void gp_draw_stroke_fill( glEnd(); } +#endif } /* ----- Existing Strokes Drawing (3D and Point) ------ */ /* draw a given stroke - just a single dot (only one point) */ static void gp_draw_stroke_point( - bGPDspoint *points, short thickness, short dflag, short sflag, - int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4]) + const bGPDspoint *points, short thickness, short UNUSED(dflag), short sflag, + int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4]) { - float fpt[3]; - bGPDspoint *pt = &points[0]; - - /* color of point */ - gp_set_point_color(pt, ink); + const bGPDspoint *pt = points; - /* set point thickness (since there's only one of these) */ - glPointSize((float)(thickness + 2) * points->pressure); - /* get final position using parent matrix */ + float fpt[3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - /* draw point */ + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + if (sflag & GP_STROKE_3DSPACE) { - glBegin(GL_POINTS); - glVertex3fv(fpt); - glEnd(); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); } else { - float co[2]; - - /* get coordinates of point */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + + /* get 2D coordinates of point */ + float co[3] = { 0.0f }; gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co); - - /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok - * - also mandatory in if Image Editor 'image-based' dot - */ - if ((thickness < GP_DRAWTHICKNESS_SPECIAL) || - ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE))) - { - glBegin(GL_POINTS); - glVertex2fv(co); - glEnd(); - } - else { - /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */ - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_FILL); - - /* need to translate drawing position, but must reset after too! */ - glTranslate2fv(co); - gluDisk(qobj, 0.0, thickness, 32, 1); - glTranslatef(-co[0], -co[1], 0.0); - - gluDeleteQuadric(qobj); - } + copy_v3_v3(fpt, co); } + + gp_set_point_uniform_color(pt, ink); + /* set point thickness (since there's only one of these) */ + immUniform1f("size", (float)(thickness + 2) * pt->pressure); + + immBegin(GL_POINTS, 1); + immVertex3fv(pos, fpt); + immEnd(); + + immUnbindProgram(); } /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */ -static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, - short UNUSED(sflag), float diff_mat[4][4], float ink[4], bool cyclic) +static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thickness, bool UNUSED(debug), + short UNUSED(sflag), const float diff_mat[4][4], const float ink[4], bool cyclic) { - bGPDspoint *pt, *pt2; float curpressure = points[0].pressure; - int i; float fpt[3]; float cyclic_fpt[3]; + int draw_points = 0; + + /* if cyclic needs one vertex more */ + int cyclic_add = 0; + if (cyclic) { + ++cyclic_add; + } + + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); + + /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */ /* draw stroke curve */ glLineWidth(max_ff(curpressure * thickness, 1.0f)); - glBegin(GL_LINE_STRIP); - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { - gp_set_point_color(pt, ink); + immBeginAtMost(GL_LINE_STRIP, totpoints + cyclic_add); + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { + gp_set_point_varying_color(pt, ink, color); /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) * Note: we want more visible levels of pressures when thickness is bigger. */ if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) { - glEnd(); + /* if the pressure changes before get at least 2 vertices, need to repeat last point to avoid assert in immEnd() */ + if (draw_points < 2) { + const bGPDspoint *pt2 = pt - 1; + mul_v3_m4v3(fpt, diff_mat, &pt2->x); + immVertex3fv(pos, fpt); + } + immEnd(); + draw_points = 0; + curpressure = pt->pressure; glLineWidth(max_ff(curpressure * thickness, 1.0f)); - glBegin(GL_LINE_STRIP); - + immBeginAtMost(GL_LINE_STRIP, totpoints - i + 1 + cyclic_add); + /* need to roll-back one point to ensure that there are no gaps in the stroke */ if (i != 0) { - pt2 = pt - 1; + const bGPDspoint *pt2 = pt - 1; mul_v3_m4v3(fpt, diff_mat, &pt2->x); - glVertex3fv(fpt); + gp_set_point_varying_color(pt2, ink, color); + immVertex3fv(pos, fpt); + ++draw_points; } - - /* now the point we want... */ - mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); } - else { - mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); - } - /* saves first point to use in cyclic */ - if (i == 0) { + + /* now the point we want */ + mul_v3_m4v3(fpt, diff_mat, &pt->x); + immVertex3fv(pos, fpt); + ++draw_points; + + if (cyclic && i == 0) { + /* save first point to use in cyclic */ copy_v3_v3(cyclic_fpt, fpt); } } - /* if cyclic draw line to first point */ + if (cyclic) { - glVertex3fv(cyclic_fpt); + /* draw line to first point to complete the cycle */ + immVertex3fv(pos, cyclic_fpt); + ++draw_points; } - glEnd(); + /* if less of two points, need to repeat last point to avoid assert in immEnd() */ + if (draw_points < 2) { + const bGPDspoint *pt2 = pt - 1; + mul_v3_m4v3(fpt, diff_mat, &pt2->x); + gp_set_point_varying_color(pt2, ink, color); + immVertex3fv(pos, fpt); + } + + immEnd(); + immUnbindProgram(); + +#if 0 /* convert to modern GL only if needed */ /* draw debug points of curve on top? */ /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */ if (debug) { glPointSize((float)(thickness + 2)); - + glBegin(GL_POINTS); - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { mul_v3_m4v3(fpt, diff_mat, &pt->x); glVertex3fv(fpt); } glEnd(); - } +#endif } /* ----- Fancy 2D-Stroke Drawing ------ */ /* draw a given stroke in 2d */ -static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, - bool debug, int offsx, int offsy, int winx, int winy, float diff_mat[4][4], float ink[4]) +static void gp_draw_stroke_2d(const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, + bool debug, int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4]) { /* otherwise thickness is twice that of the 3D view */ float thickness = (float)thickness_s * 0.5f; - + /* strokes in Image Editor need a scale factor, since units there are not pixels! */ float scalefac = 1.0f; if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) { scalefac = 0.001f; } - + + /* TODO: fancy++ with the magic of shaders */ + /* tessellation code - draw stroke as series of connected quads with connection * edges rotated to minimize shrinking artifacts, and rounded endcaps */ { - bGPDspoint *pt1, *pt2; + const bGPDspoint *pt1, *pt2; float pm[2]; int i; float fpt[3]; - - glShadeModel(GL_FLAT); - glBegin(GL_QUADS); - + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + /* this code previously used glShadeModel(GL_FLAT) */ + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_QUADS, (totpoints - 2) * 4 + 12); + for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) { float s0[2], s1[2]; /* segment 'center' points */ float t0[2], t1[2]; /* tessellated coordinates */ @@ -721,19 +802,19 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness mul_v3_m4v3(fpt, diff_mat, &pt2->x); gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1); - + /* calculate gradient and normal - 'angle'=(ny/nx) */ m1[1] = s1[1] - s0[1]; m1[0] = s1[0] - s0[0]; normalize_v2(m1); m2[1] = -m1[0]; m2[0] = m1[1]; - + /* always use pressure from first point here */ pthick = (pt1->pressure * thickness * scalefac); - + /* color of point */ - gp_set_point_color(pt1, ink); + gp_set_point_varying_color(pt1, ink, color); /* if the first segment, start of segment is segment's normal */ if (i == 0) { @@ -744,40 +825,40 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness mt[1] = m2[1] * pthick * 0.5f; sc[0] = s0[0] - (m1[0] * pthick * 0.75f); sc[1] = s0[1] - (m1[1] * pthick * 0.75f); - + t0[0] = sc[0] - mt[0]; t0[1] = sc[1] - mt[1]; t1[0] = sc[0] + mt[0]; t1[1] = sc[1] + mt[1]; - - glVertex2fv(t0); - glVertex2fv(t1); - + + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + /* calculate points for start of segment */ mt[0] = m2[0] * pthick; mt[1] = m2[1] * pthick; - + t0[0] = s0[0] - mt[0]; t0[1] = s0[1] - mt[1]; t1[0] = s0[0] + mt[0]; t1[1] = s0[1] + mt[1]; - + /* draw this line twice (first to finish off start cap, then for stroke) */ - glVertex2fv(t1); - glVertex2fv(t0); - glVertex2fv(t0); - glVertex2fv(t1); + immVertex2fv(pos, t1); + immVertex2fv(pos, t0); + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); } /* if not the first segment, use bisector of angle between segments */ else { float mb[2]; /* bisector normal */ float athick, dfac; /* actual thickness, difference between thicknesses */ - + /* calculate gradient of bisector (as average of normals) */ mb[0] = (pm[0] + m2[0]) / 2; mb[1] = (pm[1] + m2[1]) / 2; normalize_v2(mb); - + /* calculate gradient to apply * - as basis, use just pthick * bisector gradient * - if cross-section not as thick as it should be, add extra padding to fix it @@ -786,49 +867,48 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness mt[1] = mb[1] * pthick; athick = len_v2(mt); dfac = pthick - (athick * 2); - + if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) { mt[0] += (mb[0] * dfac); mt[1] += (mb[1] * dfac); } - + /* calculate points for start of segment */ t0[0] = s0[0] - mt[0]; t0[1] = s0[1] - mt[1]; t1[0] = s0[0] + mt[0]; t1[1] = s0[1] + mt[1]; - + /* draw this line twice (once for end of current segment, and once for start of next) */ - glVertex2fv(t1); - glVertex2fv(t0); - glVertex2fv(t0); - glVertex2fv(t1); + immVertex2fv(pos, t1); + immVertex2fv(pos, t0); + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); } - + /* if last segment, also draw end of segment (defined as segment's normal) */ if (i == totpoints - 2) { /* for once, we use second point's pressure (otherwise it won't be drawn) */ pthick = (pt2->pressure * thickness * scalefac); - + /* color of point */ - gp_set_point_color(pt2, ink); + gp_set_point_varying_color(pt2, ink, color); /* calculate points for end of segment */ mt[0] = m2[0] * pthick; mt[1] = m2[1] * pthick; - + t0[0] = s1[0] - mt[0]; t0[1] = s1[1] - mt[1]; t1[0] = s1[0] + mt[0]; t1[1] = s1[1] + mt[1]; - + /* draw this line twice (once for end of stroke, and once for endcap)*/ - glVertex2fv(t1); - glVertex2fv(t0); - glVertex2fv(t0); - glVertex2fv(t1); - - + immVertex2fv(pos, t1); + immVertex2fv(pos, t0); + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + /* draw end cap as last step * - make points slightly closer to center (about halfway across) */ @@ -836,34 +916,33 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness mt[1] = m2[1] * pthick * 0.5f; sc[0] = s1[0] + (m1[0] * pthick * 0.75f); sc[1] = s1[1] + (m1[1] * pthick * 0.75f); - + t0[0] = sc[0] - mt[0]; t0[1] = sc[1] - mt[1]; t1[0] = sc[0] + mt[0]; t1[1] = sc[1] + mt[1]; - - glVertex2fv(t1); - glVertex2fv(t0); + + immVertex2fv(pos, t1); + immVertex2fv(pos, t0); } - + /* store stroke's 'natural' normal for next stroke to use */ copy_v2_v2(pm, m2); } - - glEnd(); - glShadeModel(GL_SMOOTH); + + immEnd(); + immUnbindProgram(); } - + +#if 0 /* convert to modern GL only if needed */ /* draw debug points of curve on top? (original stroke points) */ if (debug) { - bGPDspoint *pt; - int i; - float fpt[3]; - glPointSize((float)(thickness_s + 2)); - + glBegin(GL_POINTS); - for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints && pt; i++, pt++) { + float fpt[3]; float co[2]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co); @@ -871,6 +950,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness } glEnd(); } +#else + UNUSED_VARS(debug); +#endif } /* ----- Strokes Drawing ------ */ @@ -884,41 +966,41 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag) return false; if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) return false; - + /* 2) Screen Space 2D Strokes */ if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) return false; if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) return false; - + /* 3) Image Space (2D) */ if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) return false; if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) return false; - - + /* skip stroke if it doesn't have any valid data */ if ((gps->points == NULL) || (gps->totpoints < 1)) return false; - + /* stroke can be drawn */ return true; } /* draw a set of strokes */ static void gp_draw_strokes( - bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag, + bGPdata *gpd, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag, bool debug, short lthick, const float opacity, const float tintcolor[4], - const bool onion, const bool custonion, float diff_mat[4][4]) + const bool onion, const bool custonion, const float diff_mat[4][4]) { - bGPDstroke *gps; float tcolor[4]; float tfill[4]; short sthickness; float ink[4]; - for (gps = gpf->strokes.first; gps; gps = gps->next) { + GPU_enable_program_point_size(); + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* check if stroke can be drawn */ if (gp_can_draw_stroke(gps, dflag) == false) { continue; @@ -936,6 +1018,10 @@ static void gp_draw_strokes( /* calculate thickness */ sthickness = gps->thickness + lthick; + if (sthickness <= 0) { + continue; + } + /* check which stroke-drawer to use */ if (dflag & GP_DRAWDATA_ONLY3D) { const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY); @@ -962,19 +1048,20 @@ static void gp_draw_strokes( interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]); tfill[3] = palcolor->fill[3] * opacity; if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) { + const float *color; if (!onion) { - glColor4fv(tfill); + color = tfill; } else { if (custonion) { - glColor4fv(tintcolor); + color = tintcolor; } else { ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]); - glColor4fv(tfill); + color = tfill; } } - gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat); + gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color); } } @@ -996,7 +1083,7 @@ static void gp_draw_strokes( } if (palcolor->flag & PC_COLOR_VOLUMETRIC) { /* volumetric stroke drawing */ - gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink); + gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink); } else { /* 3D Lines - OpenGL primitives-based */ @@ -1027,20 +1114,21 @@ static void gp_draw_strokes( interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]); tfill[3] = palcolor->fill[3] * opacity; if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) { + const float *color; if (!onion) { - glColor4fv(tfill); + color = tfill; } else { if (custonion) { - glColor4fv(tintcolor); + color = tintcolor; } else { ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2], tintcolor[3]); - glColor4fv(tfill); + color = tfill; } } - gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat); + gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color); } } @@ -1078,15 +1166,15 @@ static void gp_draw_strokes( } } } + + GPU_disable_program_point_size(); } /* Draw selected verts for strokes being edited */ static void gp_draw_strokes_edit( - bGPdata *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, - short lflag, float diff_mat[4][4], float alpha) + bGPdata *gpd, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, + short lflag, const float diff_mat[4][4], float alpha) { - bGPDstroke *gps; - /* if alpha 0 do not draw */ if (alpha == 0.0f) return; @@ -1100,36 +1188,32 @@ static void gp_draw_strokes_edit( glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); glDepthMask(0); glEnable(GL_DEPTH_TEST); - + /* first arg is normally rv3d->dist, but this isn't * available here and seems to work quite well without */ bglPolygonOffset(1.0f, 1.0f); #if 0 - glEnable(GL_POLYGON_OFFSET_LINE); + glEnable(GL_POLYGON_OFFSET_LINE); /* do we want LINE or POINT here? (merwin) */ glPolygonOffset(-1.0f, -1.0f); #endif } } - - - /* draw stroke verts */ - for (gps = gpf->strokes.first; gps; gps = gps->next) { - bGPDspoint *pt; - float vsize, bsize; - int i; - float fpt[3]; + GPU_enable_program_point_size(); + + /* draw stroke verts */ + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* check if stroke can be drawn */ if (gp_can_draw_stroke(gps, dflag) == false) continue; - + /* Optimisation: only draw points for selected strokes * We assume that selected points can only occur in * strokes that are selected too. */ if ((gps->flag & GP_STROKE_SELECT) == 0) continue; - + /* verify palette color lock */ { bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); @@ -1148,7 +1232,8 @@ static void gp_draw_strokes_edit( * they stand out more. * - We use the theme setting for size of the unselected verts */ - bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); + float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); + float vsize; if ((int)bsize > 8) { vsize = 10.0f; bsize = 8.0f; @@ -1156,89 +1241,83 @@ static void gp_draw_strokes_edit( else { vsize = bsize + 2; } - - /* First Pass: Draw all the verts (i.e. these become the unselected state) */ + /* for now, we assume that the base color of the points is not too close to the real color */ /* set color using palette */ bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); - glColor3fv(palcolor->color); - glPointSize(bsize); - - glBegin(GL_POINTS); - for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { + float selectColor[4]; + UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); + selectColor[3] = alpha; + + VertexFormat *format = immVertexFormat(); + unsigned pos; /* specified later */ + unsigned size = add_attrib(format, "size", GL_FLOAT, 1, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + if (gps->flag & GP_STROKE_3DSPACE) { + pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + } + else { + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR); + } + + immBegin(GL_POINTS, gps->totpoints); + + /* Draw start and end point differently if enabled stroke direction hint */ + bool show_direction_hint = (gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1); + + /* Draw all the stroke points (selected or not) */ + bGPDspoint *pt = gps->points; + float fpt[3]; + for (int i = 0; i < gps->totpoints; i++, pt++) { + /* size and color first */ + if (show_direction_hint && i == 0) { + /* start point in green bigger */ + immAttrib3f(color, 0.0f, 1.0f, 0.0f); + immAttrib1f(size, vsize + 4); + } + else if (show_direction_hint && (i == gps->totpoints - 1)) { + /* end point in red smaller */ + immAttrib3f(color, 1.0f, 0.0f, 0.0f); + immAttrib1f(size, vsize + 1); + } + else if (pt->flag & GP_SPOINT_SELECT) { + immAttrib3fv(color, selectColor); + immAttrib1f(size, vsize); + } + else { + immAttrib3fv(color, palcolor->color); + immAttrib1f(size, bsize); + } + + /* then position */ if (gps->flag & GP_STROKE_3DSPACE) { mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); + immVertex3fv(pos, fpt); } else { float co[2]; mul_v3_m4v3(fpt, diff_mat, &pt->x); gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); + immVertex2fv(pos, co); } } - glEnd(); - - - /* Second Pass: Draw only verts which are selected */ - float curColor[4]; - UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, curColor); - glColor4f(curColor[0], curColor[1], curColor[2], alpha); - glPointSize(vsize); - - glBegin(GL_POINTS); - for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { - if (pt->flag & GP_SPOINT_SELECT) { - if (gps->flag & GP_STROKE_3DSPACE) { - mul_v3_m4v3(fpt, diff_mat, &pt->x); - glVertex3fv(fpt); - } - else { - float co[2]; - - mul_v3_m4v3(fpt, diff_mat, &pt->x); - gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - glVertex2fv(co); - } - } - } - glEnd(); - - /* Draw start and end point if enabled stroke direction hint */ - if ((gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1)) { - bGPDspoint *p; - - glPointSize(vsize + 4); - glBegin(GL_POINTS); - - /* start point in green bigger */ - glColor3f(0.0f, 1.0f, 0.0f); - p = &gps->points[0]; - mul_v3_m4v3(fpt, diff_mat, &p->x); - glVertex3fv(fpt); - glEnd(); + immEnd(); + immUnbindProgram(); + } - /* end point in red smaller */ - glPointSize(vsize + 1); - glBegin(GL_POINTS); + GPU_disable_program_point_size(); - glColor3f(1.0f, 0.0f, 0.0f); - p = &gps->points[gps->totpoints - 1]; - mul_v3_m4v3(fpt, diff_mat, &p->x); - glVertex3fv(fpt); - glEnd(); - } - } - - /* clear depth mask */ if (dflag & GP_DRAWDATA_ONLY3D) { if (no_xray) { glDepthMask(mask_orig); glDisable(GL_DEPTH_TEST); - + bglPolygonOffset(0.0, 0.0); #if 0 glDisable(GL_POLYGON_OFFSET_LINE); @@ -1252,8 +1331,8 @@ static void gp_draw_strokes_edit( /* draw onion-skinning for a layer */ static void gp_draw_onionskins( - bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, - int UNUSED(cfra), int dflag, bool debug, float diff_mat[4][4]) + bGPdata *gpd, const bGPDlayer *gpl, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, + int UNUSED(cfra), int dflag, bool debug, const float diff_mat[4][4]) { const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)}; const float alpha = 1.0f; @@ -1266,17 +1345,14 @@ static void gp_draw_onionskins( else { copy_v3_v3(color, default_color); } - + if (gpl->gstep > 0) { - bGPDframe *gf; - float fac; - /* draw previous frames first */ - for (gf = gpf->prev; gf; gf = gf->prev) { + for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) { /* check if frame is drawable */ if ((gpf->framenum - gf->framenum) <= gpl->gstep) { /* alpha decreases with distance from curframe index */ - fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); + float fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); color[3] = alpha * fac * 0.66f; gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color, true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat); @@ -1296,8 +1372,7 @@ static void gp_draw_onionskins( else { /* don't draw - disabled */ } - - + /* 2) Now draw next frames */ if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) { copy_v3_v3(color, gpl->gcolor_next); @@ -1305,17 +1380,14 @@ static void gp_draw_onionskins( else { copy_v3_v3(color, default_color); } - + if (gpl->gstep_next > 0) { - bGPDframe *gf; - float fac; - /* now draw next frames */ - for (gf = gpf->next; gf; gf = gf->next) { + for (bGPDframe *gf = gpf->next; gf; gf = gf->next) { /* check if frame is drawable */ if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) { /* alpha decreases with distance from curframe index */ - fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1)); + float fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1)); color[3] = alpha * fac * 0.66f; gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color, true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat); @@ -1335,7 +1407,6 @@ static void gp_draw_onionskins( else { /* don't draw - disabled */ } - } /* draw interpolate strokes (used only while operator is running) */ @@ -1373,29 +1444,27 @@ void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type) /* loop over gpencil data layers, drawing them */ static void gp_draw_data_layers( - bGPDbrush *brush, float alpha, bGPdata *gpd, + const bGPDbrush *brush, float alpha, bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { - bGPDlayer *gpl; float diff_mat[4][4]; - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - bGPDframe *gpf; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* calculate parent position */ ED_gpencil_parent_location(gpl, diff_mat); - bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false; + bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG); short lthick = brush->thickness + gpl->thickness; - + /* don't draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) continue; - + /* get frame to draw */ - gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0); + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0); if (gpf == NULL) continue; - + /* set basic stroke thickness */ glLineWidth(lthick); @@ -1407,10 +1476,10 @@ static void gp_draw_data_layers( if (condition) dflag |= (draw_flag_value); \ else dflag &= ~(draw_flag_value); \ } (void)0 - + /* xray... */ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY); - + /* volumetric strokes... */ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC); @@ -1418,7 +1487,7 @@ static void gp_draw_data_layers( GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL); #undef GP_DRAWFLAG_APPLY - + /* draw 'onionskins' (frame left + right) */ if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) { /* Drawing method - only immediately surrounding (gstep = 0), @@ -1426,11 +1495,11 @@ static void gp_draw_data_layers( */ gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat); } - + /* draw the strokes already in active frame */ gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, gpl->opacity, gpl->tintcolor, false, false, diff_mat); - + /* Draw verts of selected strokes * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering * - locked layers can't be edited, so there's no point showing these verts @@ -1445,16 +1514,13 @@ static void gp_draw_data_layers( { gp_draw_strokes_edit(gpd, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, diff_mat, alpha); } - + /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) */ if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) && (gpf->flag & GP_FRAME_PAINT)) { - /* Set color for drawing buffer stroke - since this may not be set yet */ - // glColor4fv(gpl->color); - /* Buffer stroke needs to be drawn with a different linestyle * to help differentiate them from normal strokes. * @@ -1463,38 +1529,37 @@ static void gp_draw_data_layers( */ if (gpd->sflag & PC_COLOR_VOLUMETRIC) { gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, - dflag, gpd->sbuffer_sflag, gpd->scolor); + dflag, gpd->scolor); } else { - gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor); + gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor, gpd->sfill); } } } } /* draw a short status message in the top-right corner */ -static void gp_draw_status_text(bGPdata *gpd, ARegion *ar) +static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar) { rcti rect; - + /* Cannot draw any status text when drawing OpenGL Renders */ if (G.f & G_RENDER_OGL) return; - + /* Get bounds of region - Necessary to avoid problems with region overlap */ ED_region_visible_rect(ar, &rect); - + /* for now, this should only be used to indicate when we are in stroke editmode */ if (gpd->flag & GP_DATA_STROKE_EDITMODE) { const char *printable = IFACE_("GPencil Stroke Editing"); float printable_size[2]; - int xco, yco; - + BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); - xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; - yco = (rect.ymax - U.widget_unit); - + int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; + int yco = (rect.ymax - U.widget_unit); + /* text label */ UI_ThemeColor(TH_TEXT_HI); #ifdef WITH_INTERNATIONAL @@ -1502,50 +1567,54 @@ static void gp_draw_status_text(bGPdata *gpd, ARegion *ar) #else BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #endif - + /* grease pencil icon... */ // XXX: is this too intrusive? glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - + xco -= U.widget_unit; yco -= (int)printable_size[1] / 2; UI_icon_draw(xco, yco, ICON_GREASEPENCIL); - + glDisable(GL_BLEND); } } /* draw grease-pencil datablock */ static void gp_draw_data( - bGPDbrush *brush, float alpha, bGPdata *gpd, + const bGPDbrush *brush, float alpha, bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { +#if 0 /* disable to see if really needed. re-enable or delete by Dec 2016 */ /* reset line drawing style (in case previous user didn't reset) */ setlinestyle(0); - +#endif + /* turn on smooth lines (i.e. anti-aliasing) */ glEnable(GL_LINE_SMOOTH); - + /* XXX: turn on some way of ensuring that the polygon edges get smoothed * GL_POLYGON_SMOOTH is nasty and shouldn't be used, as it ends up * creating internal white rays due to the ways it accumulates stuff */ - + /* turn on alpha-blending */ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - + /* draw! */ gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag); - + /* turn off alpha blending, then smooth lines */ glDisable(GL_BLEND); // alpha blending glDisable(GL_LINE_SMOOTH); // smooth lines - + +#if 0 /* disable to see if really needed. re-enable or delete by Dec 2016 */ /* restore initial gl conditions */ glColor4f(0, 0, 0, 1); +#endif } /* if we have strokes for scenes (3d view)/clips (movie clip editor) @@ -1573,16 +1642,15 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */ gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL); } - + if (gpd_source) { if (brush != NULL) { gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source, offsx, offsy, winx, winy, cfra, dflag); } - } } - + /* scene/clip data has already been drawn, only object/track data is drawn here * if gpd_source == gpd, we don't have any object/track data and we can skip */ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) { @@ -1608,28 +1676,27 @@ void ED_gpencil_draw_2dimage(const bContext *C) ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); - bGPdata *gpd; + int offsx, offsy, sizex, sizey; int dflag = GP_DRAWDATA_NOSTATUS; - - gpd = ED_gpencil_data_get_active(C); // XXX + + bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX if (gpd == NULL) return; - + /* calculate rect */ switch (sa->spacetype) { case SPACE_IMAGE: /* image */ case SPACE_CLIP: /* clip */ { - /* just draw using standard scaling (settings here are currently ignored anyways) */ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ offsx = 0; offsy = 0; sizex = ar->winx; sizey = ar->winy; - + wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax); - + dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK; break; } @@ -1640,7 +1707,7 @@ void ED_gpencil_draw_2dimage(const bContext *C) offsy = 0; sizex = ar->winx; sizey = ar->winy; - + /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated * and everything moved to standard View2d */ @@ -1652,77 +1719,74 @@ void ED_gpencil_draw_2dimage(const bContext *C) offsy = 0; sizex = ar->winx; sizey = ar->winy; - + dflag |= GP_DRAWDATA_ONLYI2D; break; } - + if (ED_screen_animation_playing(wm)) { /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses) * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes) */ dflag |= GP_DRAWDATA_NO_ONIONS; } - - + /* draw it! */ gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype); } /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly - * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, - * second time with onlyv2d=0 for screen-aligned strokes */ + * Note: this gets called twice - first time with onlyv2d=true to draw 'canvas' strokes, + * second time with onlyv2d=false for screen-aligned strokes */ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) { wmWindowManager *wm = CTX_wm_manager(C); ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); - bGPdata *gpd; int dflag = 0; /* check that we have grease-pencil stuff to draw */ if (sa == NULL) return; - gpd = ED_gpencil_data_get_active(C); // XXX + bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX if (gpd == NULL) return; - + /* special hack for Image Editor */ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP)) dflag |= GP_DRAWDATA_IEDITHACK; - + /* draw it! */ if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS); if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS; - + gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype); - + /* draw status text (if in screen/pixel-space) */ - if (onlyv2d == false) { + if (!onlyv2d) { gp_draw_status_text(gpd, ar); } } /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly - * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes, - * second time with only3d=0 for screen-aligned strokes */ + * Note: this gets called twice - first time with only3d=true to draw 3d-strokes, + * second time with only3d=false for screen-aligned strokes */ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, ARegion *ar, bool only3d) { - bGPdata *gpd; int dflag = 0; RegionView3D *rv3d = ar->regiondata; int offsx, offsy, winx, winy; - + /* check that we have grease-pencil stuff to draw */ - gpd = ED_gpencil_data_get_active_v3d(scene, v3d); + bGPdata *gpd = ED_gpencil_data_get_active_v3d(scene, v3d); if (gpd == NULL) return; - + /* when rendering to the offscreen buffer we don't want to * deal with the camera border, otherwise map the coords to the camera border. */ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { rctf rectf; ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */ - + offsx = iroundf(rectf.xmin); offsy = iroundf(rectf.ymin); winx = iroundf(rectf.xmax - rectf.xmin); @@ -1734,7 +1798,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg winx = ar->winx; winy = ar->winy; } - + /* set flags */ if (only3d) { /* 3D strokes/3D space: @@ -1743,28 +1807,27 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg */ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); } - + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { /* don't draw status text when "only render" flag is set */ dflag |= GP_DRAWDATA_NOSTATUS; } - + if ((wm == NULL) || ED_screen_animation_playing(wm)) { /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses) * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes) */ dflag |= GP_DRAWDATA_NO_ONIONS; } - + /* draw it! */ - gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); - + gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); } void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype) { int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D; - + gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype); } diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index ec5a42c23a5..8bac80d6a3f 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -75,9 +75,10 @@ #include "ED_screen.h" #include "ED_view3d.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "gpencil_intern.h" /* ************************************************ */ @@ -958,28 +959,28 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso) static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)) { GP_EditBrush_Data *brush = gpsculpt_get_brush(CTX_data_scene(C)); - + if (brush) { - glPushMatrix(); - - glTranslatef((float)x, (float)y, 0.0f); - + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - + /* Inner Ring: Light color for action of the brush */ /* TODO: toggle between add and remove? */ - glColor4ub(255, 255, 255, 200); - glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size, 40); - + immUniformColor4ub(255, 255, 255, 200); + imm_draw_lined_circle(pos, x, y, brush->size, 40); + /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */ - glColor3ub(30, 30, 30); - glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size + 1, 40); - + immUniformColor3ub(30, 30, 30); + imm_draw_lined_circle(pos, x, y, brush->size + 1, 40); + + immUnbindProgram(); + glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); } } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index c23bfb1ff60..b483402d6c8 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -69,9 +69,10 @@ #include "ED_view3d.h" #include "ED_clip.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -1546,6 +1547,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) bGPDpalettecolor *palcolor = p->palettecolor; bGPdata *pdata = p->gpd; copy_v4_v4(pdata->scolor, palcolor->color); + copy_v4_v4(pdata->sfill, palcolor->fill); pdata->sflag = palcolor->flag; /* lock axis */ p->lock_axis = ts->gp_sculpt.lock_axis; @@ -1832,28 +1834,28 @@ static void gp_paint_cleanup(tGPsdata *p) static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) { tGPsdata *p = (tGPsdata *)p_ptr; - + if (p->paintmode == GP_PAINTMODE_ERASER) { - glPushMatrix(); - - glTranslatef((float)x, (float)y, 0.0f); - + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - - glColor4ub(255, 100, 100, 20); - glutil_draw_filled_arc(0.0, M_PI * 2.0, p->radius, 40); - - setlinestyle(6); - - glColor4ub(255, 100, 100, 200); - glutil_draw_lined_arc(0.0, M_PI * 2.0, p->radius, 40); - + + immUniformColor4ub(255, 100, 100, 20); + imm_draw_filled_circle(pos, x, y, p->radius, 40); + + setlinestyle(6); /* TODO: handle line stipple in shader */ + + immUniformColor4ub(255, 100, 100, 200); + imm_draw_lined_circle(pos, x, y, p->radius, 40); + + immUnbindProgram(); + setlinestyle(0); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); } } diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index d3d2c465d46..25fcdf33524 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -38,23 +38,21 @@ struct bContext; struct ColorManagedViewSettings; struct ColorManagedDisplaySettings; -void fdrawbezier(float vec[4][3]); -void fdrawline(float x1, float y1, float x2, float y2); -void fdrawbox(float x1, float y1, float x2, float y2); -void sdrawline(int x1, int y1, int x2, int y2); -#if 0 -void sdrawtri(int x1, int y1, int x2, int y2); -void sdrawtrifill(int x1, int y1, int x2, int y2); -#endif -void sdrawbox(int x1, int y1, int x2, int y2); - -void sdrawXORline(int x0, int y0, int x1, int y1); -void sdrawXORline4(int nr, int x0, int y0, int x1, int y1); +/* Several functions defined here are being DEPRECATED for Blender 2.8 + * + * Do not use them in new code, and you are encouraged to + * convert existing code to draw without these. + * + * These will be deleted before we ship 2.8! + * - merwin + */ -void fdrawXORellipse(float xofs, float yofs, float hw, float hh); -void fdrawXORcirc(float xofs, float yofs, float rad); +void fdrawline(float x1, float y1, float x2, float y2); /* DEPRECATED */ +void fdrawbox(float x1, float y1, float x2, float y2); /* DEPRECATED */ +void sdrawline(int x1, int y1, int x2, int y2); /* DEPRECATED */ +void sdrawbox(int x1, int y1, int x2, int y2); /* DEPRECATED */ -void fdrawcheckerboard(float x1, float y1, float x2, float y2); +void fdrawcheckerboard(float x1, float y1, float x2, float y2); /* DEPRECATED */ /* OpenGL stipple defines */ extern const unsigned char stipple_halftone[128]; @@ -74,7 +72,7 @@ extern const unsigned char stipple_checker_8px[128]; * \param radius The arc radius. * \param nsegments The number of segments to use in drawing the arc. */ -void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments); +void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments); /* DEPRECATED */ /** * Draw a filled arc with the given \a radius, @@ -87,7 +85,55 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments * \param radius The arc radius. * \param nsegments The number of segments to use in drawing the arc. */ -void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments); +void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments); /* DEPRECATED */ + +/** + * Draw a circle outline with the given \a radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \param pos The vertex attribute number for position. + * \param x Horizontal center. + * \param y Vertical center. + * \param radius The circle's radius. + * \param nsegments The number of segments to use in drawing (more = smoother). + */ +void imm_draw_lined_circle(unsigned pos, float x, float y, float radius, int nsegments); + +/* use this version when VertexFormat has a vec3 position */ +void imm_draw_lined_circle_3D(unsigned pos, float x, float y, float radius, int nsegments); + +/** + * Draw a filled circle with the given \a radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \param pos The vertex attribute number for position. + * \param x Horizontal center. + * \param y Vertical center. + * \param radius The circle's radius. + * \param nsegments The number of segments to use in drawing (more = smoother). + */ +void imm_draw_filled_circle(unsigned pos, float x, float y, float radius, int nsegments); + +/** +* Draw a lined box. +* +* \param pos The vertex attribute number for position. +* \param x1 left. +* \param y1 bottom. +* \param x2 right. +* \param y2 top. +*/ +void imm_draw_line_box(unsigned pos, float x1, float y1, float x2, float y2); + +/* use this version when VertexFormat has a vec3 position */ +void imm_draw_line_box_3D(unsigned pos, float x1, float y1, float x2, float y2); + +/** +* Pack color into 3 bytes +* +* \param x color. +*/ +void imm_cpack(unsigned int x); /** * Returns a float value as obtained by glGetFloatv. @@ -176,12 +222,11 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, int */ void glaDefine2DArea(struct rcti *screen_rect); -typedef struct gla2DDrawInfo gla2DDrawInfo; +#if 0 /* UNUSED */ -/* UNUSED */ -#if 0 +typedef struct gla2DDrawInfo gla2DDrawInfo; -gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect); +gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect); void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y); void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]); @@ -190,7 +235,8 @@ void glaEnd2DDraw(gla2DDrawInfo *di); /** Adjust the transformation mapping of a 2d area */ void gla2DGetMap(gla2DDrawInfo *di, struct rctf *rect); void gla2DSetMap(gla2DDrawInfo *di, struct rctf *rect); -#endif + +#endif /* UNUSED */ void set_inverted_drawing(int enable); void setlinestyle(int nr); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index ec09add56b8..f5f66a07aea 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -36,6 +36,8 @@ #include "DNA_view2d_types.h" #include "DNA_view3d_types.h" +#include "BLI_compiler_attrs.h" + struct wmWindowManager; struct wmWindow; struct wmNotifier; @@ -47,6 +49,7 @@ struct bScreen; struct ARegion; struct uiBlock; struct rcti; +struct Main; /* regions */ void ED_region_do_listen(struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, struct wmNotifier *note); @@ -118,6 +121,7 @@ void ED_screen_full_restore(struct bContext *C, ScrArea *sa); struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state); void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg); bool ED_screen_stereo3d_required(struct bScreen *screen); +void ED_screen_preview_render(const struct bScreen *screen, int size_x, int size_y, unsigned int *r_rect) ATTR_NONNULL(); /* anim */ void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9fbce7dd203..d48cfbee413 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -308,18 +308,20 @@ typedef enum { * Functions to draw various shapes, taking theme settings into account. * Used for code that draws its own UI style elements. */ -void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad); +void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad, const float color[4]); void UI_draw_roundbox_corner_set(int type); int UI_draw_roundbox_corner_get(void); void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad); void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy); -void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad); +void UI_draw_roundbox_gl_mode_3ubAlpha(int mode, float minx, float miny, float maxx, float maxy, float rad, unsigned char col[3], unsigned char alpha); +void UI_draw_roundbox_gl_mode_3fvAlpha(int mode, float minx, float miny, float maxx, float maxy, float rad, float col[3], float alpha); +void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad, float col[4]); void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown); void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight); void UI_draw_text_underline(int pos_x, int pos_y, int len, int height); void UI_draw_safe_areas( - float x1, float x2, float y1, float y2, + unsigned pos, float x1, float x2, float y1, float y2, const float title_aspect[2], const float action_aspect[2]); /* state for scrolldrawing */ @@ -1050,7 +1052,7 @@ void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs, const struct rcti * void UI_fontstyle_draw_simple(const struct uiFontStyle *fs, float x, float y, const char *str); void UI_fontstyle_draw_simple_backdrop( const struct uiFontStyle *fs, float x, float y, const char *str, - const unsigned char fg[4], const unsigned char bg[4]); + const float col_fg[4], const float col_bg[4]); int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str); int UI_fontstyle_height_max(const struct uiFontStyle *fs); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index f8a5f30a596..be03647d6f4 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -320,13 +320,13 @@ struct bThemeState { void UI_ThemeColor(int colorid); // sets the color plus alpha -void UI_ThemeColor4(int colorid); +void UI_ThemeColor4(int colorid); // sets color plus offset for shade -void UI_ThemeColorShade(int colorid, int offset); +void UI_ThemeColorShade(int colorid, int offset); // sets color plus offset for alpha -void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset); +void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset); // sets color, which is blend between two theme colors void UI_ThemeColorBlend(int colorid1, int colorid2, float fac); @@ -352,6 +352,9 @@ void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]) void UI_GetThemeColor4fv(int colorid, float col[4]); // get four color values, range 0.0-1.0, complete with shading offset for the RGB components void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]); +void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]); +// get four color values, range 0.0-1.0, complete with shading offset for the RGB components and blending +void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int offset, float col[4]); // get the 3 or 4 byte values void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 01ea1e953fa..f17c61b8aa1 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -57,6 +57,7 @@ #include "GPU_draw.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "UI_interface.h" @@ -79,68 +80,98 @@ int UI_draw_roundbox_corner_get(void) return roundboxtype; } -void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad) +void UI_draw_roundbox_gl_mode_3ubAlpha(int mode, float minx, float miny, float maxx, float maxy, float rad, unsigned char col[3], unsigned char alpha) +{ + float colv[4]; + colv[0] = ((float)col[0]) / 255; + colv[1] = ((float)col[1]) / 255; + colv[2] = ((float)col[2]) / 255; + colv[3] = ((float)alpha) / 255; + UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad, colv); +} + +void UI_draw_roundbox_gl_mode_3fvAlpha(int mode, float minx, float miny, float maxx, float maxy, float rad, float col[3], float alpha) +{ + float colv[4]; + colv[0] = col[0]; + colv[1] = col[1]; + colv[2] = col[2]; + colv[3] = alpha; + UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad, colv); +} + +void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad, float col[4]) { float vec[7][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293}, {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; int a; + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + /* mult */ for (a = 0; a < 7; a++) { mul_v2_fl(vec[a], rad); } - glBegin(mode); + if (mode == GL_POLYGON) { + mode = GL_TRIANGLE_FAN; + } + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(col); + + immBeginAtMost(mode, 36); /* start with corner right-bottom */ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { - glVertex2f(maxx - rad, miny); + immVertex2f(pos, maxx - rad, miny); for (a = 0; a < 7; a++) { - glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]); + immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]); } - glVertex2f(maxx, miny + rad); + immVertex2f(pos, maxx, miny + rad); } else { - glVertex2f(maxx, miny); + immVertex2f(pos, maxx, miny); } /* corner right-top */ if (roundboxtype & UI_CNR_TOP_RIGHT) { - glVertex2f(maxx, maxy - rad); + immVertex2f(pos, maxx, maxy - rad); for (a = 0; a < 7; a++) { - glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]); + immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]); } - glVertex2f(maxx - rad, maxy); + immVertex2f(pos, maxx - rad, maxy); } else { - glVertex2f(maxx, maxy); + immVertex2f(pos, maxx, maxy); } /* corner left-top */ if (roundboxtype & UI_CNR_TOP_LEFT) { - glVertex2f(minx + rad, maxy); + immVertex2f(pos, minx + rad, maxy); for (a = 0; a < 7; a++) { - glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]); + immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]); } - glVertex2f(minx, maxy - rad); + immVertex2f(pos, minx, maxy - rad); } else { - glVertex2f(minx, maxy); + immVertex2f(pos, minx, maxy); } /* corner left-bottom */ if (roundboxtype & UI_CNR_BOTTOM_LEFT) { - glVertex2f(minx, miny + rad); + immVertex2f(pos, minx, miny + rad); for (a = 0; a < 7; a++) { - glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]); + immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]); } - glVertex2f(minx + rad, miny); + immVertex2f(pos, minx + rad, miny); } else { - glVertex2f(minx, miny); + immVertex2f(pos, minx, miny); } - glEnd(); + immEnd(); + immUnbindProgram(); } static void round_box_shade_col(const float col1[3], float const col2[3], const float fac) @@ -381,17 +412,16 @@ void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, f /* set antialias line */ glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, minx, miny, maxx, maxy, rad); + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, minx, miny, maxx, maxy, rad, color); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); } /* (old, used in outliner) plain antialiased filled box */ -void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad) +void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad, const float color[4]) { - ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA); + ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA, color); } void UI_draw_text_underline(int pos_x, int pos_y, int len, int height) @@ -451,43 +481,36 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w /** * Draw title and text safe areas. * - * The first 4 parameters are the offsets for the view, not the zones. + * The first parameter is a GL_FLOAT, 2, KEEP_FLOAT vertex attrib + * The next 4 parameters are the offsets for the view, not the zones. */ void UI_draw_safe_areas( - float x1, float x2, float y1, float y2, + unsigned pos, float x1, float x2, float y1, float y2, const float title_aspect[2], const float action_aspect[2]) { const float size_x_half = (x2 - x1) * 0.5f; const float size_y_half = (y2 - y1) * 0.5f; const float *safe_areas[] = {title_aspect, action_aspect}; - int safe_len = ARRAY_SIZE(safe_areas); + const int safe_len = ARRAY_SIZE(safe_areas); bool is_first = true; for (int i = 0; i < safe_len; i++) { if (safe_areas[i][0] || safe_areas[i][1]) { - float margin_x, margin_y; - float minx, miny, maxx, maxy; - if (is_first) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f); is_first = false; } - margin_x = safe_areas[i][0] * size_x_half; - margin_y = safe_areas[i][1] * size_y_half; + float margin_x = safe_areas[i][0] * size_x_half; + float margin_y = safe_areas[i][1] * size_y_half; - minx = x1 + margin_x; - miny = y1 + margin_y; - maxx = x2 - margin_x; - maxy = y2 - margin_y; + float minx = x1 + margin_x; + float miny = y1 + margin_y; + float maxx = x2 - margin_x; + float maxy = y2 - margin_y; - glBegin(GL_LINE_LOOP); - glVertex2f(maxx, miny); - glVertex2f(maxx, maxy); - glVertex2f(minx, maxy); - glVertex2f(minx, miny); - glEnd(); + imm_draw_line_box(pos, minx, miny, maxx, maxy); } } } @@ -501,9 +524,9 @@ static void draw_scope_end(const rctf *rect, GLint *scissor) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* outline */ - glColor4f(0.f, 0.f, 0.f, 0.5f); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.5f}; + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f, color); } static void histogram_draw_one( @@ -573,9 +596,10 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - UI_ThemeColor4(TH_PREVIEW_BACK); + float color[4]; + UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color); /* need scissor test, histogram can draw outside of boundary */ GLint scissor[4]; @@ -660,9 +684,10 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - UI_ThemeColor4(TH_PREVIEW_BACK); + float color[4]; + UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color); /* need scissor test, waveform can draw outside of boundary */ glGetIntegerv(GL_VIEWPORT, scissor); @@ -904,9 +929,10 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - UI_ThemeColor4(TH_PREVIEW_BACK); + float color[4]; + UI_GetThemeColor4fv(TH_PREVIEW_BACK, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color); /* need scissor test, hvectorscope can draw outside of boundary */ GLint scissor[4]; @@ -1189,9 +1215,8 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect) float size; /* backdrop */ - glColor3ubv((unsigned char *)wcol->inner); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f); + UI_draw_roundbox_gl_mode_3ubAlpha(GL_POLYGON, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f, (unsigned char *)wcol->inner, 255); /* sphere color */ glCullFace(GL_BACK); @@ -1513,9 +1538,9 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc (rect.ymax + 1) - (rect.ymin - 1)); if (scopes->track_disabled) { - glColor4f(0.7f, 0.3f, 0.3f, 0.3f); + float color[4] = {0.7f, 0.3f, 0.3f, 0.3f}; UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color); ok = true; } @@ -1551,9 +1576,9 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc ImBuf *drawibuf = scopes->track_preview; if (scopes->use_track_mask) { - glColor4f(0.0f, 0.0f, 0.0f, 0.3f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.3f}; UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color); } glaDrawPixelsSafe(rect.xmin, rect.ymin + 1, drawibuf->x, drawibuf->y, @@ -1595,9 +1620,9 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc } if (!ok) { - glColor4f(0.f, 0.f, 0.f, 0.3f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.3f}; UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); + UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color); } /* outline */ @@ -1671,46 +1696,54 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol /* ****************************************************** */ -static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha) +static void ui_shadowbox(unsigned pos, unsigned color, float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha) { /* right quad */ - glColor4ub(0, 0, 0, alpha); - glVertex2f(maxx, miny); - glVertex2f(maxx, maxy - 0.3f * shadsize); - glColor4ub(0, 0, 0, 0); - glVertex2f(maxx + shadsize, maxy - 0.75f * shadsize); - glVertex2f(maxx + shadsize, miny); + immAttrib4ub(color, 0, 0, 0, alpha); + immVertex2f(pos, maxx, miny); + immVertex2f(pos, maxx, maxy - 0.3f * shadsize); + immAttrib4ub(color, 0, 0, 0, 0); + immVertex2f(pos, maxx + shadsize, maxy - 0.75f * shadsize); + immVertex2f(pos, maxx + shadsize, miny); /* corner shape */ - glColor4ub(0, 0, 0, alpha); - glVertex2f(maxx, miny); - glColor4ub(0, 0, 0, 0); - glVertex2f(maxx + shadsize, miny); - glVertex2f(maxx + 0.7f * shadsize, miny - 0.7f * shadsize); - glVertex2f(maxx, miny - shadsize); + immAttrib4ub(color, 0, 0, 0, alpha); + immVertex2f(pos, maxx, miny); + immAttrib4ub(color, 0, 0, 0, 0); + immVertex2f(pos, maxx + shadsize, miny); + immVertex2f(pos, maxx + 0.7f * shadsize, miny - 0.7f * shadsize); + immVertex2f(pos, maxx, miny - shadsize); /* bottom quad */ - glColor4ub(0, 0, 0, alpha); - glVertex2f(minx + 0.3f * shadsize, miny); - glVertex2f(maxx, miny); - glColor4ub(0, 0, 0, 0); - glVertex2f(maxx, miny - shadsize); - glVertex2f(minx + 0.5f * shadsize, miny - shadsize); + immAttrib4ub(color, 0, 0, 0, alpha); + immVertex2f(pos, minx + 0.3f * shadsize, miny); + immVertex2f(pos, maxx, miny); + immAttrib4ub(color, 0, 0, 0, 0); + immVertex2f(pos, maxx, miny - shadsize); + immVertex2f(pos, minx + 0.5f * shadsize, miny - shadsize); } void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy) { glEnable(GL_BLEND); - - glBegin(GL_QUADS); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + immBegin(GL_QUADS, 36); /* accumulated outline boxes to make shade not linear, is more pleasant */ - ui_shadowbox(minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8); - ui_shadowbox(minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8); - ui_shadowbox(minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8); - - glEnd(); + ui_shadowbox(pos, color, minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8); + ui_shadowbox(pos, color, minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8); + ui_shadowbox(pos, color, minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8); + immEnd(); + + immUnbindProgram(); + glDisable(GL_BLEND); } @@ -1741,16 +1774,15 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha float calpha = dalpha; for (; i--; a -= aspect) { /* alpha ranges from 2 to 20 or so */ - glColor4f(0.0f, 0.0f, 0.0f, calpha); + float color[4] = {0.0f, 0.0f, 0.0f, calpha}; + UI_draw_roundbox_gl_mode(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a, color); calpha += dalpha; - - UI_draw_roundbox_gl_mode(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a); } /* outline emphasis */ glEnable(GL_LINE_SMOOTH); - glColor4ub(0, 0, 0, 100); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.4f}; + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f, color); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 5154a77ad21..0a21c89e692 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -139,8 +139,8 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c wmWindow *win = CTX_wm_window(C); int x = win->eventstate->x; int y = win->eventstate->y; - const unsigned char fg[4] = {255, 255, 255, 255}; - const unsigned char bg[4] = {0, 0, 0, 50}; + const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; if ((name[0] == '\0') || @@ -154,7 +154,7 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c y += U.widget_unit; - UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg); + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg); } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a761bcfdf5e..241ac99edde 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -185,7 +185,6 @@ typedef struct uiSelectContextStore { uiSelectContextElem *elems; int elems_len; bool do_free; - bool is_enabled; /* When set, simply copy values (don't apply difference). * Rules are: * - dragging numbers uses delta. @@ -1160,14 +1159,11 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl ui_but_execute_begin(C, ar, but, &active_back); #ifdef USE_ALLSELECT - if (data->select_others.is_enabled) { - /* init once! */ - if (mbut_state->select_others.elems_len == 0) { - ui_selectcontext_begin(C, but, &mbut_state->select_others); - } - if (mbut_state->select_others.elems_len == 0) { - mbut_state->select_others.elems_len = -1; - } + if (mbut_state->select_others.elems_len == 0) { + ui_selectcontext_begin(C, but, &mbut_state->select_others); + } + if (mbut_state->select_others.elems_len == 0) { + mbut_state->select_others.elems_len = -1; } /* needed so we apply the right deltas */ @@ -2055,12 +2051,7 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton else # endif if (data->select_others.elems_len == 0) { - wmWindow *win = CTX_wm_window(C); - /* may have been enabled before activating */ - if (data->select_others.is_enabled || IS_ALLSELECT_EVENT(win->eventstate)) { - ui_selectcontext_begin(C, but, &data->select_others); - data->select_others.is_enabled = true; - } + ui_selectcontext_begin(C, but, &data->select_others); } if (data->select_others.elems_len == 0) { /* dont check again */ @@ -3061,11 +3052,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) #ifdef USE_ALLSELECT if (is_num_but) { - if (IS_ALLSELECT_EVENT(win->eventstate)) { - data->select_others.is_enabled = true; - data->select_others.is_copy = true; - - } + data->select_others.is_copy = true; } #endif @@ -3665,15 +3652,6 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat data->menu->popup = but->block->handle->popup; } -#ifdef USE_ALLSELECT - { - wmWindow *win = CTX_wm_window(C); - if (IS_ALLSELECT_EVENT(win->eventstate)) { - data->select_others.is_enabled = true; - } - } -#endif - /* this makes adjacent blocks auto open from now on */ //if (but->block->auto_open == 0) but->block->auto_open = 1; } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 65b12fcd64e..0573e8d9c94 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -35,6 +35,7 @@ #include "GPU_extensions.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -504,8 +505,12 @@ static void init_internal_icons(void) icongltex.id = 0; } +#if 0 /* should be a compile-time check (if needed at all) */ /* we only use a texture for cards with non-power of two */ if (GPU_full_non_power_of_two_support()) { +#else + { +#endif glGenTextures(1, &icongltex.id); if (icongltex.id) { @@ -533,11 +538,6 @@ static void init_internal_icons(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); - - if (glGetError() == GL_OUT_OF_MEMORY) { - glDeleteTextures(1, &icongltex.id); - icongltex.id = 0; - } } } } @@ -851,12 +851,15 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi { ID *id = (icon->type != 0) ? icon->obj : NULL; PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj; + /* Using jobs for screen previews crashes due to offscreen rendering. + * XXX would be nicer if PreviewImage could store if it supports jobs */ + const bool use_jobs = !id || (GS(id->name) != ID_SCR); if (prv) { const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; if (id || (prv->tag & PRV_TAG_DEFFERED) != 0) { - ui_id_preview_image_render_size(C, NULL, id, prv, size, true); + ui_id_preview_image_render_size(C, NULL, id, prv, size, use_jobs); } } break; @@ -1017,33 +1020,40 @@ static void icon_draw_texture( { float x1, x2, y1, y2; - if (rgb) glColor4f(rgb[0], rgb[1], rgb[2], alpha); - else glColor4f(alpha, alpha, alpha, alpha); - x1 = ix * icongltex.invw; x2 = (ix + ih) * icongltex.invw; y1 = iy * icongltex.invh; y2 = (iy + ih) * icongltex.invh; - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); - glBindTexture(GL_TEXTURE_2D, icongltex.id); - /* sharper downscaling, has no effect when scale matches with a mip level */ glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -0.5f); - glBegin(GL_QUADS); - glTexCoord2f(x1, y1); - glVertex2f(x, y); + glBindTexture(GL_TEXTURE_2D, icongltex.id); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); - glTexCoord2f(x2, y1); - glVertex2f(x + w, y); + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); + if (rgb) immUniform4f("color", rgb[0], rgb[1], rgb[2], alpha); + else immUniform4f("color", alpha, alpha, alpha, alpha); - glTexCoord2f(x2, y2); - glVertex2f(x + w, y + h); + immUniform1i("image", 0); - glTexCoord2f(x1, y2); - glVertex2f(x, y + h); - glEnd(); + immBegin(GL_TRIANGLE_STRIP, 4); + immAttrib2f(texCoord, x1, y2); + immVertex2f(pos, x, y + h); + + immAttrib2f(texCoord, x1, y1); + immVertex2f(pos, x, y); + + immAttrib2f(texCoord, x2, y2); + immVertex2f(pos, x + w, y + h); + + immAttrib2f(texCoord, x2, y1); + immVertex2f(pos, x + w, y); + immEnd(); + + immUnbindProgram(); glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f); @@ -1162,7 +1172,7 @@ void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big, } } -static void ui_id_brush_render(const bContext *C, ID *id) +static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs) { PreviewImage *pi = BKE_previewimg_id_ensure(id); enum eIconSizes i; @@ -1174,7 +1184,7 @@ static void ui_id_brush_render(const bContext *C, ID *id) /* check if rect needs to be created; changed * only set by dynamic icons */ if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) { - icon_set_image(C, NULL, id, pi, i, true); + icon_set_image(C, NULL, id, pi, i, use_jobs); pi->flag[i] &= ~PRV_CHANGED; } } @@ -1187,7 +1197,7 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id) if (br->flag & BRUSH_CUSTOM_ICON) { BKE_icon_id_ensure(id); - ui_id_brush_render(C, id); + ui_id_icon_render(C, id, true); } else { Object *ob = CTX_data_active_object(C); @@ -1234,6 +1244,15 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id) return id->icon_id; } +static int ui_id_screen_get_icon(const bContext *C, ID *id) +{ + BKE_icon_id_ensure(id); + /* Don't use jobs here, offscreen rendering doesn't like this and crashes. */ + ui_id_icon_render(C, id, false); + + return id->icon_id; +} + int ui_id_icon_get(const bContext *C, ID *id, const bool big) { int iconid = 0; @@ -1252,6 +1271,9 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big) /* checks if not exists, or changed */ UI_id_icon_render(C, NULL, id, big, true); break; + case ID_SCR: + iconid = ui_id_screen_get_icon(C, id); + break; default: break; } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index d8f9fdcbaae..7529f60c6f0 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -682,7 +682,8 @@ struct wmIMEData *ui_but_ime_data_get(uiBut *but); /* interface_widgets.c */ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); -void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha); +void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, + float rad, bool use_alpha, const float color[4]); void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect); void ui_draw_pie_center(uiBlock *block); uiWidgetColors *ui_tooltip_get_theme(void); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index c131bcb8e14..dd06147f226 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -65,6 +65,8 @@ #include "UI_interface_icons.h" #include "UI_resources.h" +#include "GPU_immediate.h" + #include "interface_intern.h" /*********************** defines and structs ************************/ @@ -1518,7 +1520,8 @@ static void ui_panel_category_draw_tab( int mode, float minx, float miny, float maxx, float maxy, float rad, int roundboxtype, const bool use_highlight, const bool use_shadow, - const unsigned char highlight_fade[3]) + const unsigned char highlight_fade[3], + const unsigned char col[3]) { float vec[4][2] = { {0.195, 0.02}, @@ -1527,74 +1530,88 @@ static void ui_panel_category_draw_tab( {0.98, 0.805}}; int a; + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + /* mult */ for (a = 0; a < 4; a++) { mul_v2_fl(vec[a], rad); } - glBegin(mode); + if (mode == GL_POLYGON) { + mode = GL_TRIANGLE_FAN; + } + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + immBeginAtMost(mode, 24); + + immAttrib3ubv(color, col); /* start with corner right-top */ if (use_highlight) { if (roundboxtype & UI_CNR_TOP_RIGHT) { - glVertex2f(maxx, maxy - rad); + immVertex2f(pos, maxx, maxy - rad); for (a = 0; a < 4; a++) { - glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]); + immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]); } - glVertex2f(maxx - rad, maxy); + immVertex2f(pos, maxx - rad, maxy); } else { - glVertex2f(maxx, maxy); + immVertex2f(pos, maxx, maxy); } /* corner left-top */ if (roundboxtype & UI_CNR_TOP_LEFT) { - glVertex2f(minx + rad, maxy); + immVertex2f(pos, minx + rad, maxy); for (a = 0; a < 4; a++) { - glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]); + immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]); } - glVertex2f(minx, maxy - rad); + immVertex2f(pos, minx, maxy - rad); } else { - glVertex2f(minx, maxy); + immVertex2f(pos, minx, maxy); } } if (use_highlight && !use_shadow) { if (highlight_fade) { - glColor3ubv(highlight_fade); + immAttrib3ubv(color, highlight_fade); } - glVertex2f(minx, miny + rad); - glEnd(); + immVertex2f(pos, minx, miny + rad); + immEnd(); + immUnbindProgram(); return; } /* corner left-bottom */ if (roundboxtype & UI_CNR_BOTTOM_LEFT) { - glVertex2f(minx, miny + rad); + immVertex2f(pos, minx, miny + rad); for (a = 0; a < 4; a++) { - glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]); + immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]); } - glVertex2f(minx + rad, miny); + immVertex2f(pos, minx + rad, miny); } else { - glVertex2f(minx, miny); + immVertex2f(pos, minx, miny); } /* corner right-bottom */ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { - glVertex2f(maxx - rad, miny); + immVertex2f(pos, maxx - rad, miny); for (a = 0; a < 4; a++) { - glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]); + immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]); } - glVertex2f(maxx, miny + rad); + immVertex2f(pos, maxx, miny + rad); } else { - glVertex2f(maxx, miny); + immVertex2f(pos, maxx, miny); } - glEnd(); + immEnd(); + immUnbindProgram(); } @@ -1754,19 +1771,19 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) if (is_active) #endif { - glColor3ubv(is_active ? theme_col_tab_active : theme_col_tab_inactive); ui_panel_category_draw_tab(GL_POLYGON, rct->xmin, rct->ymin, rct->xmax, rct->ymax, - tab_curve_radius - px, roundboxtype, true, true, NULL); + tab_curve_radius - px, roundboxtype, true, true, NULL, + is_active ? theme_col_tab_active : theme_col_tab_inactive); /* tab outline */ - glColor3ubv(theme_col_tab_outline); ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px, - tab_curve_radius, roundboxtype, true, true, NULL); + tab_curve_radius, roundboxtype, true, true, NULL, theme_col_tab_outline); + /* tab highlight (3d look) */ - glColor3ubv(is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive); ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, tab_curve_radius, roundboxtype, true, false, - is_active ? theme_col_back : theme_col_tab_inactive); + is_active ? theme_col_back : theme_col_tab_inactive, + is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive); } /* tab blackline */ diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 466978272bc..62bab15dfb3 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -1059,7 +1059,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *ar, uiBut *but, char *str) return match; } -static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) +static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *ar) { uiSearchboxData *data = ar->regiondata; @@ -1077,6 +1077,9 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) if (data->preview) { /* draw items */ for (a = 0; a < data->items.totitem; a++) { + /* ensure icon is up-to-date */ + ui_icon_ensure_deferred(C, data->items.icons[a], data->preview); + ui_searchbox_butrect(&rect, data, a); /* widget itself */ diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 8b41302b5bb..8bba8fc5534 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -293,7 +293,7 @@ void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const cha */ void UI_fontstyle_draw_simple_backdrop( const uiFontStyle *fs, float x, float y, const char *str, - const unsigned char fg[4], const unsigned char bg[4]) + const float col_fg[4], const float col_bg[4]) { if (fs->kerning == 1) BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); @@ -307,7 +307,6 @@ void UI_fontstyle_draw_simple_backdrop( const float margin = height / 4.0f; /* backdrop */ - glColor4ubv(bg); UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA); UI_draw_roundbox( @@ -315,9 +314,9 @@ void UI_fontstyle_draw_simple_backdrop( (y + decent) - margin, x + width + margin, (y + decent) + height + margin, - margin); + margin, col_bg); - glColor4ubv(fg); + glColor4fv(col_fg); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 4db1c845c23..2cdcf7a604d 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -417,17 +417,30 @@ static void template_ID( type = idptr.type; if (flag & UI_ID_PREVIEWS) { + ARegion *region = CTX_wm_region(C); + const bool use_big_size = (region->regiontype != RGN_TYPE_HEADER); /* silly check, could be more generic */ + /* Ugly exception for screens here, drawing their preview in icon size looks ugly/useless */ + const bool use_preview_icon = use_big_size || (id && (GS(id->name) != ID_SCR)); + const short width = UI_UNIT_X * (use_big_size ? 6 : 1.6f); + const short height = UI_UNIT_Y * (use_big_size ? 6: 1); + template->preview = true; - but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, + but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, width, height, TIP_(template_id_browse_tip(type))); - ui_def_but_icon(but, id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type), - UI_HAS_ICON | UI_BUT_ICON_PREVIEW); + if (use_preview_icon) { + ui_def_but_icon(but, ui_id_icon_get(C, id, use_big_size), UI_HAS_ICON | UI_BUT_ICON_PREVIEW); + } + else { + ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON); + UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT); + } if ((idfrom && idfrom->lib) || !editable) UI_but_flag_enable(but, UI_BUT_DISABLED); - - uiLayoutRow(layout, true); + if (use_big_size) { + uiLayoutRow(layout, true); + } } else if (flag & UI_ID_BROWSE) { but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y, diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index d43a94c5514..b75ecf68136 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -58,6 +58,7 @@ #include "interface_intern.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #ifdef WITH_INPUT_IME # include "WM_types.h" @@ -211,22 +212,23 @@ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y glDisable(GL_BLEND); } -void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha) +void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, + float rad, bool use_alpha, const float color[4]) { - float color[4]; + float draw_color[4]; int j; - + + copy_v4_v4(draw_color, color); + glEnable(GL_BLEND); - glGetFloatv(GL_CURRENT_COLOR, color); if (use_alpha) { - color[3] = 0.5f; + draw_color[3] = 0.5f; } - color[3] *= 0.125f; - glColor4fv(color); + draw_color[3] *= 0.125f; for (j = 0; j < WIDGET_AA_JITTER; j++) { glTranslate2fv(jit[j]); - UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad); + UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad, draw_color); glTranslatef(-jit[j][0], -jit[j][1], 0.0f); } @@ -1461,37 +1463,40 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b /* for underline drawing */ float font_xofs, font_yofs; - UI_fontstyle_draw_ex(fstyle, rect, drawstr + but->ofs, - drawstr_left_len - but->ofs, &font_xofs, &font_yofs); + int drawlen = (drawstr_left_len == INT_MAX) ? strlen(drawstr + but->ofs) : (drawstr_left_len - but->ofs); - if (but->menu_key != '\0') { - char fixedbuf[128]; - const char *str; + if (drawlen > 0) { + UI_fontstyle_draw_ex(fstyle, rect, drawstr + but->ofs, drawlen, &font_xofs, &font_yofs); - BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawstr_left_len)); + if (but->menu_key != '\0') { + char fixedbuf[128]; + const char *str; - str = strchr(fixedbuf, but->menu_key - 32); /* upper case */ - if (str == NULL) - str = strchr(fixedbuf, but->menu_key); + BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawlen)); - if (str) { - int ul_index = -1; - float ul_advance; + str = strchr(fixedbuf, but->menu_key - 32); /* upper case */ + if (str == NULL) + str = strchr(fixedbuf, but->menu_key); - ul_index = (int)(str - fixedbuf); + if (str) { + int ul_index = -1; + float ul_advance; - if (fstyle->kerning == 1) { - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } + ul_index = (int)(str - fixedbuf); + + if (fstyle->kerning == 1) { + BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + } - fixedbuf[ul_index] = '\0'; - ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index); + fixedbuf[ul_index] = '\0'; + ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index); - BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f); - BLF_draw(fstyle->uifont_id, "_", 2); + BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f); + BLF_draw(fstyle->uifont_id, "_", 2); - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + if (fstyle->kerning == 1) { + BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + } } } } @@ -2264,18 +2269,17 @@ void ui_hsvcircle_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect) { + /* TODO(merwin): reimplement as shader for pixel-perfect colors */ + const int tot = 64; const float radstep = 2.0f * (float)M_PI / (float)tot; const float centx = BLI_rcti_cent_x_fl(rect); const float centy = BLI_rcti_cent_y_fl(rect); float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f; - /* gouraud triangle fan */ ColorPicker *cpicker = but->custom_data; const float *hsv_ptr = cpicker->color_data; - float xpos, ypos, ang = 0.0f; float rgb[3], hsvo[3], hsv[3], col[3], colcent[3]; - int a; bool color_profile = ui_but_is_colorpicker_display_space(but); /* color */ @@ -2306,11 +2310,18 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2); - glBegin(GL_TRIANGLE_FAN); - glColor3fv(colcent); - glVertex2f(centx, centy); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + immBegin(GL_TRIANGLE_FAN, tot + 2); + immAttrib3fv(color, colcent); + immVertex2f(pos, centx, centy); - for (a = 0; a <= tot; a++, ang += radstep) { + float ang = 0.0f; + for (int a = 0; a <= tot; a++, ang += radstep) { float si = sinf(ang); float co = cosf(ang); @@ -2318,25 +2329,32 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * ui_color_picker_to_rgb_v(hsv, col); - glColor3fv(col); - glVertex2f(centx + co * radius, centy + si * radius); + immAttrib3fv(color, col); + immVertex2f(pos, centx + co * radius, centy + si * radius); } - glEnd(); - + immEnd(); + immUnbindProgram(); + /* fully rounded outline */ - glPushMatrix(); - glTranslatef(centx, centy, 0.0f); + format = immVertexFormat(); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - glColor3ubv((unsigned char *)wcol->outline); - glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1); + + immUniformColor3ubv((unsigned char *)wcol->outline); + imm_draw_lined_circle(pos, centx, centy, radius, tot); + glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - glPopMatrix(); + + immUnbindProgram(); /* cursor */ + float xpos, ypos; ui_hsvcircle_pos_from_vals(but, rect, hsvo, &xpos, &ypos); - ui_hsv_cursor(xpos, ypos); } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 539284030c2..73a9ea928cc 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -1272,7 +1272,6 @@ void UI_ThemeColor4(int colorid) cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); glColor4ubv(cp); - } /* set the color with offset for shades */ @@ -1280,7 +1279,7 @@ void UI_ThemeColorShade(int colorid, int offset) { int r, g, b; const unsigned char *cp; - + cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); r = offset + (int) cp[0]; CLAMP(r, 0, 255); @@ -1304,6 +1303,7 @@ void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) CLAMP(b, 0, 255); a = alphaoffset + (int) cp[3]; CLAMP(a, 0, 255); + glColor4ub(r, g, b, a); } @@ -1470,6 +1470,53 @@ void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]) col[2] = b; } +void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]) +{ + int r, g, b, a; + const unsigned char *cp; + + cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); + + r = coloffset + (int) cp[0]; + CLAMP(r, 0, 255); + g = coloffset + (int) cp[1]; + CLAMP(g, 0, 255); + b = coloffset + (int) cp[2]; + CLAMP(b, 0, 255); + a = alphaoffset + (int) cp[3]; + CLAMP(b, 0, 255); + + col[0] = ((float)r) / 255.0f; + col[1] = ((float)g) / 255.0f; + col[2] = ((float)b) / 255.0f; + col[3] = ((float)a) / 255.0f; +} + +void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int offset, float col[4]) +{ + int r, g, b, a; + const unsigned char *cp1, *cp2; + + cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1); + cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2); + + CLAMP(fac, 0.0f, 1.0f); + + r = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]); + CLAMP(r, 0, 255); + g = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]); + CLAMP(g, 0, 255); + b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]); + CLAMP(b, 0, 255); + a = offset + floorf((1.0f - fac) * cp1[3] + fac * cp2[3]); + CLAMP(a, 0, 255); + + col[0] = ((float)r) / 255.0f; + col[1] = ((float)g) / 255.0f; + col[2] = ((float)b) / 255.0f; + col[3] = ((float)a) / 255.0f; +} + /* get the color, in char pointer */ void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]) { @@ -1664,6 +1711,8 @@ void init_userdef_do_versions(void) U.tw_size = 25; /* percentage of window size */ U.tw_handlesize = 16; /* percentage of widget radius */ } + if (U.manipulator_scale == 0) + U.manipulator_scale = 75; if (U.pad_rot_angle == 0.0f) U.pad_rot_angle = 15.0f; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index c78d97ef86f..a358118aed1 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -49,6 +49,7 @@ #include "BKE_screen.h" #include "BKE_global.h" +#include "GPU_immediate.h" #include "WM_api.h" @@ -1100,9 +1101,6 @@ void UI_view2d_view_ortho(View2D *v2d) /* set matrix on all appropriate axes */ wmOrtho2(curmasked.xmin, curmasked.xmax, curmasked.ymin, curmasked.ymax); - - /* XXX is this necessary? */ - glLoadIdentity(); } /** @@ -1130,9 +1128,6 @@ void UI_view2d_view_orthoSpecial(ARegion *ar, View2D *v2d, const bool xaxis) wmOrtho2(curmasked.xmin - xofs, curmasked.xmax - xofs, -yofs, ar->winy - yofs); else wmOrtho2(-xofs, ar->winx - xofs, curmasked.ymin - yofs, curmasked.ymax - yofs); - - /* XXX is this necessary? */ - glLoadIdentity(); } @@ -1298,12 +1293,45 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) { float vec1[2], vec2[2]; int a, step; + int vertical_minor_step = (BLI_rcti_size_x(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC), + horizontal_major_step = (BLI_rcti_size_y(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC); + unsigned char grid_line_color[3]; /* check for grid first, as it may not exist */ if (grid == NULL) return; - glBegin(GL_LINES); + /* Count the needed vertices for the gridlines */ + unsigned vertex_count = 0; + if (flag & V2D_VERTICAL_LINES) { + /* vertical lines */ + vertex_count += 2 * vertical_minor_step; /* minor gridlines */ + vertex_count += 2 * (vertical_minor_step + 2); /* major gridlines */ + } + if (flag & V2D_HORIZONTAL_LINES) { + /* horizontal lines */ + vertex_count += 2 * (horizontal_major_step + 1); /* major gridlines */ + + /* fine lines */ + if (flag & V2D_HORIZONTAL_FINELINES) + vertex_count += 2 * (horizontal_major_step + 1); + } + /* axes */ + if (flag & V2D_HORIZONTAL_AXIS) + vertex_count += 2; + if (flag & V2D_VERTICAL_AXIS) + vertex_count += 2; + + /* If there is nothing to render, exit early */ + if (vertex_count == 0) + return; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, vertex_count); /* vertical lines */ if (flag & V2D_VERTICAL_LINES) { @@ -1313,24 +1341,31 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) vec2[1] = v2d->cur.ymax; /* minor gridlines */ - step = (BLI_rcti_size_x(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC); - UI_ThemeColor(TH_GRID); - - for (a = 0; a < step; a++) { - glVertex2fv(vec1); - glVertex2fv(vec2); - - vec2[0] = vec1[0] += grid->dx; + step = vertical_minor_step; + if (step != 0) { + UI_GetThemeColor3ubv(TH_GRID, grid_line_color); + + for (a = 0; a < step; a++) { + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); + + vec2[0] = vec1[0] += grid->dx; + } } /* major gridlines */ vec2[0] = vec1[0] -= 0.5f * grid->dx; - UI_ThemeColorShade(TH_GRID, 16); + + UI_GetThemeColorShade3ubv(TH_GRID, 16, grid_line_color); step++; for (a = 0; a <= step; a++) { - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); vec2[0] = vec1[0] -= grid->dx; } @@ -1343,12 +1378,15 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) vec1[0] = grid->startx; vec2[0] = v2d->cur.xmax; - step = (BLI_rcti_size_y(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC); - - UI_ThemeColor(TH_GRID); + step = horizontal_major_step; + + UI_GetThemeColor3ubv(TH_GRID, grid_line_color); + for (a = 0; a <= step; a++) { - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); vec2[1] = vec1[1] += grid->dy; } @@ -1358,10 +1396,12 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) step++; if (flag & V2D_HORIZONTAL_FINELINES) { - UI_ThemeColorShade(TH_GRID, 16); + UI_GetThemeColorShade3ubv(TH_GRID, 16, grid_line_color); for (a = 0; a < step; a++) { - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); vec2[1] = vec1[1] -= grid->dy; } @@ -1369,7 +1409,7 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) } /* Axes are drawn as darker lines */ - UI_ThemeColorShade(TH_GRID, -50); + UI_GetThemeColorShade3ubv(TH_GRID, -50, grid_line_color); /* horizontal axis */ if (flag & V2D_HORIZONTAL_AXIS) { @@ -1377,8 +1417,10 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) vec2[0] = v2d->cur.xmax; vec1[1] = vec2[1] = 0.0f; - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); } /* vertical axis */ @@ -1387,91 +1429,157 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag) vec2[1] = v2d->cur.ymax; vec1[0] = vec2[0] = 0.0f; - glVertex2fv(vec1); - glVertex2fv(vec2); + immSkipAttrib(color); + immVertex2fv(pos, vec1); + immAttrib3ubv(color, grid_line_color); + immVertex2fv(pos, vec2); } - glEnd(); + immEnd(); + immUnbindProgram(); } /* Draw a constant grid in given 2d-region */ void UI_view2d_constant_grid_draw(View2D *v2d) { - float start, step = 25.0f; - - UI_ThemeColorShade(TH_BACK, -10); + float start_x, start_y, step = 25.0f; + int count_x, count_y; - start = v2d->cur.xmin - (float)fmod(v2d->cur.xmin, step); + start_x = v2d->cur.xmin; + if (start_x < 0.0) + start_x += -(float)fmod(v2d->cur.xmin, step); + else + start_x += (step - (float)fmod(v2d->cur.xmin, step)); + + if (start_x > v2d->cur.xmax) + count_x = 0; + else + count_x = (v2d->cur.xmax - start_x) / step + 1; + + start_y = v2d->cur.ymin; + if (start_y < 0.0) + start_y += -(float)fmod(v2d->cur.ymin, step); + else + start_y += (step - (float)fabs(fmod(v2d->cur.ymin, step))); + + if (start_y > v2d->cur.ymax) + count_y = 0; + else + count_y = (v2d->cur.ymax - start_y) / step + 1; - glBegin(GL_LINES); - for (; start < v2d->cur.xmax; start += step) { - glVertex2f(start, v2d->cur.ymin); - glVertex2f(start, v2d->cur.ymax); - } + if (count_x > 0 || count_y > 0) { + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + float theme_color[3]; - start = v2d->cur.ymin - (float)fmod(v2d->cur.ymin, step); - for (; start < v2d->cur.ymax; start += step) { - glVertex2f(v2d->cur.xmin, start); - glVertex2f(v2d->cur.xmax, start); - } + UI_GetThemeColorShade3fv(TH_BACK, -10, theme_color); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, count_x * 2 + count_y * 2 + 4); + + immAttrib3fv(color, theme_color); + for (int i = 0; i < count_x ; start_x += step, i++) { + immVertex2f(pos, start_x, v2d->cur.ymin); + immVertex2f(pos, start_x, v2d->cur.ymax); + } + + for (int i = 0; i < count_y; start_y += step, i++) { + immVertex2f(pos, v2d->cur.xmin, start_y); + immVertex2f(pos, v2d->cur.xmax, start_y); + } - /* X and Y axis */ - UI_ThemeColorShade(TH_BACK, -18); - glVertex2f(0.0f, v2d->cur.ymin); - glVertex2f(0.0f, v2d->cur.ymax); - glVertex2f(v2d->cur.xmin, 0.0f); - glVertex2f(v2d->cur.xmax, 0.0f); + /* X and Y axis */ + UI_GetThemeColorShade3fv(TH_BACK, -18, theme_color); + + immAttrib3fv(color, theme_color); + immVertex2f(pos, 0.0f, v2d->cur.ymin); + immVertex2f(pos, 0.0f, v2d->cur.ymax); + immVertex2f(pos, v2d->cur.xmin, 0.0f); + immVertex2f(pos, v2d->cur.xmax, 0.0f); - glEnd(); + immEnd(); + immUnbindProgram(); + } } /* Draw a multi-level grid in given 2d-region */ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels) { + /* Exit if there is nothing to draw */ + if (totlevels == 0) + return; + int offset = -10; float lstep = step; - int level; + unsigned char grid_line_color[3]; + + /* Make an estimate of at least how many vertices will be needed */ + unsigned vertex_count = 4; + vertex_count += 2 * ((int)((v2d->cur.xmax - v2d->cur.xmin) / lstep) + 1); + vertex_count += 2 * ((int)((v2d->cur.ymax - v2d->cur.ymin) / lstep) + 1); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); glLineWidth(1.0f); - for (level = 0; level < totlevels; ++level) { - int i; - float start; - - UI_ThemeColorShade(colorid, offset); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBeginAtMost(GL_LINES, vertex_count); + + for (int level = 0; level < totlevels; ++level) { + UI_GetThemeColorShade3ubv(colorid, offset, grid_line_color); - i = (v2d->cur.xmin >= 0.0f ? -(int)(-v2d->cur.xmin / lstep) : (int)(v2d->cur.xmin / lstep)); - start = i * lstep; + int i = (int)(v2d->cur.xmin / lstep); + if (v2d->cur.xmin > 0.0f) + i++; + float start = i * lstep; - glBegin(GL_LINES); for (; start < v2d->cur.xmax; start += lstep, ++i) { if (i == 0 || (level < totlevels - 1 && i % level_size == 0)) continue; - glVertex2f(start, v2d->cur.ymin); - glVertex2f(start, v2d->cur.ymax); + + immSkipAttrib(color); + immVertex2f(pos, start, v2d->cur.ymin); + immAttrib3ubv(color, grid_line_color); + immVertex2f(pos, start, v2d->cur.ymax); } - i = (v2d->cur.ymin >= 0.0f ? -(int)(-v2d->cur.ymin / lstep) : (int)(v2d->cur.ymin / lstep)); + i = (int)(v2d->cur.ymin / lstep); + if (v2d->cur.ymin > 0.0f) + i++; start = i * lstep; for (; start < v2d->cur.ymax; start += lstep, ++i) { if (i == 0 || (level < totlevels - 1 && i % level_size == 0)) continue; - glVertex2f(v2d->cur.xmin, start); - glVertex2f(v2d->cur.xmax, start); + + immSkipAttrib(color); + immVertex2f(pos, v2d->cur.xmin, start); + immAttrib3ubv(color, grid_line_color); + immVertex2f(pos, v2d->cur.xmax, start); } - /* X and Y axis */ - UI_ThemeColorShade(colorid, offset - 8); - glVertex2f(0.0f, v2d->cur.ymin); - glVertex2f(0.0f, v2d->cur.ymax); - glVertex2f(v2d->cur.xmin, 0.0f); - glVertex2f(v2d->cur.xmax, 0.0f); - - glEnd(); - lstep *= level_size; offset -= 6; } + + /* X and Y axis */ + UI_GetThemeColorShade3ubv(colorid, -18 + ((totlevels - 1) * -6) , grid_line_color); + + immSkipAttrib(color); + immVertex2f(pos, 0.0f, v2d->cur.ymin); + immAttrib3ubv(color, grid_line_color); + immVertex2f(pos, 0.0f, v2d->cur.ymax); + + immSkipAttrib(color); + immVertex2f(pos, v2d->cur.xmin, 0.0f); + immAttrib3ubv(color, grid_line_color); + immVertex2f(pos, v2d->cur.xmax, 0.0f); + + immEnd(); + immUnbindProgram(); } /* the price we pay for not exposting structs :( */ @@ -1693,6 +1801,10 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v Scene *scene = CTX_data_scene(C); rcti vert, hor; int scroll = view2d_scroll_mapped(v2d->scroll); + unsigned char scrollers_back_color[4]; + + /* Color for scrollbar backs */ + UI_GetThemeColor4ubv(TH_BACK, scrollers_back_color); /* make copies of rects for less typing */ vert = vs->vert; @@ -1704,7 +1816,6 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v uiWidgetColors wcol = btheme->tui.wcol_scroll; rcti slider; int state; - unsigned char col[4]; slider.xmin = vs->hor_min; slider.xmax = vs->hor_max; @@ -1728,10 +1839,16 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v } /* clean rect behind slider, but not with transparent background */ - UI_GetThemeColor4ubv(TH_BACK, col); - if (col[3] == 255) { - glColor3ub(col[0], col[1], col[2]); - glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax); + if (scrollers_back_color[3] == 255) { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3ubv(scrollers_back_color); + immRecti(pos, v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax); + + immUnbindProgram(); } UI_draw_widget_scroll(&wcol, &hor, &slider, state); @@ -1805,7 +1922,6 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v uiWidgetColors wcol = btheme->tui.wcol_scroll; rcti slider; int state; - unsigned char col[4]; slider.xmin = vert.xmin; slider.xmax = vert.xmax; @@ -1829,10 +1945,16 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v } /* clean rect behind slider, but not with transparent background */ - UI_GetThemeColor4ubv(TH_BACK, col); - if (col[3] == 255) { - glColor3ub(col[0], col[1], col[2]); - glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax); + if (scrollers_back_color[3] == 255) { + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3ubv(scrollers_back_color); + immRecti(pos, v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax); + + immUnbindProgram(); } UI_draw_widget_scroll(&wcol, &vert, &slider, state); @@ -2424,11 +2546,6 @@ void UI_view2d_text_cache_draw(ARegion *ar) BLI_memarena_free(g_v2d_strings_arena); g_v2d_strings_arena = NULL; } - - // glMatrixMode(GL_PROJECTION); - // glPopMatrix(); - // glMatrixMode(GL_MODELVIEW); - // glPopMatrix(); } diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 87c08dc6583..c48e142f233 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -94,6 +94,7 @@ #include "ED_datafiles.h" #include "ED_render.h" +#include "ED_screen.h" #ifndef NDEBUG /* Used for database init assert(). */ @@ -1022,6 +1023,12 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat *do_update = true; } + else if (idtype == ID_SCR) { + bScreen *screen = (bScreen *)id; + + ED_screen_preview_render(screen, sp->sizex, sp->sizey, sp->pr_rect); + *do_update = true; + } else { /* re-use shader job */ shader_preview_startjob(customdata, stop, do_update); diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index ed86ffa5e16..43e044b613a 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -42,6 +42,7 @@ set(SRC area.c glutil.c screen_context.c + screen_draw.c screen_edit.c screen_ops.c screendump.c diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index e6bb604d387..fe734954bba 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -57,6 +57,9 @@ #include "ED_screen_types.h" #include "ED_space_api.h" +#include "GPU_immediate.h" +#include "GPU_draw.h" + #include "BIF_gl.h" #include "BIF_glutil.h" #include "BLF_api.h" @@ -89,21 +92,30 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINE_STRIP, 5); + /* right */ - glColor4ub(0, 0, 0, 30); - sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax); + immAttrib4ub(color, 0, 0, 0, 30); + immVertex2f(pos, rect.xmax, rect.ymax); + immVertex2f(pos, rect.xmax, rect.ymin); /* bottom */ - glColor4ub(0, 0, 0, 30); - sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin); + immVertex2f(pos, rect.xmin, rect.ymin); - /* top */ - glColor4ub(255, 255, 255, 30); - sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax); - /* left */ - glColor4ub(255, 255, 255, 30); - sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax); + immAttrib4ub(color, 255, 255, 255, 30); + immVertex2f(pos, rect.xmin, rect.ymax); + + /* top */ + immVertex2f(pos, rect.xmax, rect.ymax); + + immEnd(); + immUnbindProgram(); glDisable(GL_BLEND); } @@ -206,15 +218,27 @@ static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, f if (G.debug_value == 1) { rcti click_rect; float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC; - char alpha_debug = 255 * alpha; + unsigned char alpha_debug = 255 * alpha; BLI_rcti_init(&click_rect, x, x + icon_size, y, y + icon_size); - glColor4ub(255, 0, 0, alpha_debug); - fdrawbox(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); - glColor4ub(0, 255, 255, alpha_debug); - fdrawline(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); - fdrawline(click_rect.xmin, click_rect.ymax, click_rect.xmax, click_rect.ymin); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immAttrib4ub(color, 255, 0, 0, alpha_debug); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + imm_draw_line_box(pos, click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); + + immAttrib4ub(color, 0, 255, 255, alpha_debug); + immBegin(GL_LINES, 4); + immVertex2f(pos, click_rect.xmin, click_rect.ymin); + immVertex2f(pos, click_rect.xmax, click_rect.ymax); + immVertex2f(pos, click_rect.xmin, click_rect.ymax); + immVertex2f(pos, click_rect.xmax, click_rect.ymin); + immEnd(); + + immUnbindProgram(); } } @@ -229,69 +253,96 @@ static void area_draw_azone(short x1, short y1, short x2, short y2) dx = copysign(ceilf(0.3f * abs(dx)), dx); dy = copysign(ceilf(0.3f * abs(dy)), dy); - glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); + + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned col = add_attrib(format, "color", GL_UNSIGNED_BYTE, 4, NORMALIZE_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, 12); + + immAttrib4ub(col, 255, 255, 255, 180); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y1); + + immAttrib4ub(col, 255, 255, 255, 130); + immVertex2f(pos, x1, y2 - dy); + immVertex2f(pos, x2 - dx, y1); + + immAttrib4ub(col, 255, 255, 255, 80); + immVertex2f(pos, x1, y2 - 2 * dy); + immVertex2f(pos, x2 - 2 * dx, y1); - glColor4ub(255, 255, 255, 180); - fdrawline(x1, y2, x2, y1); - glColor4ub(255, 255, 255, 130); - fdrawline(x1, y2 - dy, x2 - dx, y1); - glColor4ub(255, 255, 255, 80); - fdrawline(x1, y2 - 2 * dy, x2 - 2 * dx, y1); - - glColor4ub(0, 0, 0, 210); - fdrawline(x1, y2 + 1, x2 + 1, y1); - glColor4ub(0, 0, 0, 180); - fdrawline(x1, y2 - dy + 1, x2 - dx + 1, y1); - glColor4ub(0, 0, 0, 150); - fdrawline(x1, y2 - 2 * dy + 1, x2 - 2 * dx + 1, y1); + immAttrib4ub(col, 0, 0, 0, 210); + immVertex2f(pos, x1, y2 + 1); + immVertex2f(pos, x2 + 1, y1); + + immAttrib4ub(col, 0, 0, 0, 180); + immVertex2f(pos, x1, y2 - dy + 1); + immVertex2f(pos, x2 - dx + 1, y1); + + immAttrib4ub(col, 0, 0, 0, 150); + immVertex2f(pos, x1, y2 - 2 * dy + 1); + immVertex2f(pos, x2 - 2 * dx + 1, y1); + + immEnd(); + immUnbindProgram(); glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); } static void region_draw_azone_icon(AZone *az) { - GLUquadricObj *qobj = NULL; - short midx = az->x1 + (az->x2 - az->x1) / 2; - short midy = az->y1 + (az->y2 - az->y1) / 2; - - qobj = gluNewQuadric(); - - glPushMatrix(); - glTranslatef(midx, midy, 0.0); - - /* outlined circle */ - glEnable(GL_LINE_SMOOTH); + float midx = az->x1 + (az->x2 - az->x1) * 0.5f; + float midy = az->y1 + (az->y2 - az->y1) * 0.5f; - glColor4f(1.f, 1.f, 1.f, 0.8f); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); - gluQuadricDrawStyle(qobj, GLU_FILL); - gluDisk(qobj, 0.0, 4.25f, 16, 1); + /* outlined circle */ + GPU_enable_program_point_size(); /* TODO: make a fixed-size shader to avoid this */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + immUniform4f("color", 1.0f, 1.0f, 1.0f, 0.8f); + immUniform4f("outlineColor", 0.2f, 0.2f, 0.2f, 0.9f); + immUniform1f("outlineWidth", 1.0f); + immUniform1f("size", 9.5f); + immBegin(GL_POINTS, 1); + immVertex2f(pos, midx, midy); + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); - glColor4f(0.2f, 0.2f, 0.2f, 0.9f); - - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0.0, 4.25f, 16, 1); - - glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); - gluDeleteQuadric(qobj); - /* + */ - sdrawline(midx, midy - 2, midx, midy + 3); - sdrawline(midx - 2, midy, midx + 3, midy); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniform4f("color", 0.2f, 0.2f, 0.2f, 0.9f); + immBegin(GL_LINES, 4); + immVertex2f(pos, midx, midy - 2); + immVertex2f(pos, midx, midy + 3); + immVertex2f(pos, midx - 2, midy); + immVertex2f(pos, midx + 3, midy); + immEnd(); + immUnbindProgram(); } static void draw_azone_plus(float x1, float y1, float x2, float y2) { float width = 0.1f * U.widget_unit; float pad = 0.2f * U.widget_unit; - - glRectf((x1 + x2 - width) * 0.5f, y1 + pad, (x1 + x2 + width) * 0.5f, y2 - pad); - glRectf(x1 + pad, (y1 + y2 - width) * 0.5f, (x1 + x2 - width) * 0.5f, (y1 + y2 + width) * 0.5f); - glRectf((x1 + x2 + width) * 0.5f, (y1 + y2 - width) * 0.5f, x2 - pad, (y1 + y2 + width) * 0.5f); + + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + glEnable(GL_BLEND); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.8f, 0.8f, 0.8f, 0.4f); + + immRectf(pos, (x1 + x2 - width) * 0.5f, y1 + pad, (x1 + x2 + width) * 0.5f, y2 - pad); + immRectf(pos, x1 + pad, (y1 + y2 - width) * 0.5f, (x1 + x2 - width) * 0.5f, (y1 + y2 + width) * 0.5f); + immRectf(pos, (x1 + x2 + width) * 0.5f, (y1 + y2 - width) * 0.5f, x2 - pad, (y1 + y2 + width) * 0.5f); + + immUnbindProgram(); + glDisable(GL_BLEND); } static void region_draw_azone_tab_plus(AZone *az) @@ -314,15 +365,10 @@ static void region_draw_azone_tab_plus(AZone *az) break; } - glColor4f(0.05f, 0.05f, 0.05f, 0.4f); - UI_draw_roundbox((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f); + float color[4] = {0.05f, 0.05f, 0.05f, 0.4f}; + UI_draw_roundbox((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, color); - glEnable(GL_BLEND); - - glColor4f(0.8f, 0.8f, 0.8f, 0.4f); draw_azone_plus((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2); - - glDisable(GL_BLEND); } static void region_draw_azone_tab(AZone *az) @@ -528,9 +574,13 @@ void ED_region_do_draw(bContext *C, ARegion *ar) /* for debugging unneeded area redraws and partial redraw */ #if 0 glEnable(GL_BLEND); - glColor4f(drand48(), drand48(), drand48(), 0.1f); - glRectf(ar->drawrct.xmin - ar->winrct.xmin, ar->drawrct.ymin - ar->winrct.ymin, + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(drand48(), drand48(), drand48(), 0.1f); + immRectf(pos, ar->drawrct.xmin - ar->winrct.xmin, ar->drawrct.ymin - ar->winrct.ymin, ar->drawrct.xmax - ar->winrct.xmin, ar->drawrct.ymax - ar->winrct.ymin); + immUnbindProgram(); glDisable(GL_BLEND); #endif @@ -1968,8 +2018,12 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c /* view should be in pixelspace */ UI_view2d_view_restore(C); glEnable(GL_BLEND); - UI_ThemeColor4((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK); - glRecti(0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK); + immRecti(pos, 0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1); + immUnbindProgram(); glDisable(GL_BLEND); } else { @@ -2098,8 +2152,12 @@ void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], con glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4fv(fill_color); - glRecti(rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(fill_color); + immRecti(pos, rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1); + immUnbindProgram(); glDisable(GL_BLEND); /* text */ @@ -2298,12 +2356,15 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, box_y = metadata_box_height_get(ibuf, blf_mono_font, true); if (box_y) { - UI_ThemeColor(TH_METADATA_BG); - /* set up rect */ BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymax, frame->ymax + box_y); /* draw top box */ - glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_METADATA_BG); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); BLF_enable(blf_mono_font, BLF_CLIPPING); @@ -2320,12 +2381,15 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, box_y = metadata_box_height_get(ibuf, blf_mono_font, false); if (box_y) { - UI_ThemeColor(TH_METADATA_BG); - /* set up box rect */ BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymin - box_y, frame->ymin); /* draw top box */ - glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_METADATA_BG); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); BLF_enable(blf_mono_font, BLF_CLIPPING); @@ -2346,11 +2410,16 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy) int x1, y1, x2, y2; /* the image is located inside (0, 0), (1, 1) as set by view2d */ - UI_ThemeColorShade(TH_BACK, 20); - UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x1, &y1); UI_view2d_view_to_region(&ar->v2d, 1.0f, 1.0f, &x2, &y2); - glRectf(x1, y1, x2, y2); + + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, 20); + immRectf(pos, x1, y1, x2, y2); + immUnbindProgram(); /* gridsize adapted to zoom level */ gridsize = 0.5f * (zoomx + zoomy); @@ -2370,33 +2439,52 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy) } } - /* the fine resolution level */ blendfac = 0.25f * gridsize - floorf(0.25f * gridsize); CLAMP(blendfac, 0.0f, 1.0f); - UI_ThemeColorShade(TH_BACK, (int)(20.0f * (1.0f - blendfac))); - fac = 0.0f; - glBegin(GL_LINES); - while (fac < 1.0f) { - glVertex2f(x1, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x2, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y1); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y2); - fac += gridstep; - } + int count_fine = 1.0f / gridstep; + int count_large = 1.0f / (4.0f * gridstep); - /* the large resolution level */ - UI_ThemeColor(TH_BACK); + if (count_fine > 0) { + VertexFormat_clear(format); + pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, 4 * count_fine + 4 * count_large); + + float theme_color[3]; + UI_GetThemeColorShade3fv(TH_BACK, (int)(20.0f * (1.0f - blendfac)), theme_color); + immAttrib3fv(color, theme_color); + fac = 0.0f; + + /* the fine resolution level */ + for (int i = 0; i < count_fine; i++) { + immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2); + fac += gridstep; + } - fac = 0.0f; - while (fac < 1.0f) { - glVertex2f(x1, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x2, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y1); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y2); - fac += 4.0f * gridstep; + if (count_large > 0) { + UI_GetThemeColor3fv(TH_BACK, theme_color); + immAttrib3fv(color, theme_color); + fac = 0.0f; + + /* the large resolution level */ + for (int i = 0; i < count_large; i++) { + immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2); + fac += 4.0f * gridstep; + } + } + + immEnd(); + immUnbindProgram(); } - glEnd(); } /* If the area has overlapping regions, it returns visible rect for Region *ar */ @@ -2433,8 +2521,13 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect) void ED_region_cache_draw_background(const ARegion *ar) { - glColor4ub(128, 128, 255, 64); - glRecti(0, 0, ar->winx, 8 * UI_DPI_FAC); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ub(128, 128, 255, 64); + immRecti(pos, 0, 0, ar->winx, 8 * UI_DPI_FAC); + immUnbindProgram(); } void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y) diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 93bac3f6660..47593252ecb 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -49,47 +49,12 @@ #include "IMB_imbuf_types.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "UI_interface.h" -#ifndef GL_CLAMP_TO_EDGE -#define GL_CLAMP_TO_EDGE 0x812F -#endif - -/* UNUSED */ -#if 0 -void fdrawbezier(float vec[4][3]) -{ - float dist; - float curve_res = 24, spline_step = 0.0f; - - dist = 0.5f * fabsf(vec[0][0] - vec[3][0]); - - /* check direction later, for top sockets */ - vec[1][0] = vec[0][0] + dist; - vec[1][1] = vec[0][1]; - - vec[2][0] = vec[3][0] - dist; - vec[2][1] = vec[3][1]; - /* we can reuse the dist variable here to increment the GL curve eval amount */ - dist = 1.0f / curve_res; - - cpack(0x0); - glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]); - glBegin(GL_LINE_STRIP); - while (spline_step < 1.000001f) { -#if 0 - if (do_shaded) - UI_ThemeColorBlend(th_col1, th_col2, spline_step); -#endif - glEvalCoord1f(spline_step); - spline_step += dist; - } - glEnd(); -} -#endif -void fdrawline(float x1, float y1, float x2, float y2) +void fdrawline(float x1, float y1, float x2, float y2) /* DEPRECATED */ { glBegin(GL_LINES); glVertex2f(x1, y1); @@ -99,6 +64,7 @@ void fdrawline(float x1, float y1, float x2, float y2) void fdrawbox(float x1, float y1, float x2, float y2) { + /* DEPRECATED: use imm_draw_line_box instead */ glBegin(GL_LINE_LOOP); glVertex2f(x1, y1); @@ -109,7 +75,7 @@ void fdrawbox(float x1, float y1, float x2, float y2) glEnd(); } -void fdrawcheckerboard(float x1, float y1, float x2, float y2) +void fdrawcheckerboard(float x1, float y1, float x2, float y2) /* DEPRECATED */ { unsigned char col1[4] = {40, 40, 40}, col2[4] = {50, 50, 50}; @@ -123,7 +89,7 @@ void fdrawcheckerboard(float x1, float y1, float x2, float y2) GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } -void sdrawline(int x1, int y1, int x2, int y2) +void sdrawline(int x1, int y1, int x2, int y2) /* DEPRECATED */ { glBegin(GL_LINES); glVertex2i(x1, y1); @@ -131,40 +97,9 @@ void sdrawline(int x1, int y1, int x2, int y2) glEnd(); } -/* UNUSED */ -#if 0 -/* - * x1,y2 - * | \ - * | \ - * | \ - * x1,y1-- x2,y1 - */ - -static void sdrawtripoints(int x1, int y1, int x2, int y2) -{ - glVertex2i(x1, y1); - glVertex2i(x1, y2); - glVertex2i(x2, y1); -} - -void sdrawtri(int x1, int y1, int x2, int y2) -{ - glBegin(GL_LINE_STRIP); - sdrawtripoints(x1, y1, x2, y2); - glEnd(); -} - -void sdrawtrifill(int x1, int y1, int x2, int y2) -{ - glBegin(GL_TRIANGLES); - sdrawtripoints(x1, y1, x2, y2); - glEnd(); -} -#endif - void sdrawbox(int x1, int y1, int x2, int y2) { + /* DEPRECATED: use imm_draw_line_box instead */ glBegin(GL_LINE_LOOP); glVertex2i(x1, y1); @@ -204,95 +139,10 @@ void set_inverted_drawing(int enable) GL_TOGGLE(GL_DITHER, !enable); } -/* UNUSED */ -#if 0 -void sdrawXORline(int x0, int y0, int x1, int y1) -{ - if (x0 == x1 && y0 == y1) return; - - set_inverted_drawing(1); - - glBegin(GL_LINES); - glVertex2i(x0, y0); - glVertex2i(x1, y1); - glEnd(); - - set_inverted_drawing(0); -} - -void sdrawXORline4(int nr, int x0, int y0, int x1, int y1) -{ - static int old[4][2][2]; - static char flags[4] = {0, 0, 0, 0}; - - /* with builtin memory, max 4 lines */ - - set_inverted_drawing(1); - - glBegin(GL_LINES); - if (nr == -1) { /* flush */ - for (nr = 0; nr < 4; nr++) { - if (flags[nr]) { - glVertex2iv(old[nr][0]); - glVertex2iv(old[nr][1]); - flags[nr] = 0; - } - } - } - else { - if (nr >= 0 && nr < 4) { - if (flags[nr]) { - glVertex2iv(old[nr][0]); - glVertex2iv(old[nr][1]); - } - - old[nr][0][0] = x0; - old[nr][0][1] = y0; - old[nr][1][0] = x1; - old[nr][1][1] = y1; - - flags[nr] = 1; - } - - glVertex2i(x0, y0); - glVertex2i(x1, y1); - } - glEnd(); - - set_inverted_drawing(0); -} - -void fdrawXORellipse(float xofs, float yofs, float hw, float hh) -{ - if (hw == 0) return; - - set_inverted_drawing(1); - - glPushMatrix(); - glTranslatef(xofs, yofs, 0.0f); - glScalef(1.0f, hh / hw, 1.0f); - glutil_draw_lined_arc(0.0, M_PI * 2.0, hw, 20); - glPopMatrix(); - - set_inverted_drawing(0); -} - -#endif - -void fdrawXORcirc(float xofs, float yofs, float rad) -{ - set_inverted_drawing(1); - - glPushMatrix(); - glTranslatef(xofs, yofs, 0.0); - glutil_draw_lined_arc(0.0, M_PI * 2.0, rad, 20); - glPopMatrix(); - - set_inverted_drawing(0); -} void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments) { + /* DEPRECATED */ int i; glBegin(GL_TRIANGLE_FAN); @@ -308,6 +158,7 @@ void glutil_draw_filled_arc(float start, float angle, float radius, int nsegment void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments) { + /* DEPRECATED */ int i; glBegin(GL_LINE_STRIP); @@ -320,6 +171,66 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments glEnd(); } +static void imm_draw_circle(PrimitiveType prim_type, unsigned pos, float x, float y, float rad, int nsegments) +{ + immBegin(prim_type, nsegments); + for (int i = 0; i < nsegments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)nsegments); + immVertex2f(pos, x + rad * cosf(angle), + y + rad * sinf(angle)); + } + immEnd(); +} + +void imm_draw_lined_circle(unsigned pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle(PRIM_LINE_LOOP, pos, x, y, rad, nsegments); +} + +void imm_draw_filled_circle(unsigned pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle(PRIM_TRIANGLE_FAN, pos, x, y, rad, nsegments); +} + +void imm_draw_lined_circle_3D(unsigned pos, float x, float y, float rad, int nsegments) +{ + immBegin(PRIM_LINE_LOOP, nsegments); + for (int i = 0; i < nsegments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)nsegments); + immVertex3f(pos, x + rad * cosf(angle), + y + rad * sinf(angle), 0.0f); + } + immEnd(); +} + +void imm_draw_line_box(unsigned pos, float x1, float y1, float x2, float y2) +{ + immBegin(PRIM_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y1); + immEnd(); +} + +void imm_draw_line_box_3D(unsigned pos, float x1, float y1, float x2, float y2) +{ + /* use this version when VertexFormat has a vec3 position */ + immBegin(PRIM_LINE_LOOP, 4); + immVertex3f(pos, x1, y1, 0.0f); + immVertex3f(pos, x1, y2, 0.0f); + immVertex3f(pos, x2, y2, 0.0f); + immVertex3f(pos, x2, y1, 0.0f); + immEnd(); +} + +void imm_cpack(unsigned int x) +{ + immUniformColor3ub(((x)& 0xFF), + (((x) >> 8) & 0xFF), + (((x) >> 16) & 0xFF)); +} + float glaGetOneFloat(int param) { GLfloat v; @@ -401,12 +312,6 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter); -#if defined(__APPLE__) && 0 - /* [merwin] disable this workaround and see if anyone is affected. If not scrap it! Also at end of this function */ - /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */ - glPixelZoom(1.0f, 1.0f); -#endif - /* setup seamless 2=on, 0=off */ seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0; @@ -514,11 +419,6 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, glBindTexture(GL_TEXTURE_2D, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - -#if defined(__APPLE__) && 0 - /* workaround for os x 10.5/10.6 driver bug (above) */ - glPixelZoom(xzoom, yzoom); -#endif } void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, @@ -673,6 +573,8 @@ void glaDefine2DArea(rcti *screen_rect) glLoadIdentity(); } +/* TODO(merwin): put the following 2D code to use, or build new 2D code inspired & informd by it */ + #if 0 /* UNUSED */ struct gla2DDrawInfo { @@ -785,7 +687,8 @@ void glaEnd2DDraw(gla2DDrawInfo *di) MEM_freeN(di); } -#endif + +#endif /* UNUSED */ /* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */ @@ -999,6 +902,7 @@ void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int void cpack(unsigned int x) { + /* DEPRECATED: use imm_cpack */ glColor3ub(( (x) & 0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF)); diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c new file mode 100644 index 00000000000..f73bed16330 --- /dev/null +++ b/source/blender/editors/screen/screen_draw.c @@ -0,0 +1,435 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/screen/screen_draw.c + * \ingroup edscr + */ + +#include "ED_screen.h" + +#include "GPU_framebuffer.h" +#include "GPU_immediate.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "screen_intern.h" + + +/** + * Draw vertical shape visualizing future joining (left as well right direction of future joining). + */ +static void draw_horizontal_join_shape(ScrArea *sa, char dir) +{ + vec2f points[10]; + short i; + float w, h; + float width = sa->v3->vec.x - sa->v1->vec.x; + float height = sa->v3->vec.y - sa->v1->vec.y; + + if (height < width) { + h = height / 8; + w = height / 4; + } + else { + h = width / 8; + w = width / 4; + } + + points[0].x = sa->v1->vec.x; + points[0].y = sa->v1->vec.y + height / 2; + + points[1].x = sa->v1->vec.x; + points[1].y = sa->v1->vec.y; + + points[2].x = sa->v4->vec.x - w; + points[2].y = sa->v4->vec.y; + + points[3].x = sa->v4->vec.x - w; + points[3].y = sa->v4->vec.y + height / 2 - 2 * h; + + points[4].x = sa->v4->vec.x - 2 * w; + points[4].y = sa->v4->vec.y + height / 2; + + points[5].x = sa->v4->vec.x - w; + points[5].y = sa->v4->vec.y + height / 2 + 2 * h; + + points[6].x = sa->v3->vec.x - w; + points[6].y = sa->v3->vec.y; + + points[7].x = sa->v2->vec.x; + points[7].y = sa->v2->vec.y; + + points[8].x = sa->v4->vec.x; + points[8].y = sa->v4->vec.y + height / 2 - h; + + points[9].x = sa->v4->vec.x; + points[9].y = sa->v4->vec.y + height / 2 + h; + + if (dir == 'l') { + /* when direction is left, then we flip direction of arrow */ + float cx = sa->v1->vec.x + width; + for (i = 0; i < 10; i++) { + points[i].x -= cx; + points[i].x = -points[i].x; + points[i].x += sa->v1->vec.x; + } + } + + glBegin(GL_POLYGON); + for (i = 0; i < 5; i++) + glVertex2f(points[i].x, points[i].y); + glEnd(); + glBegin(GL_POLYGON); + for (i = 4; i < 8; i++) + glVertex2f(points[i].x, points[i].y); + glVertex2f(points[0].x, points[0].y); + glEnd(); + + glRectf(points[2].x, points[2].y, points[8].x, points[8].y); + glRectf(points[6].x, points[6].y, points[9].x, points[9].y); +} + +/** + * Draw vertical shape visualizing future joining (up/down direction). + */ +static void draw_vertical_join_shape(ScrArea *sa, char dir) +{ + vec2f points[10]; + short i; + float w, h; + float width = sa->v3->vec.x - sa->v1->vec.x; + float height = sa->v3->vec.y - sa->v1->vec.y; + + if (height < width) { + h = height / 4; + w = height / 8; + } + else { + h = width / 4; + w = width / 8; + } + + points[0].x = sa->v1->vec.x + width / 2; + points[0].y = sa->v3->vec.y; + + points[1].x = sa->v2->vec.x; + points[1].y = sa->v2->vec.y; + + points[2].x = sa->v1->vec.x; + points[2].y = sa->v1->vec.y + h; + + points[3].x = sa->v1->vec.x + width / 2 - 2 * w; + points[3].y = sa->v1->vec.y + h; + + points[4].x = sa->v1->vec.x + width / 2; + points[4].y = sa->v1->vec.y + 2 * h; + + points[5].x = sa->v1->vec.x + width / 2 + 2 * w; + points[5].y = sa->v1->vec.y + h; + + points[6].x = sa->v4->vec.x; + points[6].y = sa->v4->vec.y + h; + + points[7].x = sa->v3->vec.x; + points[7].y = sa->v3->vec.y; + + points[8].x = sa->v1->vec.x + width / 2 - w; + points[8].y = sa->v1->vec.y; + + points[9].x = sa->v1->vec.x + width / 2 + w; + points[9].y = sa->v1->vec.y; + + if (dir == 'u') { + /* when direction is up, then we flip direction of arrow */ + float cy = sa->v1->vec.y + height; + for (i = 0; i < 10; i++) { + points[i].y -= cy; + points[i].y = -points[i].y; + points[i].y += sa->v1->vec.y; + } + } + + glBegin(GL_POLYGON); + for (i = 0; i < 5; i++) + glVertex2f(points[i].x, points[i].y); + glEnd(); + glBegin(GL_POLYGON); + for (i = 4; i < 8; i++) + glVertex2f(points[i].x, points[i].y); + glVertex2f(points[0].x, points[0].y); + glEnd(); + + glRectf(points[2].x, points[2].y, points[8].x, points[8].y); + glRectf(points[6].x, points[6].y, points[9].x, points[9].y); +} + +/** + * Draw join shape due to direction of joining. + */ +static void draw_join_shape(ScrArea *sa, char dir) +{ + if (dir == 'u' || dir == 'd') + draw_vertical_join_shape(sa, dir); + else + draw_horizontal_join_shape(sa, dir); +} + +/** + * Draw screen area darker with arrow (visualization of future joining). + */ +static void scrarea_draw_shape_dark(ScrArea *sa, char dir) +{ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4ub(0, 0, 0, 50); + draw_join_shape(sa, dir); +} + +/** + * Draw screen area ligher with arrow shape ("eraser" of previous dark shape). + */ +static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir)) +{ + glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); + /* value 181 was hardly computed: 181~105 */ + glColor4ub(255, 255, 255, 50); + /* draw_join_shape(sa, dir); */ + glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y); +} + +static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2) +{ + /* right border area */ + if (x2 < sizex - 1) { + glVertex2s(x2, y1); + glVertex2s(x2, y2); + } + + /* left border area */ + if (x1 > 0) { /* otherwise it draws the emboss of window over */ + glVertex2s(x1, y1); + glVertex2s(x1, y2); + } + + /* top border area */ + if (y2 < sizey - 1) { + glVertex2s(x1, y2); + glVertex2s(x2, y2); + } + + /* bottom border area */ + if (y1 > 0) { + glVertex2s(x1, y1); + glVertex2s(x2, y1); + } +} + +/** + * \brief Screen edges drawing. + */ +static void drawscredge_area(ScrArea *sa, int sizex, int sizey) +{ + short x1 = sa->v1->vec.x; + short y1 = sa->v1->vec.y; + short x2 = sa->v3->vec.x; + short y2 = sa->v3->vec.y; + + drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2); +} + +/** + * Only for edge lines between areas, and the blended join arrows. + */ +void ED_screen_draw(wmWindow *win) +{ + const int winsize_x = WM_window_pixels_x(win); + const int winsize_y = WM_window_pixels_y(win); + + ScrArea *sa; + ScrArea *sa1 = NULL; + ScrArea *sa2 = NULL; + ScrArea *sa3 = NULL; + + wmSubWindowSet(win, win->screen->mainwin); + + /* Note: first loop only draws if U.pixelsize > 1, skip otherwise */ + if (U.pixelsize > 1.0f) { + /* FIXME: doesn't our glLineWidth already scale by U.pixelsize? */ + glLineWidth((2.0f * U.pixelsize) - 1); + glColor3ub(0x50, 0x50, 0x50); + glBegin(GL_LINES); + for (sa = win->screen->areabase.first; sa; sa = sa->next) + drawscredge_area(sa, winsize_x, winsize_y); + glEnd(); + } + + glLineWidth(1); + glColor3ub(0, 0, 0); + glBegin(GL_LINES); + for (sa = win->screen->areabase.first; sa; sa = sa->next) { + drawscredge_area(sa, winsize_x, winsize_y); + + /* gather area split/join info */ + if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa; + if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa; + if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa; + } + glEnd(); + + /* blended join arrow */ + if (sa1 && sa2) { + int dir = area_getorientation(sa1, sa2); + int dira = -1; + if (dir != -1) { + switch (dir) { + case 0: /* W */ + dir = 'r'; + dira = 'l'; + break; + case 1: /* N */ + dir = 'd'; + dira = 'u'; + break; + case 2: /* E */ + dir = 'l'; + dira = 'r'; + break; + case 3: /* S */ + dir = 'u'; + dira = 'd'; + break; + } + } + glEnable(GL_BLEND); + scrarea_draw_shape_dark(sa2, dir); + scrarea_draw_shape_light(sa1, dira); + glDisable(GL_BLEND); + } + + /* splitpoint */ + if (sa3) { + glEnable(GL_BLEND); + glBegin(GL_LINES); + glColor4ub(255, 255, 255, 100); + + if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) { + glVertex2s(sa3->totrct.xmin, win->eventstate->y); + glVertex2s(sa3->totrct.xmax, win->eventstate->y); + glColor4ub(0, 0, 0, 100); + glVertex2s(sa3->totrct.xmin, win->eventstate->y + 1); + glVertex2s(sa3->totrct.xmax, win->eventstate->y + 1); + } + else { + glVertex2s(win->eventstate->x, sa3->totrct.ymin); + glVertex2s(win->eventstate->x, sa3->totrct.ymax); + glColor4ub(0, 0, 0, 100); + glVertex2s(win->eventstate->x + 1, sa3->totrct.ymin); + glVertex2s(win->eventstate->x + 1, sa3->totrct.ymax); + } + glEnd(); + glDisable(GL_BLEND); + } + + win->screen->do_draw = false; +} + + +/* -------------------------------------------------------------------- */ +/* Screen Thumbnail Preview */ + +/** + * Calculates a scale factor to squash the preview for \a screen into a rectangle of given size and aspect. + */ +static void screen_preview_scale_get( + const bScreen *screen, float size_x, float size_y, + const float asp[2], + float r_scale[2]) +{ + float max_x = 0, max_y = 0; + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + max_x = MAX2(max_x, sa->totrct.xmax); + max_y = MAX2(max_y, sa->totrct.ymax); + } + r_scale[0] = (size_x * asp[0]) / max_x; + r_scale[1] = (size_y * asp[1]) / max_y; +} + +static void screen_preview_draw_areas(const bScreen *screen, const float scale[2], const float col[4], + const float ofs_between_areas) +{ + const float ofs_h = ofs_between_areas * 0.5f; + unsigned int pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + rctf rect; + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(col); + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + rect.xmin = sa->totrct.xmin * scale[0] + ofs_h; + rect.xmax = sa->totrct.xmax * scale[0] - ofs_h; + rect.ymin = sa->totrct.ymin * scale[1] + ofs_h; + rect.ymax = sa->totrct.ymax * scale[1] - ofs_h; + + immBegin(PRIM_TRIANGLE_FAN, 4); + immVertex2f(pos, rect.xmin, rect.ymin); + immVertex2f(pos, rect.xmax, rect.ymin); + immVertex2f(pos, rect.xmax, rect.ymax); + immVertex2f(pos, rect.xmin, rect.ymax); + immEnd(); + } + + immUnbindProgram(); +} + +static void screen_preview_draw(const bScreen *screen, int size_x, int size_y) +{ + const float asp[2] = {1.0f, 0.8f}; /* square previews look a bit ugly */ + /* could use theme color (tui.wcol_menu_item.text), but then we'd need to regenerate all previews when changing */ + const float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float scale[2]; + + wmOrtho2(0.0f, size_x, 0.0f, size_y); + /* center */ + glTranslatef(size_x * (1.0f - asp[0]) * 0.5f, size_y * (1.0f - asp[1]) * 0.5f, 0.0f); + + screen_preview_scale_get(screen, size_x, size_y, asp, scale); + screen_preview_draw_areas(screen, scale, col, 1.5f); +} + +/** + * Render the preview for a screen layout in \a screen. + */ +void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect) +{ + char err_out[256] = "unknown"; + GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, err_out); + + GPU_offscreen_bind(offscreen, true); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + screen_preview_draw(screen, size_x, size_y); + + GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, r_rect); + GPU_offscreen_unbind(offscreen, true); + + GPU_offscreen_free(offscreen); +} diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 5cd0d33c365..239577a9fc4 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -42,6 +42,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_icons.h" #include "BKE_image.h" #include "BKE_global.h" #include "BKE_library.h" @@ -51,9 +52,6 @@ #include "BKE_screen.h" #include "BKE_scene.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" - #include "WM_api.h" #include "WM_types.h" @@ -615,7 +613,9 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) screen_delarea(C, scr, sa2); removedouble_scrverts(scr); sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - + /* Update preview thumbnail */ + BKE_icon_changed(scr->id.icon_id); + return 1; } @@ -834,217 +834,6 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) } -/* *********************** DRAWING **************************************** */ - -/* draw vertical shape visualizing future joining (left as well - * right direction of future joining) */ -static void draw_horizontal_join_shape(ScrArea *sa, char dir) -{ - vec2f points[10]; - short i; - float w, h; - float width = sa->v3->vec.x - sa->v1->vec.x; - float height = sa->v3->vec.y - sa->v1->vec.y; - - if (height < width) { - h = height / 8; - w = height / 4; - } - else { - h = width / 8; - w = width / 4; - } - - points[0].x = sa->v1->vec.x; - points[0].y = sa->v1->vec.y + height / 2; - - points[1].x = sa->v1->vec.x; - points[1].y = sa->v1->vec.y; - - points[2].x = sa->v4->vec.x - w; - points[2].y = sa->v4->vec.y; - - points[3].x = sa->v4->vec.x - w; - points[3].y = sa->v4->vec.y + height / 2 - 2 * h; - - points[4].x = sa->v4->vec.x - 2 * w; - points[4].y = sa->v4->vec.y + height / 2; - - points[5].x = sa->v4->vec.x - w; - points[5].y = sa->v4->vec.y + height / 2 + 2 * h; - - points[6].x = sa->v3->vec.x - w; - points[6].y = sa->v3->vec.y; - - points[7].x = sa->v2->vec.x; - points[7].y = sa->v2->vec.y; - - points[8].x = sa->v4->vec.x; - points[8].y = sa->v4->vec.y + height / 2 - h; - - points[9].x = sa->v4->vec.x; - points[9].y = sa->v4->vec.y + height / 2 + h; - - if (dir == 'l') { - /* when direction is left, then we flip direction of arrow */ - float cx = sa->v1->vec.x + width; - for (i = 0; i < 10; i++) { - points[i].x -= cx; - points[i].x = -points[i].x; - points[i].x += sa->v1->vec.x; - } - } - - glBegin(GL_POLYGON); - for (i = 0; i < 5; i++) - glVertex2f(points[i].x, points[i].y); - glEnd(); - glBegin(GL_POLYGON); - for (i = 4; i < 8; i++) - glVertex2f(points[i].x, points[i].y); - glVertex2f(points[0].x, points[0].y); - glEnd(); - - glRectf(points[2].x, points[2].y, points[8].x, points[8].y); - glRectf(points[6].x, points[6].y, points[9].x, points[9].y); -} - -/* draw vertical shape visualizing future joining (up/down direction) */ -static void draw_vertical_join_shape(ScrArea *sa, char dir) -{ - vec2f points[10]; - short i; - float w, h; - float width = sa->v3->vec.x - sa->v1->vec.x; - float height = sa->v3->vec.y - sa->v1->vec.y; - - if (height < width) { - h = height / 4; - w = height / 8; - } - else { - h = width / 4; - w = width / 8; - } - - points[0].x = sa->v1->vec.x + width / 2; - points[0].y = sa->v3->vec.y; - - points[1].x = sa->v2->vec.x; - points[1].y = sa->v2->vec.y; - - points[2].x = sa->v1->vec.x; - points[2].y = sa->v1->vec.y + h; - - points[3].x = sa->v1->vec.x + width / 2 - 2 * w; - points[3].y = sa->v1->vec.y + h; - - points[4].x = sa->v1->vec.x + width / 2; - points[4].y = sa->v1->vec.y + 2 * h; - - points[5].x = sa->v1->vec.x + width / 2 + 2 * w; - points[5].y = sa->v1->vec.y + h; - - points[6].x = sa->v4->vec.x; - points[6].y = sa->v4->vec.y + h; - - points[7].x = sa->v3->vec.x; - points[7].y = sa->v3->vec.y; - - points[8].x = sa->v1->vec.x + width / 2 - w; - points[8].y = sa->v1->vec.y; - - points[9].x = sa->v1->vec.x + width / 2 + w; - points[9].y = sa->v1->vec.y; - - if (dir == 'u') { - /* when direction is up, then we flip direction of arrow */ - float cy = sa->v1->vec.y + height; - for (i = 0; i < 10; i++) { - points[i].y -= cy; - points[i].y = -points[i].y; - points[i].y += sa->v1->vec.y; - } - } - - glBegin(GL_POLYGON); - for (i = 0; i < 5; i++) - glVertex2f(points[i].x, points[i].y); - glEnd(); - glBegin(GL_POLYGON); - for (i = 4; i < 8; i++) - glVertex2f(points[i].x, points[i].y); - glVertex2f(points[0].x, points[0].y); - glEnd(); - - glRectf(points[2].x, points[2].y, points[8].x, points[8].y); - glRectf(points[6].x, points[6].y, points[9].x, points[9].y); -} - -/* draw join shape due to direction of joining */ -static void draw_join_shape(ScrArea *sa, char dir) -{ - if (dir == 'u' || dir == 'd') - draw_vertical_join_shape(sa, dir); - else - draw_horizontal_join_shape(sa, dir); -} - -/* draw screen area darker with arrow (visualization of future joining) */ -static void scrarea_draw_shape_dark(ScrArea *sa, char dir) -{ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ub(0, 0, 0, 50); - draw_join_shape(sa, dir); -} - -/* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */ -static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir)) -{ - glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); - /* value 181 was hardly computed: 181~105 */ - glColor4ub(255, 255, 255, 50); - /* draw_join_shape(sa, dir); */ - glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y); -} - -static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2) -{ - /* right border area */ - if (x2 < sizex - 1) { - glVertex2s(x2, y1); - glVertex2s(x2, y2); - } - - /* left border area */ - if (x1 > 0) { /* otherwise it draws the emboss of window over */ - glVertex2s(x1, y1); - glVertex2s(x1, y2); - } - - /* top border area */ - if (y2 < sizey - 1) { - glVertex2s(x1, y2); - glVertex2s(x2, y2); - } - - /* bottom border area */ - if (y1 > 0) { - glVertex2s(x1, y1); - glVertex2s(x2, y1); - } -} - -/** screen edges drawing **/ -static void drawscredge_area(ScrArea *sa, int sizex, int sizey) -{ - short x1 = sa->v1->vec.x; - short y1 = sa->v1->vec.y; - short x2 = sa->v3->vec.x; - short y2 = sa->v3->vec.y; - - drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2); -} /* ****************** EXPORTED API TO OTHER MODULES *************************** */ @@ -1069,6 +858,9 @@ static void region_cursor_set(wmWindow *win, int swinid, int swin_changed) for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid == swinid) { if (swin_changed || (ar->type && ar->type->event_cursor)) { + if (WM_manipulatormap_cursor_set(ar->manipulator_map, win)) { + return; + } ED_region_cursor_set(win, sa, ar); } return; @@ -1101,100 +893,6 @@ void ED_screen_do_listen(bContext *C, wmNotifier *note) } } -/* only for edge lines between areas, and the blended join arrows */ -void ED_screen_draw(wmWindow *win) -{ - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); - - ScrArea *sa; - ScrArea *sa1 = NULL; - ScrArea *sa2 = NULL; - ScrArea *sa3 = NULL; - - wmSubWindowSet(win, win->screen->mainwin); - - /* Note: first loop only draws if U.pixelsize > 1, skip otherwise */ - if (U.pixelsize > 1.0f) { - /* FIXME: doesn't our glLineWidth already scale by U.pixelsize? */ - glLineWidth((2.0f * U.pixelsize) - 1); - glColor3ub(0x50, 0x50, 0x50); - glBegin(GL_LINES); - for (sa = win->screen->areabase.first; sa; sa = sa->next) - drawscredge_area(sa, winsize_x, winsize_y); - glEnd(); - } - - glLineWidth(1); - glColor3ub(0, 0, 0); - glBegin(GL_LINES); - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - drawscredge_area(sa, winsize_x, winsize_y); - - /* gather area split/join info */ - if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa; - if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa; - if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa; - } - glEnd(); - - /* blended join arrow */ - if (sa1 && sa2) { - int dir = area_getorientation(sa1, sa2); - int dira = -1; - if (dir != -1) { - switch (dir) { - case 0: /* W */ - dir = 'r'; - dira = 'l'; - break; - case 1: /* N */ - dir = 'd'; - dira = 'u'; - break; - case 2: /* E */ - dir = 'l'; - dira = 'r'; - break; - case 3: /* S */ - dir = 'u'; - dira = 'd'; - break; - } - } - glEnable(GL_BLEND); - scrarea_draw_shape_dark(sa2, dir); - scrarea_draw_shape_light(sa1, dira); - glDisable(GL_BLEND); - } - - /* splitpoint */ - if (sa3) { - glEnable(GL_BLEND); - glBegin(GL_LINES); - glColor4ub(255, 255, 255, 100); - - if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) { - glVertex2s(sa3->totrct.xmin, win->eventstate->y); - glVertex2s(sa3->totrct.xmax, win->eventstate->y); - glColor4ub(0, 0, 0, 100); - glVertex2s(sa3->totrct.xmin, win->eventstate->y + 1); - glVertex2s(sa3->totrct.xmax, win->eventstate->y + 1); - } - else { - glVertex2s(win->eventstate->x, sa3->totrct.ymin); - glVertex2s(win->eventstate->x, sa3->totrct.ymax); - glColor4ub(0, 0, 0, 100); - glVertex2s(win->eventstate->x + 1, sa3->totrct.ymin); - glVertex2s(win->eventstate->x + 1, sa3->totrct.ymax); - } - glEnd(); - glDisable(GL_BLEND); - } - - win->screen->do_draw = false; -} - /* helper call for below, dpi changes headers */ static void screen_refresh_headersizes(void) { @@ -1274,25 +972,28 @@ void ED_screens_initialize(wmWindowManager *wm) void ED_region_exit(bContext *C, ARegion *ar) { wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); ARegion *prevar = CTX_wm_region(C); if (ar->type && ar->type->exit) ar->type->exit(wm, ar); CTX_wm_region_set(C, ar); + WM_event_remove_handlers(C, &ar->handlers); + WM_event_modal_handler_region_replace(win, ar, NULL); if (ar->swinid) { - wm_subwindow_close(CTX_wm_window(C), ar->swinid); + wm_subwindow_close(win, ar->swinid); ar->swinid = 0; } - + if (ar->headerstr) { MEM_freeN(ar->headerstr); ar->headerstr = NULL; } if (ar->regiontimer) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ar->regiontimer); + WM_event_remove_timer(wm, win, ar->regiontimer); ar->regiontimer = NULL; } @@ -1302,6 +1003,7 @@ void ED_region_exit(bContext *C, ARegion *ar) void ED_area_exit(bContext *C, ScrArea *sa) { wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *ar; @@ -1309,10 +1011,13 @@ void ED_area_exit(bContext *C, ScrArea *sa) sa->type->exit(wm, sa); CTX_wm_area_set(C, sa); + for (ar = sa->regionbase.first; ar; ar = ar->next) ED_region_exit(C, ar); WM_event_remove_handlers(C, &sa->handlers); + WM_event_modal_handler_area_replace(win, sa, NULL); + CTX_wm_area_set(C, prevsa); } diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index ccb6d5a6dca..49c0869fcfb 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -31,6 +31,8 @@ #ifndef __SCREEN_INTERN_H__ #define __SCREEN_INTERN_H__ +struct bContextDataResult; + /* internal exports only */ #define AZONESPOT (0.6f * U.widget_unit) @@ -40,12 +42,12 @@ /* area.c */ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free); void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2); -void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade); +void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade); /* screen_edit.c */ ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2); ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge); -int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2); +int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2); int area_getorientation(ScrArea *sa, ScrArea *sb); void select_connected_scredge(bScreen *sc, ScrEdge *edge); @@ -61,7 +63,7 @@ ScrEdge *screen_find_active_scredge(bScreen *sc, struct AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2]); /* screen_context.c */ -int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result); +int ed_screen_context(const struct bContext *C, const char *member, struct bContextDataResult *result); extern const char *screen_context_dir[]; /* doc access */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index a7a0a240259..32b63aca34c 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -53,6 +53,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" @@ -1220,6 +1221,8 @@ static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int } WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */ + /* Update preview thumbnail */ + BKE_icon_changed(sc->id.icon_id); } } @@ -1508,7 +1511,9 @@ static int area_split_apply(bContext *C, wmOperator *op) ED_area_tag_redraw(sd->narea); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); - + /* Update preview thumbnail */ + BKE_icon_changed(sc->id.icon_id); + return 1; } diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 2dd7400bc37..6bfa51bf9fc 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -56,6 +56,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -451,25 +453,24 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float /* Helper callback for drawing the cursor itself */ static void screencast_draw_cursor(bContext *UNUSED(C), int x, int y, void *UNUSED(p_ptr)) { - - glPushMatrix(); - - glTranslatef((float)x, (float)y, 0.0f); - - glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - - glColor4ub(0, 0, 0, 32); - glutil_draw_filled_arc(0.0, M_PI * 2.0, 20, 40); - - glColor4ub(255, 255, 255, 128); - glutil_draw_lined_arc(0.0, M_PI * 2.0, 20, 40); + + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ub(0, 0, 0, 32); + imm_draw_filled_circle(pos, (float)x, (float)y, 20, 40); + + immUniformColor4ub(255, 255, 255, 128); + imm_draw_lined_circle(pos, (float)x, (float)y, 20, 40); + + immUnbindProgram(); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); } /* Turn brush cursor in 3D view on/off */ diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index bf344e1f721..ffaaed8ab42 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -78,6 +78,7 @@ #include "GPU_draw.h" #include "GPU_buffers.h" +#include "GPU_immediate.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -721,12 +722,28 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glLineWidth(4.0); - glColor4ub(0, 0, 0, 255); - sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]); + immUniformColor4ub(0, 0, 0, 255); + + immBegin(GL_LINES, 2); + immVertex2i(pos, x, y); + immVertex2i(pos, pop->startmouse[0], pop->startmouse[1]); + immEnd(); + glLineWidth(2.0); - glColor4ub(255, 255, 255, 255); - sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]); + immUniformColor4ub(255, 255, 255, 255); + + immBegin(GL_LINES, 2); + immVertex2i(pos, x, y); + immVertex2i(pos, pop->startmouse[0], pop->startmouse[1]); + immEnd(); + + immUnbindProgram(); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 9fc96e06299..df9c67b1f2e 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -61,6 +61,7 @@ #include "ED_keyframes_draw.h" #include "action_intern.h" +#include "GPU_immediate.h" /* ************************************************************************* */ /* Channel List */ @@ -203,6 +204,12 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* first backdrop strips */ y = (float)(-ACHANNEL_HEIGHT(ac)); + + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glEnable(GL_BLEND); for (ale = anim_data.first; ale; ale = ale->next) { @@ -221,7 +228,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* determine if channel is selected */ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); - + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { switch (ale->type) { case ANIMTYPE_SUMMARY: @@ -233,60 +240,60 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) case ANIMTYPE_SCENE: case ANIMTYPE_OBJECT: { - if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45); - else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22); + if (sel) immUniformColor4ub(col1b[0], col1b[1], col1b[2], 0x45); + else immUniformColor4ub(col1b[0], col1b[1], col1b[2], 0x22); break; } case ANIMTYPE_FILLACTD: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: { - if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45); - else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22); + if (sel) immUniformColor4ub(col2b[0], col2b[1], col2b[2], 0x45); + else immUniformColor4ub(col2b[0], col2b[1], col2b[2], 0x22); break; } case ANIMTYPE_GROUP: { - if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22); - else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22); + if (sel) immUniformColor4ub(col1a[0], col1a[1], col1a[2], 0x22); + else immUniformColor4ub(col2a[0], col2a[1], col2a[2], 0x22); break; } default: { - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); - else glColor4ub(col2[0], col2[1], col2[2], 0x22); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22); break; } } /* draw region twice: firstly backdrop, then the current range */ - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); if (ac->datatype == ANIMCONT_ACTION) - glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } else if (ac->datatype == ANIMCONT_GPENCIL) { /* frames less than one get less saturated background */ - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); - else glColor4ub(col2[0], col2[1], col2[2], 0x22); - glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22); + immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); /* frames one and higher get a saturated background */ - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44); - else glColor4ub(col2[0], col2[1], col2[2], 0x44); - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x44); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x44); + immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } else if (ac->datatype == ANIMCONT_MASK) { /* TODO --- this is a copy of gpencil */ /* frames less than one get less saturated background */ - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); - else glColor4ub(col2[0], col2[1], col2[2], 0x22); - glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x22); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x22); + immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); /* frames one and higher get a saturated background */ - if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44); - else glColor4ub(col2[0], col2[1], col2[2], 0x44); - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); + if (sel) immUniformColor4ub(col1[0], col1[1], col1[2], 0x44); + else immUniformColor4ub(col2[0], col2[1], col2[2], 0x44); + immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } } } @@ -353,11 +360,12 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* black line marking 'current frame' for Time-Slide transform mode */ if (saction->flag & SACTION_MOVING) { - glColor3f(0.0f, 0.0f, 0.0f); - - glBegin(GL_LINES); - glVertex2f(saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD); - glVertex2f(saction->timeslide, v2d->cur.ymax); - glEnd(); + immUniformColor3f(0.0f, 0.0f, 0.0f); + + immBegin(GL_LINES, 2); + immVertex2f(pos, saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD); + immVertex2f(pos, saction->timeslide, v2d->cur.ymax); + immEnd(); } + immUnbindProgram(); } diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index ac6e3123e4e..5ff1d758563 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -121,12 +121,17 @@ void ED_spacetypes_init(void) ED_operatortypes_view2d(); ED_operatortypes_ui(); - - /* register operators */ + + /* register types for operators and manipulators */ spacetypes = BKE_spacetypes_list(); for (type = spacetypes->first; type; type = type->next) { - if (type->operatortypes) + /* init manipulator types first, operator-types need them */ + if (type->manipulators) { + type->manipulators(); + } + if (type->operatortypes) { type->operatortypes(); + } } /* register internal render callbacks */ diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 6396b390ca0..c45b8acae0a 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -40,6 +40,7 @@ #include "MEM_guardedalloc.h" #include "BIF_gl.h" +#include "GPU_immediate.h" #include "UI_interface.h" #include "UI_resources.h" @@ -157,6 +158,8 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha int offl = 0, offc = 0; int xy[2] = {CONSOLE_DRAW_MARGIN, CONSOLE_DRAW_MARGIN}; int pen[2]; + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); xy[1] += tvc->lheight / 6; console_cursor_wrap_offset(sc->prompt, tvc->console_width, &offl, &offc, NULL); @@ -168,14 +171,17 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha pen[1] += tvc->lheight * offl; /* cursor */ - UI_GetThemeColor3ubv(TH_CONSOLE_CURSOR, fg); - glColor3ubv(fg); - - glRecti((xy[0] + pen[0]) - 1, - (xy[1] + pen[1]), - (xy[0] + pen[0]) + 1, - (xy[1] + pen[1] + tvc->lheight) - ); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_CONSOLE_CURSOR); + + immRectf(pos, + (xy[0] + pen[0]) - 1, + (xy[1] + pen[1]), + (xy[0] + pen[0]) + 1, + (xy[1] + pen[1] + tvc->lheight) + ); + + immUnbindProgram(); } console_line_color(fg, cl_iter->type); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 52d01063175..f049d616aa7 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -71,6 +71,10 @@ #include "WM_api.h" #include "WM_types.h" +//#include "GPU_draw.h" +//#include "GPU_basic_shader.h" +#include "GPU_immediate.h" + #include "filelist.h" #include "file_intern.h" // own include @@ -258,9 +262,10 @@ void file_draw_buttons(const bContext *C, ARegion *ar) static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade) { - UI_ThemeColorShade(colorid, shade); + float color[4]; + UI_GetThemeColorShade4fv(colorid, shade, color); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox((float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f); + UI_draw_roundbox((float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f, color); } @@ -394,8 +399,13 @@ static void file_draw_preview( /* border */ if (use_dropshadow) { - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2,KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); + imm_draw_line_box(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + immUnbindProgram(); } but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL); @@ -467,33 +477,43 @@ static void draw_dividers(FileLayout *layout, View2D *v2d) const int step = (layout->tile_w + 2 * layout->tile_border_x); int v1[2], v2[2]; int sx; + unsigned int vertex_ct = 0; unsigned char col_hi[3], col_lo[3]; + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + + vertex_ct = (v2d->cur.xmax - v2d->tot.xmin) / step + 1; /* paint at least 1 divider */ + vertex_ct *= 4; /* vertex_count = 2 points per divider * 2 lines per divider */ + UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi); UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo); v1[1] = v2d->cur.ymax - layout->tile_border_y; v2[1] = v2d->cur.ymin; - glBegin(GL_LINES); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, vertex_ct); /* vertical column dividers */ sx = (int)v2d->tot.xmin; while (sx < v2d->cur.xmax) { sx += step; - glColor3ubv(col_lo); v1[0] = v2[0] = sx; - glVertex2iv(v1); - glVertex2iv(v2); + immAttrib3ubv(color, col_lo); + immVertex2iv(pos, v1); + immVertex2iv(pos, v2); - glColor3ubv(col_hi); v1[0] = v2[0] = sx + 1; - glVertex2iv(v1); - glVertex2iv(v2); + immAttrib3ubv(color, col_hi); + immVertex2iv(pos, v1); + immVertex2iv(pos, v2); } - glEnd(); + immEnd(); + immUnbindProgram(); } void file_draw_list(const bContext *C, ARegion *ar) diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 96a078b2817..9781c909ef6 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -50,6 +50,9 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" + #include "ED_anim_api.h" #include "graph_intern.h" @@ -121,16 +124,37 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d) /* Points ---------------- */ -/* helper func - draw keyframe vertices only for an F-Curve */ -static void draw_fcurve_vertices_keyframes(FCurve *fcu, SpaceIpo *UNUSED(sipo), View2D *v2d, short edit, short sel) +/* helper func - set color to draw F-Curve data with */ +static void set_fcurve_vertex_color(FCurve *fcu, bool sel) +{ + /* Fade the 'intensity' of the vertices based on the selection of the curves too */ + int alphaOffset = (int)((fcurve_display_alpha(fcu) - 1.0f) * 255); + + float color[4]; + + /* Set color of curve vertex based on state of curve (i.e. 'Edit' Mode) */ + if ((fcu->flag & FCURVE_PROTECTED) == 0) { + /* Curve's points ARE BEING edited */ + UI_GetThemeColorShadeAlpha4fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, 0, alphaOffset, color); + } + else { + /* Curve's points CANNOT BE edited */ + UI_GetThemeColorShadeAlpha4fv(sel ? TH_TEXT_HI : TH_TEXT, 0, alphaOffset, color); + } + + immUniformColor4fv(color); +} + +static void draw_fcurve_selected_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, bool sel, unsigned pos) { - BezTriple *bezt = fcu->bezt; const float fac = 0.05f * BLI_rctf_size_x(&v2d->cur); - int i; - - glBegin(GL_POINTS); - - for (i = 0; i < fcu->totvert; i++, bezt++) { + + set_fcurve_vertex_color(fcu, sel); + + immBeginAtMost(GL_POINTS, fcu->totvert); + + BezTriple *bezt = fcu->bezt; + for (int i = 0; i < fcu->totvert; i++, bezt++) { /* as an optimization step, only draw those in view * - we apply a correction factor to ensure that points don't pop in/out due to slight twitches of view size */ @@ -141,80 +165,50 @@ static void draw_fcurve_vertices_keyframes(FCurve *fcu, SpaceIpo *UNUSED(sipo), * - */ if ((bezt->f2 & SELECT) == sel) - glVertex3fv(bezt->vec[1]); + immVertex2fv(pos, bezt->vec[1]); } else { /* no check for selection here, as curve is not editable... */ /* XXX perhaps we don't want to even draw points? maybe add an option for that later */ - glVertex3fv(bezt->vec[1]); + immVertex2fv(pos, bezt->vec[1]); } } } - - glEnd(); -} + immEnd(); +} -/* helper func - draw handle vertex for an F-Curve as a round unfilled circle - * NOTE: the caller MUST HAVE GL_LINE_SMOOTH & GL_BLEND ENABLED, otherwise, the controls don't - * have a consistent appearance (due to off-pixel alignments)... - */ -static void draw_fcurve_handle_control(float x, float y, float xscale, float yscale, float hsize) +/* helper func - draw keyframe vertices only for an F-Curve */ +static void draw_fcurve_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, unsigned pos) { - static GLuint displist = 0; - - /* initialize round circle shape */ - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0, 0.7, 8, 1); - gluDeleteQuadric(qobj); - - glEndList(); - } - - /* adjust view transform before starting */ - glTranslatef(x, y, 0.0f); - glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f); - - /* draw! */ - glCallList(displist); - - /* restore view transform */ - glScalef(xscale / hsize, yscale / hsize, 1.0); - glTranslatef(-x, -y, 0.0f); + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + + immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize); + + draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, false, pos); + draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, true, pos); + + immUnbindProgram(); } + /* helper func - draw handle vertices only for an F-Curve (if it is not protected) */ -static void draw_fcurve_vertices_handles(FCurve *fcu, SpaceIpo *sipo, View2D *v2d, short sel, short sel_handle_only, float units_scale) +static void draw_fcurve_selected_handle_vertices(FCurve *fcu, View2D *v2d, bool sel, bool sel_handle_only, unsigned pos) { - BezTriple *bezt = fcu->bezt; - BezTriple *prevbezt = NULL; - float hsize, xscale, yscale; - int i; - - /* get view settings */ - hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize; - UI_view2d_scale_get(v2d, &xscale, &yscale); + (void) v2d; /* TODO: use this to draw only points in view */ - /* Compensate OGL scale sued for unit mapping, so circle will be circle, not ellipse */ - yscale *= units_scale; - /* set handle color */ - if (sel) UI_ThemeColor(TH_HANDLE_VERTEX_SELECT); - else UI_ThemeColor(TH_HANDLE_VERTEX); - - /* anti-aliased lines for more consistent appearance */ - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - - for (i = 0; i < fcu->totvert; i++, prevbezt = bezt, bezt++) { - /* Draw the editmode handles for a bezier curve (others don't have handles) + float hcolor[3]; + UI_GetThemeColor3fv(sel ? TH_HANDLE_VERTEX_SELECT : TH_HANDLE_VERTEX, hcolor); + immUniform4f("outlineColor", hcolor[0], hcolor[1], hcolor[2], 1.0f); + immUniformColor3fvAlpha(hcolor, 0.4f); + + immBeginAtMost(GL_POINTS, fcu->totvert * 2); + + BezTriple *bezt = fcu->bezt; + BezTriple *prevbezt = NULL; + for (int i = 0; i < fcu->totvert; i++, prevbezt = bezt, bezt++) { + /* Draw the editmode handles for a bezier curve (others don't have handles) * if their selection status matches the selection status we're drawing for * - first handle only if previous beztriple was bezier-mode * - second handle only if current beztriple is bezier-mode @@ -225,68 +219,61 @@ static void draw_fcurve_vertices_handles(FCurve *fcu, SpaceIpo *sipo, View2D *v2 if (!sel_handle_only || BEZT_ISSEL_ANY(bezt)) { if ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) { if ((bezt->f1 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[0][0] < v2d->cur.xmax)*/ - draw_fcurve_handle_control(bezt->vec[0][0], bezt->vec[0][1], xscale, yscale, hsize); + immVertex2fv(pos, bezt->vec[0]); } - + if (bezt->ipo == BEZT_IPO_BEZ) { if ((bezt->f3 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[2][0] < v2d->cur.xmax)*/ - draw_fcurve_handle_control(bezt->vec[2][0], bezt->vec[2][1], xscale, yscale, hsize); + immVertex2fv(pos, bezt->vec[2]); } } } - - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); + + immEnd(); } -/* helper func - set color to draw F-Curve data with */ -static void set_fcurve_vertex_color(FCurve *fcu, short sel) +/* helper func - draw handle vertices only for an F-Curve (if it is not protected) */ +static void draw_fcurve_handle_vertices(FCurve *fcu, View2D *v2d, bool sel_handle_only, unsigned pos) { - /* Fade the 'intensity' of the vertices based on the selection of the curves too */ - int alphaOffset = (int)((fcurve_display_alpha(fcu) - 1.0f) * 255); - - /* Set color of curve vertex based on state of curve (i.e. 'Edit' Mode) */ - if ((fcu->flag & FCURVE_PROTECTED) == 0) { - /* Curve's points ARE BEING edited */ - if (sel) UI_ThemeColorShadeAlpha(TH_VERTEX_SELECT, 0, alphaOffset); - else UI_ThemeColorShadeAlpha(TH_VERTEX, 0, alphaOffset); - } - else { - /* Curve's points CANNOT BE edited */ - if (sel) UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, alphaOffset); - else UI_ThemeColorShadeAlpha(TH_TEXT, 0, alphaOffset); - } + /* smooth outlines for more consistent appearance */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + + /* set handle size */ + immUniform1f("size", (UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) + 1.0f) * U.pixelsize); + immUniform1f("outlineWidth", 1.0f * U.pixelsize); + + draw_fcurve_selected_handle_vertices(fcu, v2d, false, sel_handle_only, pos); + draw_fcurve_selected_handle_vertices(fcu, v2d, true, sel_handle_only, pos); + + immUnbindProgram(); } -static void draw_fcurve_vertices(SpaceIpo *sipo, ARegion *ar, FCurve *fcu, short do_handles, short sel_handle_only, float units_scale) +static void draw_fcurve_vertices(ARegion *ar, FCurve *fcu, bool do_handles, bool sel_handle_only) { View2D *v2d = &ar->v2d; - + /* only draw points if curve is visible - * - draw unselected points before selected points as separate passes to minimize color-changing overhead - * (XXX dunno if this is faster than drawing all in one pass though) - * and also to make sure in the case of overlapping points that the selected is always visible + * - draw unselected points before selected points as separate passes + * to make sure in the case of overlapping points that the selected is always visible * - draw handles before keyframes, so that keyframes will overlap handles (keyframes are more important for users) */ - - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + glEnable(GL_BLEND); + GPU_enable_program_point_size(); + /* draw the two handles first (if they're shown, the curve doesn't have just a single keyframe, and the curve is being edited) */ if (do_handles) { - set_fcurve_vertex_color(fcu, 0); - draw_fcurve_vertices_handles(fcu, sipo, v2d, 0, sel_handle_only, units_scale); - - set_fcurve_vertex_color(fcu, 1); - draw_fcurve_vertices_handles(fcu, sipo, v2d, 1, sel_handle_only, units_scale); + draw_fcurve_handle_vertices(fcu, v2d, sel_handle_only, pos); } - + /* draw keyframes over the handles */ - set_fcurve_vertex_color(fcu, 0); - draw_fcurve_vertices_keyframes(fcu, sipo, v2d, !(fcu->flag & FCURVE_PROTECTED), 0); - - set_fcurve_vertex_color(fcu, 1); - draw_fcurve_vertices_keyframes(fcu, sipo, v2d, !(fcu->flag & FCURVE_PROTECTED), 1); + draw_fcurve_keyframe_vertices(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), pos); + + GPU_disable_program_point_size(); + glDisable(GL_BLEND); } /* Handles ---------------- */ @@ -303,10 +290,10 @@ static bool draw_fcurve_handles_check(SpaceIpo *sipo, FCurve *fcu) (fcu->totvert <= 1) /* do not show handles if there is only 1 keyframe, otherwise they all clump together in an ugly ball */ ) { - return 0; + return false; } else { - return 1; + return true; } } @@ -1080,7 +1067,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid glDisable(GL_BLEND); } - draw_fcurve_vertices(sipo, ar, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY), unit_scale); + draw_fcurve_vertices(ar, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY)); } else { /* samples: only draw two indicators at either end as indicators */ diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index e810f4db7dd..dd575619c0f 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -718,39 +718,6 @@ void draw_image_sample_line(SpaceImage *sima) } } -/* XXX becomes WM paint cursor */ -#if 0 -static void draw_image_view_tool(Scene *scene) -{ - ToolSettings *settings = scene->toolsettings; - Brush *brush = settings->imapaint.brush; - int mval[2]; - float radius; - int draw = 0; - - if (brush) { - if (settings->imapaint.flag & IMAGEPAINT_DRAWING) { - if (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING) - draw = 1; - } - else if (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL) - draw = 1; - - if (draw) { - getmouseco_areawin(mval); - - radius = BKE_brush_size_get(brush) * G.sima->zoom; - fdrawXORcirc(mval[0], mval[1], radius); - - if (brush->innerradius != 1.0) { - radius *= brush->innerradius; - fdrawXORcirc(mval[0], mval[1], radius); - } - } - } -} -#endif - static unsigned char *get_alpha_clone_image(const bContext *C, Scene *scene, int *width, int *height) { Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint); diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index c801a736e31..b82972853e2 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -39,6 +39,8 @@ #include "BLI_utildefines.h" #include "BLI_string_utf8.h" +#include "GPU_immediate.h" + #include "BIF_gl.h" #include "BKE_text.h" @@ -81,9 +83,15 @@ static void console_draw_sel(const char *str, const int sel[2], const int xy[2], glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ubv(bg_sel); - glRecti(xy[0] + (cwidth * sta), xy[1] - 2 + lheight, xy[0] + (cwidth * end), xy[1] - 2); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ubv(bg_sel); + immRecti(pos, xy[0] + (cwidth * sta), xy[1] - 2 + lheight, xy[0] + (cwidth * end), xy[1] - 2); + + immUnbindProgram(); glDisable(GL_BLEND); } @@ -182,8 +190,14 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str cdc->sel[1] = str_len - sel_orig[0]; if (bg) { - glColor3ubv(bg); - glRecti(0, cdc->xy[1], cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines))); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ubv(bg); + immRecti(pos, 0, cdc->xy[1], cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines))); + + immUnbindProgram(); } glColor3ubv(fg); @@ -230,8 +244,14 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str else { /* simple, no wrap */ if (bg) { - glColor3ubv(bg); - glRecti(0, cdc->xy[1], cdc->winx, cdc->xy[1] + cdc->lheight); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ubv(bg); + immRecti(pos, 0, cdc->xy[1], cdc->winx, cdc->xy[1] + cdc->lheight); + + immUnbindProgram(); } glColor3ubv(fg); diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 5b3c062e16d..a9b8bfd08c8 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -1,3 +1,4 @@ + /* * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -56,6 +57,9 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_draw.h" + #include "WM_types.h" #include "UI_interface.h" @@ -268,13 +272,14 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col /* helper call for drawing influence/time control curves for a given NLA-strip */ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc) { + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.7f, 0.7f, 0.7f, 1.0f); + const float yheight = ymaxc - yminc; - - /* drawing color is simply a light-gray */ - // TODO: is this color suitable? - // XXX nasty hacked color for now... which looks quite bad too... - glColor3f(0.7f, 0.7f, 0.7f); - + /* draw with AA'd line */ glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); @@ -285,45 +290,49 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc) float cfra; /* plot the curve (over the strip's main region) */ - glBegin(GL_LINE_STRIP); + immBegin(GL_LINE_STRIP, abs(strip->end - strip->start + 1)); + /* sample at 1 frame intervals, and draw * - min y-val is yminc, max is y-maxc, so clamp in those regions */ for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) { float y = evaluate_fcurve(fcu, cfra); // assume this to be in 0-1 range - glVertex2f(cfra, ((y * yheight) + yminc)); + immVertex2f(pos, cfra, ((y * yheight) + yminc)); } - glEnd(); // GL_LINE_STRIP + + immEnd(); } else { /* use blend in/out values only if both aren't zero */ if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) { - glBegin(GL_LINE_STRIP); + immBeginAtMost(GL_LINE_STRIP, 4); + /* start of strip - if no blendin, start straight at 1, otherwise from 0 to 1 over blendin frames */ if (IS_EQF(strip->blendin, 0.0f) == 0) { - glVertex2f(strip->start, yminc); - glVertex2f(strip->start + strip->blendin, ymaxc); + immVertex2f(pos, strip->start, yminc); + immVertex2f(pos, strip->start + strip->blendin, ymaxc); } else - glVertex2f(strip->start, ymaxc); + immVertex2f(pos, strip->start, ymaxc); /* end of strip */ if (IS_EQF(strip->blendout, 0.0f) == 0) { - glVertex2f(strip->end - strip->blendout, ymaxc); - glVertex2f(strip->end, yminc); + immVertex2f(pos, strip->end - strip->blendout, ymaxc); + immVertex2f(pos, strip->end, yminc); } else - glVertex2f(strip->end, ymaxc); - glEnd(); // GL_LINE_STRIP + immVertex2f(pos, strip->end, ymaxc); + + immEnd(); } } - - /* time -------------------------- */ - // XXX do we want to draw this curve? in a different color too? - + /* turn off AA'd lines */ glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); + + //Unbind GPU_SHADER_2D_UNIFORM_COLOR + immUnbindProgram(); } /* main call for drawing a single NLA-strip */ diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 7b08b8368ba..c3f2d05b0fb 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -53,6 +53,9 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -62,6 +65,7 @@ #include "WM_types.h" #include "UI_resources.h" +#include "UI_view2d.h" #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" @@ -80,49 +84,6 @@ static void node_socket_button_label(bContext *UNUSED(C), uiLayout *layout, Poin uiItemL(layout, text, 0); } - -/* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */ - -#if 0 /* UNUSED */ -static void node_draw_socket_new(bNodeSocket *sock, float size) -{ - float x = sock->locx, y = sock->locy; - - /* 16 values of sin function */ - static float si[16] = { - 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f, - 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f, - -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f, - -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f - }; - /* 16 values of cos function */ - static float co[16] = { - 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f, - -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f, - -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f, - 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f, - }; - int a; - - glColor3ub(180, 180, 180); - - glBegin(GL_POLYGON); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); - - glColor4ub(0, 0, 0, 150); - glEnable(GL_BLEND); - glEnable(GL_LINE_SMOOTH); - glBegin(GL_LINE_LOOP); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); -} -#endif - /* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */ static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -465,7 +426,7 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode, { rctf *rct = &node->totr; int color_id = node_get_colorid(node); - unsigned char color[4]; + float color[4]; float alpha; /* skip if out of view */ @@ -475,36 +436,37 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode, return; } - UI_GetThemeColor4ubv(TH_NODE_FRAME, color); - alpha = (float)(color[3]) / 255.0f; + UI_GetThemeColor4fv(TH_NODE_FRAME, color); + alpha = color[3]; /* shadow */ node_draw_shadow(snode, node, BASIS_RAD, alpha); /* body */ - if (node->flag & NODE_CUSTOM_COLOR) - glColor4f(node->color[0], node->color[1], node->color[2], alpha); + if (node->flag & NODE_CUSTOM_COLOR) { + rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], alpha); + } else - UI_ThemeColor4(TH_NODE_FRAME); + UI_GetThemeColor4fv(TH_NODE_FRAME, color); glEnable(GL_BLEND); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD); + UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color); glDisable(GL_BLEND); /* outline active and selected emphasis */ if (node->flag & SELECT) { glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - + if (node->flag & NODE_ACTIVE) - UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40); + UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color); else - UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40); + UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color); + UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, - rct->xmin, rct->ymin, - rct->xmax, rct->ymax, BASIS_RAD); - + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color); + + glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } @@ -580,14 +542,12 @@ static void node_draw_reroute_prepare(const bContext *UNUSED(C), bNodeTree *UNUS static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(snode), bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key)) { - bNodeSocket *sock; char showname[128]; /* 128 used below */ rctf *rct = &node->totr; #if 0 /* UNUSED */ float size = NODE_REROUTE_SIZE; #endif - float socket_size = NODE_SOCKSIZE; /* skip if out of view */ if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax || @@ -637,9 +597,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED( /* only draw input socket. as they all are placed on the same position. * highlight also if node itself is selected, since we don't display the node body separately! */ - for (sock = node->inputs.first; sock; sock = sock->next) { - node_socket_circle_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT)); - } + node_draw_sockets(&ar->v2d, C, ntree, node, false, node->flag & SELECT); UI_block_end(C, node->block); UI_block_draw(C, node->block); @@ -2229,14 +2187,21 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo const float cx = x + snode->zoom * backdropWidth * node->custom3; const float cy = y + snode->zoom * backdropHeight * node->custom4; - glColor3f(1.0, 1.0, 1.0); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); - glBegin(GL_LINES); - glVertex2f(cx - 25, cy - 25); - glVertex2f(cx + 25, cy + 25); - glVertex2f(cx + 25, cy - 25); - glVertex2f(cx - 25, cy + 25); - glEnd(); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3f(1.0f, 1.0f, 1.0f); + + immBegin(GL_LINES, 4); + immVertex2f(pos, cx - 25, cy - 25); + immVertex2f(pos, cx + 25, cy + 25); + immVertex2f(pos, cx + 25, cy - 25); + immVertex2f(pos, cx - 25, cy + 25); + immEnd(); + + immUnbindProgram(); } } @@ -2255,9 +2220,6 @@ static void node_composit_backdrop_boxmask(SpaceNode *snode, ImBuf *backdrop, bN float cx, cy, x1, x2, x3, x4; float y1, y2, y3, y4; - - glColor3f(1.0, 1.0, 1.0); - cx = x + snode->zoom * backdropWidth * boxmask->x; cy = y + snode->zoom * backdropHeight * boxmask->y; @@ -2270,12 +2232,21 @@ static void node_composit_backdrop_boxmask(SpaceNode *snode, ImBuf *backdrop, bN y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom; y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom; - glBegin(GL_LINE_LOOP); - glVertex2f(x1, y1); - glVertex2f(x2, y2); - glVertex2f(x3, y3); - glVertex2f(x4, y4); - glEnd(); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3f(1.0f, 1.0f, 1.0f); + + immBegin(GL_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x3, y3); + immVertex2f(pos, x4, y4); + immEnd(); + + immUnbindProgram(); } static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y) @@ -2293,9 +2264,6 @@ static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop float cx, cy, x1, x2, x3, x4; float y1, y2, y3, y4; - - glColor3f(1.0, 1.0, 1.0); - cx = x + snode->zoom * backdropWidth * ellipsemask->x; cy = y + snode->zoom * backdropHeight * ellipsemask->y; @@ -2308,13 +2276,21 @@ static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom; y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom; - glBegin(GL_LINE_LOOP); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); - glVertex2f(x1, y1); - glVertex2f(x2, y2); - glVertex2f(x3, y3); - glVertex2f(x4, y4); - glEnd(); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3f(1.0f, 1.0f, 1.0f); + + immBegin(GL_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x3, y3); + immVertex2f(pos, x4, y4); + immEnd(); + + immUnbindProgram(); } static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index ab40c55b59d..2a0593e6a0d 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -54,6 +54,9 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_draw.h" +#include "GPU_immediate.h" + #include "WM_api.h" #include "WM_types.h" @@ -617,60 +620,16 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) glDisable(GL_LINE_SMOOTH); } -/* this might have some more generic use */ -static void node_circle_draw(float x, float y, float size, const float col[4], int highlight) +static void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, PointerRNA node_ptr, bNodeSocket *sock, unsigned pos, unsigned col) { - /* 16 values of sin function */ - static const float si[16] = { - 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f, - 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f, - -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f, - -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f - }; - /* 16 values of cos function */ - static const float co[16] = { - 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f, - -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f, - -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f, - 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f, - }; - int a; - - glColor4fv(col); - - glEnable(GL_BLEND); - glBegin(GL_POLYGON); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); - glDisable(GL_BLEND); - - if (highlight) { - UI_ThemeColor(TH_TEXT_HI); - glLineWidth(1.5f); - } - else { - glColor4ub(0, 0, 0, 150); - } - glEnable(GL_BLEND); - glEnable(GL_LINE_SMOOTH); - glBegin(GL_LINE_LOOP); - for (a = 0; a < 16; a++) - glVertex2f(x + size * si[a], y + size * co[a]); - glEnd(); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); -} - -void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int highlight) -{ - PointerRNA ptr, node_ptr; + PointerRNA ptr; float color[4]; RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); - RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color); - node_circle_draw(sock->locx, sock->locy, size, color, highlight); + + immAttrib4fv(col, color); + immVertex2f(pos, sock->locx, sock->locy); } /* ************** Socket callbacks *********** */ @@ -679,10 +638,15 @@ static void node_draw_preview_background(float tile, rctf *rect) { float x, y; + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* draw checkerboard backdrop to show alpha */ - glColor3ub(120, 120, 120); - glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax); - glColor3ub(160, 160, 160); + immUniformColor3ub(120, 120, 120); + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + immUniformColor3ub(160, 160, 160); for (y = rect->ymin; y < rect->ymax; y += tile * 2) { for (x = rect->xmin; x < rect->xmax; x += tile * 2) { @@ -693,7 +657,7 @@ static void node_draw_preview_background(float tile, rctf *rect) if (y + tile > rect->ymax) tiley = rect->ymax - y; - glRectf(x, y, x + tilex, y + tiley); + immRectf(pos, x, y, x + tilex, y + tiley); } } for (y = rect->ymin + tile; y < rect->ymax; y += tile * 2) { @@ -705,9 +669,10 @@ static void node_draw_preview_background(float tile, rctf *rect) if (y + tile > rect->ymax) tiley = rect->ymax - y; - glRectf(x, y, x + tilex, y + tiley); + immRectf(pos, x, y, x + tilex, y + tiley); } } + immUnbindProgram(); } /* not a callback */ @@ -773,23 +738,129 @@ void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha) else { const float margin = 3.0f; - glColor4f(0.0f, 0.0f, 0.0f, 0.33f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.33f}; glEnable(GL_BLEND); UI_draw_roundbox(rct->xmin - margin, rct->ymin - margin, - rct->xmax + margin, rct->ymax + margin, radius + margin); + rct->xmax + margin, rct->ymax + margin, radius + margin, color); glDisable(GL_BLEND); } } +void node_draw_sockets(View2D *v2d, const bContext *C, bNodeTree *ntree, bNode *node, bool draw_outputs, bool select_all) +{ + PointerRNA node_ptr; + RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); + + float xscale, yscale; + UI_view2d_scale_get(v2d, &xscale, &yscale); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned col = add_attrib(format, "color", GL_FLOAT, 4, KEEP_FLOAT); + + glEnable(GL_BLEND); + GPU_enable_program_point_size(); + + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_SMOOTH); + + /* set handle size */ + immUniform1f("size", 2.0f * NODE_SOCKSIZE * xscale); // 2 * size to have diameter + + if (!select_all) { + /* outline for unselected sockets */ + immUniform1f("outlineWidth", 1.0f); + immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 0.6f); + + immBeginAtMost(GL_POINTS, BLI_listbase_count(&node->inputs) + BLI_listbase_count(&node->outputs)); + } + + /* socket inputs */ + short selected_input_ct = 0; + bNodeSocket *sock; + for (sock = node->inputs.first; sock; sock = sock->next) { + if (nodeSocketIsHidden(sock)) + continue; + if (select_all || (sock->flag & SELECT)) { + ++selected_input_ct; + continue; + } + + node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col); + } + + /* socket outputs */ + short selected_output_ct = 0; + if (draw_outputs) { + for (sock = node->outputs.first; sock; sock = sock->next) { + if (nodeSocketIsHidden(sock)) + continue; + if (select_all || (sock->flag & SELECT)) { + ++selected_output_ct; + continue; + } + + node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col); + } + } + + if (!select_all) { + immEnd(); + } + + /* go back and draw selected sockets */ + if (selected_input_ct + selected_output_ct > 0) { + /* outline for selected sockets */ + float c[3]; + UI_GetThemeColor3fv(TH_TEXT_HI, c); + immUniform4f("outlineColor", c[0], c[1], c[2], 1.0f); + immUniform1f("outlineWidth", 1.5f); + + immBegin(GL_POINTS, selected_input_ct + selected_output_ct); + + if (selected_input_ct) { + /* socket inputs */ + for (sock = node->inputs.first; sock; sock = sock->next) { + if (nodeSocketIsHidden(sock)) + continue; + if (select_all || (sock->flag & SELECT)) { + node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col); + if (--selected_input_ct == 0) + break; /* stop as soon as last one is drawn */ + } + } + } + + if (selected_output_ct) { + /* socket outputs */ + for (sock = node->outputs.first; sock; sock = sock->next) { + if (nodeSocketIsHidden(sock)) + continue; + if (select_all || (sock->flag & SELECT)) { + node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col); + if (--selected_output_ct == 0) + break; /* stop as soon as last one is drawn */ + } + } + } + + immEnd(); + } + + immUnbindProgram(); + + GPU_disable_program_point_size(); + glDisable(GL_BLEND); +} + static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key) { bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data; - bNodeSocket *sock; rctf *rct = &node->totr; float iconofs; /* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */ float iconbutw = 0.8f * UI_UNIT_X; int color_id = node_get_colorid(node); + float color[4]; char showname[128]; /* 128 used below */ View2D *v2d = &ar->v2d; @@ -798,7 +869,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN nodeSynchronizeID(node, false); /* skip if out of view */ - if (BLI_rctf_isect(&node->totr, &ar->v2d.cur, NULL) == false) { + if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) { UI_block_end(C, node->block); node->block = NULL; return; @@ -809,21 +880,20 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN /* header uses color from backdrop, but we make it opaqie */ if (color_id == TH_NODE) { - float col[3]; - UI_GetThemeColorShade3fv(color_id, -20, col); - glColor4f(col[0], col[1], col[2], 1.0f); + UI_GetThemeColorShade3fv(color_id, -20, color); } else - UI_ThemeColor(color_id); + UI_GetThemeColor4fv(color_id, color); if (node->flag & NODE_MUTED) - UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f); + UI_GetThemeColorBlendShade4fv(color_id, TH_REDALERT, 0.5f, 0, color); + #ifdef WITH_COMPOSITOR if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) { if (COM_isHighlightedbNode(node)) { - UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f); + UI_GetThemeColorBlendShade4fv(color_id, TH_ACTIVE, 0.5f, 0, color); } } #endif @@ -831,7 +901,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN glLineWidth(1.0f); UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); - UI_draw_roundbox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD); + UI_draw_roundbox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD, color); /* show/hide icons */ iconofs = rct->xmax - 0.35f * U.widget_unit; @@ -885,12 +955,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN UI_draw_icon_tri(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v'); } - /* this isn't doing anything for the label, so commenting out */ -#if 0 - if (node->flag & SELECT) - UI_ThemeColor(TH_TEXT_HI); - else - UI_ThemeColor(TH_TEXT); +#if 0 /* this isn't doing anything for the label, so commenting out */ + UI_ThemeColor((node->flag & SELECT) ? TH_TEXT_HI : TH_TEXT); #endif nodeLabel(ntree, node, showname, sizeof(showname)); @@ -905,30 +971,27 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN /* body */ if (!nodeIsRegistered(node)) - UI_ThemeColor4(TH_REDALERT); /* use warning color to indicate undefined types */ - else if (node->flag & NODE_CUSTOM_COLOR) - glColor3fv(node->color); + UI_GetThemeColor4fv(TH_REDALERT, color); /* use warning color to indicate undefined types */ + else if (node->flag & NODE_CUSTOM_COLOR) { + rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f); + } else - UI_ThemeColor4(TH_NODE); + UI_GetThemeColor4fv(TH_NODE, color); glEnable(GL_BLEND); UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT); - UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD); + UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD, color); glDisable(GL_BLEND); /* outline active and selected emphasis */ if (node->flag & SELECT) { - glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - - if (node->flag & NODE_ACTIVE) - UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40); - else - UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40); - + + UI_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color); + UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD); - + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color); + glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } @@ -937,23 +1000,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if (node->flag & NODE_MUTED) node_draw_mute_line(v2d, snode, node); - - /* socket inputs, buttons */ - for (sock = node->inputs.first; sock; sock = sock->next) { - if (nodeSocketIsHidden(sock)) - continue; - - node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); - } - - /* socket outputs */ - for (sock = node->outputs.first; sock; sock = sock->next) { - if (nodeSocketIsHidden(sock)) - continue; - - node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); - } - + node_draw_sockets(v2d, C, ntree, node, true, false); + /* preview */ if (node->flag & NODE_PREVIEW && previews) { bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key); @@ -973,13 +1021,16 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key)) { - bNodeSocket *sock; rctf *rct = &node->totr; float dx, centy = BLI_rctf_cent_y(rct); float hiddenrad = BLI_rctf_size_y(rct) / 2.0f; - float socket_size = NODE_SOCKSIZE; int color_id = node_get_colorid(node); + float color[4]; char showname[128]; /* 128 is used below */ + View2D *v2d = &ar->v2d; + float xscale, yscale; + + UI_view2d_scale_get(v2d, &xscale, &yscale); /* shadow */ node_draw_shadow(snode, node, hiddenrad, 1.0f); @@ -987,31 +1038,29 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b /* body */ UI_ThemeColor(color_id); if (node->flag & NODE_MUTED) - UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f); + UI_GetThemeColorBlendShade4fv(color_id, TH_REDALERT, 0.5f, 0, color); #ifdef WITH_COMPOSITOR if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) { if (COM_isHighlightedbNode(node)) { - UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f); + UI_GetThemeColorBlendShade4fv(color_id, TH_ACTIVE, 0.5f, 0, color); } } #else (void)ntree; #endif - UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad); + UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color); /* outline active and selected emphasis */ if (node->flag & SELECT) { glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - if (node->flag & NODE_ACTIVE) - UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40); - else - UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad); - + UI_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color); + + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color); + glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); } @@ -1021,8 +1070,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - glColor3fv(node->color); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad); + UI_draw_roundbox_gl_mode_3fvAlpha(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad, node->color, 1.0f); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); @@ -1053,12 +1101,9 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b /* disable lines */ if (node->flag & NODE_MUTED) node_draw_mute_line(&ar->v2d, snode, node); - - if (node->flag & SELECT) - UI_ThemeColor(TH_SELECT); - else - UI_ThemeColor(TH_TEXT); - + + UI_ThemeColor((node->flag & SELECT) ? TH_SELECT : TH_TEXT); + if (node->miniwidth > 0.0f) { nodeLabel(ntree, node, showname, sizeof(showname)); @@ -1082,17 +1127,8 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b fdrawline(rct->xmax - dx, centy - 4.0f, rct->xmax - dx, centy + 4.0f); fdrawline(rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f); - /* sockets */ - for (sock = node->inputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); - } - - for (sock = node->outputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); - } - + node_draw_sockets(v2d, C, ntree, node, true, false); + UI_block_end(C, node->block); UI_block_draw(C, node->block); node->block = NULL; @@ -1272,12 +1308,14 @@ static void draw_group_overlay(const bContext *C, ARegion *ar) View2D *v2d = &ar->v2d; rctf rect = v2d->cur; uiBlock *block; - + float color[4]; + /* shade node groups to separate them visually */ - UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70); glEnable(GL_BLEND); + + UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, -70, color); UI_draw_roundbox_corner_set(UI_CNR_NONE); - UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0); + UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0, color); glDisable(GL_BLEND); /* set the block bounds to clip mouse events from underlying nodes */ diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 6b8fa0b88fe..3b5d32a432a 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -67,12 +67,11 @@ void snode_group_offset(struct SpaceNode *snode, float *x, float *y); /* transfo /* node_draw.c */ int node_get_colorid(struct bNode *node); -void node_socket_circle_draw(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, - struct bNodeSocket *sock, float size, int highlight); int node_get_resize_cursor(int directions); void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha); void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *node, bNodeInstanceKey key); +void node_draw_sockets(struct View2D *v2d, const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, bool draw_outputs, bool select_all); void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); int node_select_area_default(struct bNode *node, int x, int y); int node_tweak_area_default(struct bNode *node, int x, int y); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 33a5a7ca7b7..18f4a02ab72 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -68,6 +68,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" + #include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" @@ -1385,13 +1387,14 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa float ufac = UI_UNIT_X / 20.0f; UI_draw_roundbox_corner_set(UI_CNR_ALL); - glColor4ub(255, 255, 255, 100); + float color[4] = {1.0f, 1.0f, 1.0f, 0.4f}; UI_draw_roundbox( (float) *offsx - 1.0f * ufac, (float)ys + 1.0f * ufac, (float)*offsx + UI_UNIT_X - 2.0f * ufac, (float)ys + UI_UNIT_Y - ufac, - (float)UI_UNIT_Y / 2.0f - ufac); + (float)UI_UNIT_Y / 2.0f - ufac, + color); glEnable(GL_BLEND); /* roundbox disables */ } @@ -1415,11 +1418,14 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty) { TreeElement *ten; - - /* store coord and continue, we need coordinates for elements outside view too */ - te->xs = startx; - te->ys = starty; - + + /* closed items may be displayed in row of parent, don't change their coordinate! */ + if ((te->flag & TE_ICONROW) == 0) { + /* store coord and continue, we need coordinates for elements outside view too */ + te->xs = startx; + te->ys = starty; + } + for (ten = te->subtree.first; ten; ten = ten->next) { outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty); } @@ -1435,12 +1441,12 @@ static void outliner_draw_tree_element( float ufac = UI_UNIT_X / 20.0f; int offsx = 0; eOLDrawState active = OL_DRAWSEL_NONE; - + float color[4]; tselem = TREESTORE(te); if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) { int xmax = ar->v2d.cur.xmax; - unsigned char alpha = 128; + float alpha = 0.5f; if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { *te_edit = te; @@ -1452,26 +1458,11 @@ static void outliner_draw_tree_element( glEnable(GL_BLEND); - /* start by highlighting search matches - * we don't expand items when searching in the datablocks but we - * still want to highlight any filter matches. - */ - if ((SEARCHING_OUTLINER(soops) || (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0)) && - (tselem->flag & TSE_SEARCHMATCH)) - { - char col[4]; - UI_GetThemeColorType4ubv(TH_MATCH, SPACE_OUTLINER, col); - col[3] = alpha; - glColor4ubv((GLubyte *)col); - glRecti(startx, *starty + 1, ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); - } - /* colors for active/selected data */ if (tselem->type == 0) { - if (te->idcode == ID_SCE) { if (tselem->id == (ID *)scene) { - glColor4ub(255, 255, 255, alpha); + rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); active = OL_DRAWSEL_ACTIVE; } } @@ -1480,8 +1471,7 @@ static void outliner_draw_tree_element( if (group_select_flag(gr)) { char col[4]; UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); - col[3] = alpha; - glColor4ubv((GLubyte *)col); + rgba_float_args_set(color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha); active = OL_DRAWSEL_ACTIVE; } @@ -1507,18 +1497,17 @@ static void outliner_draw_tree_element( UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); col[3] = alpha; } - - glColor4ubv((GLubyte *)col); + rgba_float_args_set(color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha); } } else if (scene->obedit && scene->obedit->data == tselem->id) { - glColor4ub(255, 255, 255, alpha); + rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); active = OL_DRAWSEL_ACTIVE; } else { if (tree_element_active(C, scene, soops, te, OL_SETSEL_NONE, false)) { - glColor4ub(220, 220, 255, alpha); + rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); active = OL_DRAWSEL_ACTIVE; } } @@ -1527,7 +1516,7 @@ static void outliner_draw_tree_element( if (tree_element_type_active(NULL, scene, soops, te, tselem, OL_SETSEL_NONE, false) != OL_DRAWSEL_NONE) { active = OL_DRAWSEL_ACTIVE; } - glColor4ub(220, 220, 255, alpha); + rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); } /* active circle */ @@ -1538,7 +1527,7 @@ static void outliner_draw_tree_element( (float)*starty + 1.0f * ufac, (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac, (float)*starty + UI_UNIT_Y - 1.0f * ufac, - UI_UNIT_Y / 2.0f - 1.0f * ufac); + UI_UNIT_Y / 2.0f - 1.0f * ufac, color); glEnable(GL_BLEND); /* roundbox disables it */ te->flag |= TE_ACTIVE; // for lookup in display hierarchies @@ -1654,7 +1643,7 @@ static void outliner_draw_tree_element( } } -static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx, int *starty) +static void outliner_draw_hierarchy_lines(SpaceOops *soops, ListBase *lb, int startx, int *starty) { TreeElement *te; TreeStoreElem *tselem; @@ -1674,7 +1663,7 @@ static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx, *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, soops)) - outliner_draw_hierarchy(soops, &te->subtree, startx + UI_UNIT_X, starty); + outliner_draw_hierarchy_lines(soops, &te->subtree, startx + UI_UNIT_X, starty); } /* vertical line */ @@ -1710,34 +1699,73 @@ static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase * } } -static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty) +static void outliner_draw_highlights_recursive( + const ARegion *ar, const SpaceOops *soops, const ListBase *lb, + const float col_selection[4], const float col_highlight[4], const float col_searchmatch[4], + int start_x, int *io_start_y) { - TreeElement *te; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - + const bool is_searching = SEARCHING_OUTLINER(soops) || + (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0); + + for (TreeElement *te = lb->first; te; te = te->next) { + const TreeStoreElem *tselem = TREESTORE(te); + const int start_y = *io_start_y; + /* selection status */ if (tselem->flag & TSE_SELECTED) { - glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); + glColor4fv(col_selection); + glRecti(0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); + } + + /* search match highlights + * we don't expand items when searching in the datablocks but we + * still want to highlight any filter matches. */ + if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) { + glColor4fv(col_searchmatch); + glRecti(start_x, start_y + 1, ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); + } + + /* mouse hover highlights */ + if (tselem->flag & TSE_HIGHLIGHTED) { + glColor4fv(col_highlight); + glRecti(0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); + } + + *io_start_y -= UI_UNIT_Y; + if (TSELEM_OPEN(tselem, soops)) { + outliner_draw_highlights_recursive( + ar, soops, &te->subtree, col_selection, col_highlight, col_searchmatch, + start_x + UI_UNIT_X, io_start_y); } - *starty -= UI_UNIT_Y; - if (TSELEM_OPEN(tselem, soops)) outliner_draw_selection(ar, soops, &te->subtree, starty); } } +static void outliner_draw_highlights(ARegion *ar, SpaceOops *soops, int startx, int *starty) +{ + const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; + float col_selection[4], col_searchmatch[4]; + + UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection); + col_selection[3] = 1.0f; /* no alpha */ + UI_GetThemeColor4fv(TH_MATCH, col_searchmatch); + col_searchmatch[3] = 0.5f; + + glEnable(GL_BLEND); + outliner_draw_highlights_recursive(ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch, + startx, starty); + glDisable(GL_BLEND); +} -static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, - SpaceOops *soops, TreeElement **te_edit) +static void outliner_draw_tree( + bContext *C, uiBlock *block, Scene *scene, ARegion *ar, + SpaceOops *soops, const bool has_restrict_icons, + TreeElement **te_edit) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - TreeElement *te; int starty, startx; - float col[3]; - + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once - + if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { /* struct marks */ UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); @@ -1745,25 +1773,39 @@ static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegio starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; outliner_draw_struct_marks(ar, soops, &soops->tree, &starty); } - - /* always draw selection fill before hierarchy */ - UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col); - glColor3fv(col); + + /* draw highlights before hierarchy */ starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; - outliner_draw_selection(ar, soops, &soops->tree, &starty); - + startx = 0; + outliner_draw_highlights(ar, soops, startx, &starty); + + /* set scissor so tree elements or lines can't overlap restriction icons */ + GLfloat scissor[4] = {0}; + if (has_restrict_icons) { + int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)OL_TOGW + 1; + CLAMP_MIN(mask_x, 0); + + glGetFloatv(GL_SCISSOR_BOX, scissor); + glScissor(ar->winrct.xmin, ar->winrct.ymin, mask_x, ar->winy); + } + // gray hierarchy lines UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.4f); starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET; startx = 6; - outliner_draw_hierarchy(soops, &soops->tree, startx, &starty); - + outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty); + // items themselves starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; startx = 0; - for (te = soops->tree.first; te; te = te->next) { + for (TreeElement *te = soops->tree.first; te; te = te->next) { outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, te, startx, &starty, te_edit); } + + if (has_restrict_icons) { + /* reset scissor */ + glScissor(UNPACK4(scissor)); + } } @@ -1771,34 +1813,36 @@ static void outliner_back(ARegion *ar) { int ystart; - UI_ThemeColorShade(TH_BACK, 6); ystart = (int)ar->v2d.tot.ymax; ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - - while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) { - glRecti(0, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y); - ystart -= 2 * UI_UNIT_Y; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, 6); + + const float x1 = 0.0f, x2 = ar->v2d.cur.xmax; + float y1 = ystart, y2; + int tot = (int)floor(ystart - ar->v2d.cur.ymin + 2 * UI_UNIT_Y) / (2 * UI_UNIT_Y); + + if (tot > 0) { + immBegin(GL_QUADS, 4 * tot); + while (tot--) { + y1 -= 2 * UI_UNIT_Y; + y2 = y1 + UI_UNIT_Y; + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x1, y2); + } + immEnd(); } + immUnbindProgram(); } static void outliner_draw_restrictcols(ARegion *ar) { - int ystart; - - /* background underneath */ - UI_ThemeColor(TH_BACK); - glRecti((int)(ar->v2d.cur.xmax - OL_TOGW), - (int)(ar->v2d.cur.ymin - 1), (int)ar->v2d.cur.xmax, (int)ar->v2d.cur.ymax); - - UI_ThemeColorShade(TH_BACK, 6); - ystart = (int)ar->v2d.tot.ymax; - ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - - while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) { - glRecti((int)ar->v2d.cur.xmax - OL_TOGW, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y); - ystart -= 2 * UI_UNIT_Y; - } - UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); /* view */ @@ -1833,6 +1877,7 @@ void draw_outliner(const bContext *C) uiBlock *block; int sizey = 0, sizex = 0, sizex_rna = 0; TreeElement *te_edit = NULL; + bool has_restrict_icons; outliner_build_tree(mainvar, scene, soops); // always @@ -1854,6 +1899,7 @@ void draw_outliner(const bContext *C) /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */ sizex = sizex_rna + OL_RNA_COL_SIZEX + 50; + has_restrict_icons = false; } else { /* width must take into account restriction columns (if visible) so that entries will still be visible */ @@ -1865,7 +1911,8 @@ void draw_outliner(const bContext *C) // XXX this isn't that great yet... if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) sizex += OL_TOGW * 3; - + + has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS); } /* adds vertical offset */ @@ -1882,19 +1929,19 @@ void draw_outliner(const bContext *C) /* draw outliner stuff (background, hierarchy lines and names) */ outliner_back(ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); - outliner_draw_tree((bContext *)C, block, scene, ar, soops, &te_edit); + outliner_draw_tree((bContext *)C, block, scene, ar, soops, has_restrict_icons, &te_edit); if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { /* draw rna buttons */ outliner_draw_rnacols(ar, sizex_rna); outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); } - else if ((soops->outlinevis == SO_ID_ORPHANS) && !(soops->flag & SO_HIDE_RESTRICTCOLS)) { + else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { /* draw user toggle columns */ outliner_draw_restrictcols(ar); outliner_draw_userbuts(block, ar, soops, &soops->tree); } - else if (!(soops->flag & SO_HIDE_RESTRICTCOLS)) { + else if (has_restrict_icons) { /* draw restriction columns */ outliner_draw_restrictcols(ar); outliner_draw_restrictbuts(block, scene, ar, soops, &soops->tree); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 345ac353c11..4dcdcc69d6d 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -148,8 +148,95 @@ TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2] return NULL; } +/** + * Try to find an item under y-coordinate \a view_co_y (view-space). + * \note Recursive + */ +TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y) +{ + for (TreeElement *te_iter = tree->first; te_iter; te_iter = te_iter->next) { + if (view_co_y < (te_iter->ys + UI_UNIT_Y)) { + if (view_co_y > te_iter->ys) { + /* co_y is inside this element */ + return te_iter; + } + else if (TSELEM_OPEN(te_iter->store_elem, soops)) { + /* co_y is lower than current element, possibly inside children */ + TreeElement *te_sub = outliner_find_item_at_y(soops, &te_iter->subtree, view_co_y); + if (te_sub) { + return te_sub; + } + } + } + } + + return NULL; +} + +/** + * Collapsed items can show their children as click-able icons. This function tries to find + * such an icon that represents the child item at x-coordinate \a view_co_x (view-space). + * + * \return a hovered child item or \a parent_te (if no hovered child found). + */ +TreeElement *outliner_find_item_at_x_in_row(const SpaceOops *soops, const TreeElement *parent_te, float view_co_x) +{ + if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) { /* if parent_te is opened, it doesn't show childs in row */ + /* no recursion, items can only display their direct children in the row */ + for (TreeElement *child_te = parent_te->subtree.first; + child_te && view_co_x >= child_te->xs; /* don't look further if co_x is smaller than child position*/ + child_te = child_te->next) + { + if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) && (view_co_x < child_te->xend)) { + return child_te; + } + } + } + + /* return parent if no child is hovered */ + return (TreeElement *)parent_te; +} + + /* ************************************************************** */ -/* Click Activated */ + +/* Highlight --------------------------------------------------- */ + +static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); + + TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my); + bool changed = false; + + if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) { + changed = outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false); + if (hovered_te) { + hovered_te->store_elem->flag |= TSE_HIGHLIGHTED; + changed = true; + } + } + + if (changed) { + soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */ + ED_region_tag_redraw(ar); + } + + return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); +} + +void OUTLINER_OT_highlight_update(wmOperatorType *ot) +{ + ot->name = "Update Highlight"; + ot->idname = "OUTLINER_OT_highlight_update"; + ot->description = "Update the item highlight based on the current mouse position"; + + ot->invoke = outliner_highlight_update; + + ot->poll = ED_operator_outliner_active; +} /* Toggle Open/Closed ------------------------------------------- */ @@ -740,17 +827,34 @@ int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel) return 0; } -void outliner_set_flag(ListBase *lb, short flag, short set) +/** + * Set or unset \a flag for all outliner elements in \a lb and sub-trees. + * \return if any flag was modified. + */ +bool outliner_set_flag(ListBase *lb, short flag, short set) { TreeElement *te; TreeStoreElem *tselem; - + bool changed = false; + bool has_flag; + for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); - if (set == 0) tselem->flag &= ~flag; - else tselem->flag |= flag; - outliner_set_flag(&te->subtree, flag, set); + has_flag = (tselem->flag & flag); + if (set == 0) { + if (has_flag) { + tselem->flag &= ~flag; + changed = true; + } + } + else if (!has_flag){ + tselem->flag |= flag; + changed = true; + } + changed |= outliner_set_flag(&te->subtree, flag, set); } + + return changed; } /* Restriction Columns ------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index ccc52f2dba8..f23c294c488 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -65,10 +65,14 @@ typedef struct TreeElement { ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF, ID_PAL)) /* Only in 'blendfile' mode ... :/ */ /* TreeElement->flag */ -#define TE_ACTIVE 1 -#define TE_ICONROW 2 -#define TE_LAZY_CLOSED 4 -#define TE_FREE_NAME 8 +enum { + TE_ACTIVE = (1 << 0), + /* Closed items display their children as icon within the row. TE_ICONROW is for + * these child-items that are visible but only within the row of the closed parent. */ + TE_ICONROW = (1 << 1), + TE_LAZY_CLOSED = (1 << 2), + TE_FREE_NAME = (1 << 3), +}; /* button events */ #define OL_NAMEBUTTON 1 @@ -150,7 +154,7 @@ eOLDrawState tree_element_type_active( TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive); eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, SpaceOops *soops, TreeElement *te, const eOLSetState set, const bool handle_all_types); -int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive); +int outliner_item_activate_or_toggle_closed(struct bContext *C, int x, int y, bool extend, bool recursive); /* outliner_edit.c ---------------------------------------------- */ typedef void (*outliner_operation_cb)( @@ -167,7 +171,7 @@ void outliner_do_object_operation( int common_restrict_check(struct bContext *C, struct Object *ob); int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel); -void outliner_set_flag(ListBase *lb, short flag, short set); +bool outliner_set_flag(ListBase *lb, short flag, short set); void object_toggle_visibility_cb( struct bContext *C, struct ReportList *reports, struct Scene *scene, @@ -208,8 +212,14 @@ void id_remap_cb( struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); + +TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y); +TreeElement *outliner_find_item_at_x_in_row(const SpaceOops *soops, const TreeElement *parent_te, float view_co_x); + /* ...................................................... */ +void OUTLINER_OT_highlight_update(struct wmOperatorType *ot); + void OUTLINER_OT_item_activate(struct wmOperatorType *ot); void OUTLINER_OT_item_openclose(struct wmOperatorType *ot); void OUTLINER_OT_item_rename(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 776717c8443..f0c2d848f7a 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -43,6 +43,7 @@ void outliner_operatortypes(void) { + WM_operatortype_append(OUTLINER_OT_highlight_update); WM_operatortype_append(OUTLINER_OT_item_activate); WM_operatortype_append(OUTLINER_OT_select_border); WM_operatortype_append(OUTLINER_OT_item_openclose); @@ -93,7 +94,9 @@ void outliner_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_find(keyconf, "Outliner", SPACE_OUTLINER, 0); wmKeyMapItem *kmi; - + + WM_keymap_add_item(keymap, "OUTLINER_OT_highlight_update", MOUSEMOVE, KM_ANY, KM_ANY, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0); kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, 0, 0); diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 89df471990a..a73e160f357 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -68,55 +68,6 @@ #include "outliner_intern.h" -/* ****************************************************** */ -/* Outliner Selection (gray-blue highlight for rows) */ - -static int outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting) -{ - TreeElement *te; - TreeStoreElem *tselem; - bool changed = false; - - for (te = lb->first; te && *index >= 0; te = te->next, (*index)--) { - tselem = TREESTORE(te); - - /* if we've encountered the right item, set its 'Outliner' selection status */ - if (*index == 0) { - /* this should be the last one, so no need to do anything with index */ - if ((te->flag & TE_ICONROW) == 0) { - /* -1 value means toggle testing for now... */ - if (*selecting == -1) { - if (tselem->flag & TSE_SELECTED) - *selecting = 0; - else - *selecting = 1; - } - - /* set selection */ - if (*selecting) - tselem->flag |= TSE_SELECTED; - else - tselem->flag &= ~TSE_SELECTED; - - changed |= true; - } - } - else if (TSELEM_OPEN(tselem, soops)) { - /* Only try selecting sub-elements if we haven't hit the right element yet - * - * Hack warning: - * Index must be reduced before supplying it to the sub-tree to try to do - * selection, however, we need to increment it again for the next loop to - * function correctly - */ - (*index)--; - changed |= outliner_select(soops, &te->subtree, index, selecting); - (*index)++; - } - } - - return changed; -} /* ****************************************************** */ /* Outliner Element Selection/Activation on Click */ @@ -886,163 +837,164 @@ eOLDrawState tree_element_type_active( /* ================================================ */ -static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, bool extend, bool recursive, const float mval[2]) +static void outliner_item_activate( + bContext *C, SpaceOops *soops, TreeElement *te, + const bool extend, const bool recursive) { - - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); - bool openclose = false; - - /* open close icon */ - if ((te->flag & TE_ICONROW) == 0) { // hidden icon, no open/close - if (mval[0] > te->xs && mval[0] < te->xs + UI_UNIT_X) - openclose = true; - } - - if (openclose) { - /* all below close/open? */ - if (extend) { - tselem->flag &= ~TSE_CLOSED; - outliner_set_flag(&te->subtree, TSE_CLOSED, !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1)); - } - else { - if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED; - else tselem->flag |= TSE_CLOSED; - + Scene *scene = CTX_data_scene(C); + TreeStoreElem *tselem = TREESTORE(te); + + /* always makes active object, except for some specific types. + * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want + * to switch out of edit mode (see T48328 for details). */ + if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) { + tree_element_set_active_object(C, scene, soops, te, + (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, + recursive && tselem->type == 0); + } + + if (tselem->type == 0) { // the lib blocks + /* editmode? */ + if (te->idcode == ID_SCE) { + if (scene != (Scene *)tselem->id) { + ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id); } - - return true; } - /* name and first icon */ - else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) { - - /* always makes active object, except for some specific types. - * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want - * to switch out of edit mode (see T48328 for details). */ - if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) { - tree_element_set_active_object(C, scene, soops, te, - (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive && tselem->type == 0); - } + else if (te->idcode == ID_GR) { + Group *gr = (Group *)tselem->id; + GroupObject *gob; - if (tselem->type == 0) { // the lib blocks - /* editmode? */ - if (te->idcode == ID_SCE) { - if (scene != (Scene *)tselem->id) { - ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id); - } - } - else if (te->idcode == ID_GR) { - Group *gr = (Group *)tselem->id; - GroupObject *gob; - - if (extend) { - int sel = BA_SELECT; - for (gob = gr->gobject.first; gob; gob = gob->next) { - if (gob->ob->flag & SELECT) { - sel = BA_DESELECT; - break; - } - } - - for (gob = gr->gobject.first; gob; gob = gob->next) { - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel); - } - } - else { - BKE_scene_base_deselect_all(scene); - - for (gob = gr->gobject.first; gob; gob = gob->next) { - if ((gob->ob->flag & SELECT) == 0) - ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_SELECT); - } + if (extend) { + int sel = BA_SELECT; + for (gob = gr->gobject.first; gob; gob = gob->next) { + if (gob->ob->flag & SELECT) { + sel = BA_DESELECT; + break; } - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { - WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); - } - else { // rest of types - tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, false); } + for (gob = gr->gobject.first; gob; gob = gob->next) { + ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel); + } } else { - tree_element_type_active(C, scene, soops, te, tselem, - extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive); + BKE_scene_base_deselect_all(scene); + + for (gob = gr->gobject.first; gob; gob = gob->next) { + if ((gob->ob->flag & SELECT) == 0) + ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_SELECT); + } } - return true; + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } - } - - for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, mval)) { - return true; + else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { + WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + } + else { // rest of types + tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, false); } + + } + else { + tree_element_type_active(C, scene, soops, te, tselem, + extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, + recursive); } - return false; } -int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recursive) +/** + * \param extend: Don't deselect other items, only modify \a te. + * \param toggle: Select \a te when not selected, deselect when selected. + */ +static void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle) +{ + TreeStoreElem *tselem = TREESTORE(te); + const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED); + + if (extend == false) { + outliner_set_flag(&soops->tree, TSE_SELECTED, false); + } + tselem->flag = new_flag; +} + +static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children) +{ + TreeStoreElem *tselem = TREESTORE(te); + if (toggle_children) { + tselem->flag &= ~TSE_CLOSED; + + const bool all_opened = !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1); + outliner_set_flag(&te->subtree, TSE_CLOSED, all_opened); + } + else { + tselem->flag ^= TSE_CLOSED; + } +} + +static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x) +{ + return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X); +} + +static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x) +{ + return (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && + !(soops->flag & SO_HIDE_RESTRICTCOLS) && + (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); +} + +int outliner_item_activate_or_toggle_closed(bContext *C, int x, int y, bool extend, bool recursive) { - Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); TreeElement *te; - float fmval[2]; + float view_mval[2]; + bool changed = false, rebuild_tree = false; - UI_view2d_region_to_view(&ar->v2d, x, y, &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, x, y, &view_mval[0], &view_mval[1]); - if (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && - !(soops->flag & SO_HIDE_RESTRICTCOLS) && - (fmval[0] > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)) - { + if (outliner_is_co_within_restrict_columns(soops, ar, view_mval[0])) { return OPERATOR_CANCELLED; } - for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, fmval)) break; + if (!(te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]))) { + /* skip */ } - - if (te) { - ED_undo_push(C, "Outliner click event"); + else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { + outliner_item_toggle_closed(te, extend); + changed = true; + rebuild_tree = true; } else { - short selecting = -1; - int row; - - /* get row number - 100 here is just a dummy value since we don't need the column */ - UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET, - fmval[0], fmval[1], NULL, &row); - - /* select relevant row */ - if (outliner_select(soops, &soops->tree, &row, &selecting)) { - + /* the row may also contain children, if one is hovered we want this instead of current te */ + TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]); + + outliner_item_select(soops, activate_te, extend, extend); + outliner_item_activate(C, soops, activate_te, extend, recursive); + changed = true; + } + + if (changed) { + if (!rebuild_tree) { + /* only needs to redraw, no rebuild */ soops->storeflag |= SO_TREESTORE_REDRAW; - - /* no need for undo push here, only changing outliner data which is - * scene level - campbell */ - /* ED_undo_push(C, "Outliner selection event"); */ } + ED_undo_push(C, "Outliner selection change"); + ED_region_tag_redraw(ar); } - - ED_region_tag_redraw(ar); return OPERATOR_FINISHED; } /* event can enterkey, then it opens/closes */ -static int outliner_item_activate(bContext *C, wmOperator *op, const wmEvent *event) +static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bool extend = RNA_boolean_get(op->ptr, "extend"); bool recursive = RNA_boolean_get(op->ptr, "recursive"); int x = event->mval[0]; int y = event->mval[1]; - return outliner_item_do_activate(C, x, y, extend, recursive); + return outliner_item_activate_or_toggle_closed(C, x, y, extend, recursive); } void OUTLINER_OT_item_activate(wmOperatorType *ot) @@ -1051,7 +1003,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot) ot->idname = "OUTLINER_OT_item_activate"; ot->description = "Handle mouse clicks to activate/select items"; - ot->invoke = outliner_item_activate; + ot->invoke = outliner_item_activate_invoke; ot->poll = ED_operator_outliner_active; diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 7739d241bd3..d6300b74aea 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -380,7 +380,7 @@ static void object_select_hierarchy_cb( wmWindow *win = CTX_wm_window(C); int x = win->eventstate->mval[0]; int y = win->eventstate->mval[1]; - outliner_item_do_activate(C, x, y, true, true); + outliner_item_activate_or_toggle_closed(C, x, y, true, true); } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index e1768e4aedc..d7771d06787 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -59,6 +59,7 @@ #include "BIF_glutil.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "ED_anim_api.h" #include "ED_gpencil.h" @@ -1048,30 +1049,31 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons /* border */ setlinestyle(3); - UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); - glBegin(GL_LINE_LOOP); - glVertex2f(x1 - 0.5f, y1 - 0.5f); - glVertex2f(x1 - 0.5f, y2 + 0.5f); - glVertex2f(x2 + 0.5f, y2 + 0.5f); - glVertex2f(x2 + 0.5f, y1 - 0.5f); - glEnd(); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_BACK); + + imm_draw_line_box(pos, x1 - 0.5f, y1 - 0.5f, x2 + 0.5f, y2 + 0.5f); /* safety border */ if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) { UI_draw_safe_areas( - x1, x2, y1, y2, + pos, x1, x2, y1, y2, scene->safe_areas.title, scene->safe_areas.action); if (sseq->flag & SEQ_SHOW_SAFE_CENTER) { UI_draw_safe_areas( - x1, x2, y1, y2, + pos, x1, x2, y1, y2, scene->safe_areas.title_center, scene->safe_areas.action_center); } } + immUnbindProgram(); + setlinestyle(0); } diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 81605a80f69..30b607e063d 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -906,7 +906,7 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back) { bTheme *btheme = UI_GetTheme(); uiWidgetColors wcol = btheme->tui.wcol_scroll; - unsigned char col[4]; + float col[4]; float rad; UI_ThemeColor(TH_BACK); @@ -916,11 +916,10 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back) UI_draw_roundbox_corner_set(UI_CNR_ALL); rad = 0.4f * min_ii(BLI_rcti_size_x(&st->txtscroll), BLI_rcti_size_y(&st->txtscroll)); - UI_GetThemeColor3ubv(TH_HILITE, col); - col[3] = 48; - glColor4ubv(col); + UI_GetThemeColor3fv(TH_HILITE, col); + col[3] = 0.18f; glEnable(GL_BLEND); - UI_draw_roundbox(st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad); + UI_draw_roundbox(st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad, col); glDisable(GL_BLEND); } diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 15eb154c757..5e7060d6651 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -69,6 +69,8 @@ #include "ED_space_api.h" #include "ED_markers.h" +#include "GPU_immediate.h" + #include "time_intern.h" /* ************************ main time area region *********************** */ @@ -80,21 +82,36 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d) */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); + if (PSFRA < PEFRA) { - glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); - glRectf((float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); + immRectf(pos, (float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } else { - glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); } + glDisable(GL_BLEND); - UI_ThemeColorShade(TH_BACK, -60); /* thin lines where the actual frames are */ - fdrawline((float)PSFRA, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); - fdrawline((float)PEFRA, v2d->cur.ymin, (float)PEFRA, v2d->cur.ymax); + immUniformThemeColorShade(TH_BACK, -60); + + immBegin(GL_LINES, 4); + + immVertex2f(pos, (float)PSFRA, v2d->cur.ymin); + immVertex2f(pos, (float)PSFRA, v2d->cur.ymax); + + immVertex2f(pos, (float)PEFRA, v2d->cur.ymin); + immVertex2f(pos, (float)PEFRA, v2d->cur.ymax); + + immEnd(); + immUnbindProgram(); } static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) @@ -296,7 +313,7 @@ static ActKeyColumn *time_cfra_find_ak(ActKeyColumn *ak, float cframe) } /* helper for time_draw_keyframes() */ -static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) +static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel, const unsigned char color[3]) { bDopeSheet ads = {NULL}; DLRBT_Tree keys; @@ -339,21 +356,42 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) * the first visible keyframe (last one can then be easily checked) * - draw within a single GL block to be faster */ - glBegin(GL_LINES); - for (ak = time_cfra_find_ak(keys.root, v2d->cur.xmin); - (ak) && (ak->cfra <= v2d->cur.xmax); - ak = ak->next) - { - glVertex2f(ak->cfra, ymin); - glVertex2f(ak->cfra, ymax); + + ActKeyColumn *link; + int max_len = 0; + + ak = time_cfra_find_ak(keys.root, v2d->cur.xmin); + + for (link = ak; link; link = link->next) { + max_len++; } - glEnd(); // GL_LINES - + + if (max_len > 0) { + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3ubv(color); + + immBeginAtMost(GL_LINES, max_len * 2); + + for (; (ak) && (ak->cfra <= v2d->cur.xmax); + ak = ak->next) + { + immVertex2f(pos, ak->cfra, ymin); + immVertex2f(pos, ak->cfra, ymax); + } + + immEnd(); + immUnbindProgram(); + } + /* free temp stuff */ BLI_dlrbTree_free(&keys); } -static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel) +static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel, const unsigned char color[3]) { CacheFile *cache_file; @@ -380,7 +418,7 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN; - time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color); } for (bConstraint *con = ob->constraints.first; con; con = con->next) { @@ -398,7 +436,7 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN; - time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color); } } } @@ -410,21 +448,23 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) Object *ob = CTX_data_active_object(C); View2D *v2d = &ar->v2d; bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0); + unsigned char color[3]; /* set this for all keyframe lines once and for all */ glLineWidth(1.0); /* draw cache files keyframes (if available) */ - UI_ThemeColor(TH_TIME_KEYFRAME); - time_draw_caches_keyframes(CTX_data_main(C), scene, v2d, onlysel); + UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color); + time_draw_caches_keyframes(CTX_data_main(C), scene, v2d, onlysel, color); /* draw grease pencil keyframes (if available) */ - UI_ThemeColor(TH_TIME_GP_KEYFRAME); + UI_GetThemeColor3ubv(TH_TIME_GP_KEYFRAME, color); + if (scene->gpd) { - time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel, color); } if (ob && ob->gpd) { - time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel, color); } /* draw scene keyframes first @@ -433,8 +473,8 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) */ if (onlysel == 0) { /* set draw color */ - UI_ThemeColorShade(TH_TIME_KEYFRAME, -50); - time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel); + UI_GetThemeColorShade3ubv(TH_TIME_KEYFRAME, -50, color); + time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel, color); } /* draw keyframes from selected objects @@ -442,11 +482,11 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) * OR the onlysel flag was set, which means that only active object's keyframes should * be considered */ - UI_ThemeColor(TH_TIME_KEYFRAME); - + UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color); + if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) { /* draw keyframes for active object only */ - time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel); + time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel, color); } else { bool active_done = false; @@ -455,7 +495,7 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) CTX_DATA_BEGIN (C, Object *, obsel, selected_objects) { /* last arg is 0, since onlysel doesn't apply here... */ - time_draw_idblock_keyframes(v2d, (ID *)obsel, 0); + time_draw_idblock_keyframes(v2d, (ID *)obsel, 0, color); /* if this object is the active one, set flag so that we don't draw again */ if (obsel == ob) @@ -465,7 +505,7 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) /* if active object hasn't been done yet, draw it... */ if (ob && (active_done == 0)) - time_draw_idblock_keyframes(v2d, (ID *)ob, 0); + time_draw_idblock_keyframes(v2d, (ID *)ob, 0, color); } } diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index a5c60248bf1..8fca2ed564e 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -52,6 +52,7 @@ set(SRC view3d_buttons.c view3d_camera_control.c view3d_draw.c + view3d_draw_legacy.c view3d_edit.c view3d_fly.c view3d_walk.c diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 95a2df68e4a..7ac176f82b1 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -2161,11 +2161,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, bone_matrix_translate_y(bmat, pchan->bone->length); glMultMatrixf(bmat); - glColor3ubv(col); - float viewmat_pchan[4][4]; mul_m4_m4m4(viewmat_pchan, rv3d->viewmatob, bmat); - drawaxes(viewmat_pchan, pchan->bone->length * 0.25f, OB_ARROWS); + drawaxes(viewmat_pchan, pchan->bone->length * 0.25f, OB_ARROWS, col); glPopMatrix(); } @@ -2370,11 +2368,9 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) bone_matrix_translate_y(bmat, eBone->length); glMultMatrixf(bmat); - glColor3ubv(col); - float viewmat_ebone[4][4]; mul_m4_m4m4(viewmat_ebone, rv3d->viewmatob, bmat); - drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS); + drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS, col); glPopMatrix(); } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 90d33dc5995..46d682233ed 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -90,6 +90,9 @@ #include "GPU_select.h" #include "GPU_basic_shader.h" #include "GPU_shader.h" +#include "GPU_immediate.h" +#include "GPU_batch.h" +#include "GPU_matrix.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -105,6 +108,9 @@ #include "view3d_intern.h" /* bad level include */ +/* prototypes */ +static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos); + /* Workaround for sequencer scene render mode. * * Strips doesn't use DAG to update objects or so, which @@ -208,12 +214,346 @@ typedef struct drawBMSelect_userData { bool select; } drawBMSelect_userData; -static void draw_bounding_volume(Object *ob, char type); +typedef struct { + VertexBuffer *pos_in_order; + ElementList *edges_in_order; + ElementList *triangles_in_order; + + Batch *all_verts; + Batch *all_edges; + Batch *all_triangles; + + Batch *fancy_edges; /* owns its vertex buffer (not shared) */ + Batch *overlay_edges; /* owns its vertex buffer */ +} MeshBatchCache; + +static void MBC_discard(MeshBatchCache *cache) +{ + if (cache->all_verts) Batch_discard(cache->all_verts); + if (cache->all_edges) Batch_discard(cache->all_edges); + if (cache->all_triangles) Batch_discard(cache->all_triangles); + + if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order); + if (cache->edges_in_order) ElementList_discard(cache->edges_in_order); + if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order); + + if (cache->fancy_edges) { + Batch_discard_all(cache->fancy_edges); + } + + if (cache->overlay_edges) { + Batch_discard_all(cache->overlay_edges); + } + + MEM_freeN(cache); +} + +static MeshBatchCache *MBC_get(DerivedMesh *dm) +{ + if (dm->batchCache == NULL) { + /* create cache */ + dm->batchCache = MEM_callocN(sizeof(MeshBatchCache), "MeshBatchCache"); + /* init everything to 0 is ok for now */ + + + /* tell DerivedMesh how to clean up these caches (just once) */ + /* TODO: find a better place for this w/out exposing internals to DM */ + /* TODO (long term): replace DM with something less messy */ + static bool first = true; + if (first) { + DM_set_batch_cleanup_callback((DMCleanupBatchCache)MBC_discard); + first = false; + } + } + + return dm->batchCache; +} + +static VertexBuffer *MBC_get_pos_in_order(DerivedMesh *dm) +{ + MeshBatchCache *cache = MBC_get(dm); + + if (cache->pos_in_order == NULL) { + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + const int vertex_ct = dm->getNumVerts(dm); + const MVert *verts = dm->getVertArray(dm); + const unsigned stride = (verts + 1) - verts; /* or sizeof(MVert) */ + + cache->pos_in_order = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(cache->pos_in_order, vertex_ct); +#if 0 + fillAttribStride(cache->pos_in_order, pos_id, stride, &verts[0].co); +#else + for (int i = 0; i < vertex_ct; ++i) { + setAttrib(cache->pos_in_order, pos_id, i, &verts[i].co); + } +#endif + } + + return cache->pos_in_order; +} + +static Batch *MBC_get_all_verts(DerivedMesh *dm) +{ + MeshBatchCache *cache = MBC_get(dm); + + if (cache->all_verts == NULL) { + /* create batch from DM */ + cache->all_verts = Batch_create(GL_POINTS, MBC_get_pos_in_order(dm), NULL); + Batch_set_builtin_program(cache->all_verts, GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + } + + return cache->all_verts; +} + +static ElementList *MBC_get_edges_in_order(DerivedMesh *dm) +{ + MeshBatchCache *cache = MBC_get(dm); + + if (cache->edges_in_order == NULL) { + const int vertex_ct = dm->getNumVerts(dm); + const int edge_ct = dm->getNumEdges(dm); + const MEdge *edges = dm->getEdgeArray(dm); + ElementListBuilder elb; + ElementListBuilder_init(&elb, GL_LINES, edge_ct, vertex_ct); + for (int i = 0; i < edge_ct; ++i) { + const MEdge *edge = edges + i; + add_line_vertices(&elb, edge->v1, edge->v2); + } + cache->edges_in_order = ElementList_build(&elb); + } + + return cache->edges_in_order; +} + +static ElementList *MBC_get_triangles_in_order(DerivedMesh *dm) +{ + MeshBatchCache *cache = MBC_get(dm); + + if (cache->triangles_in_order == NULL) { + const int vertex_ct = dm->getNumVerts(dm); + const int tessface_ct = dm->getNumTessFaces(dm); + const MFace *tessfaces = dm->getTessFaceArray(dm); + ElementListBuilder elb; + ElementListBuilder_init(&elb, GL_TRIANGLES, tessface_ct, vertex_ct); + for (int i = 0; i < tessface_ct; ++i) { + const MFace *tess = tessfaces + i; + add_triangle_vertices(&elb, tess->v1, tess->v2, tess->v3); + /* tessface can be triangle or quad */ + if (tess->v4) { + add_triangle_vertices(&elb, tess->v3, tess->v2, tess->v4); + } + } + cache->triangles_in_order = ElementList_build(&elb); + } + + return cache->triangles_in_order; +} + +static Batch *MBC_get_all_edges(DerivedMesh *dm) +{ + MeshBatchCache *cache = MBC_get(dm); + + if (cache->all_edges == NULL) { + /* create batch from DM */ + cache->all_edges = Batch_create(GL_LINES, MBC_get_pos_in_order(dm), MBC_get_edges_in_order(dm)); + } + + return cache->all_edges; +} + +static Batch *MBC_get_all_triangles(DerivedMesh *dm) +{ + MeshBatchCache *cache = MBC_get(dm); + + if (cache->all_triangles == NULL) { + /* create batch from DM */ + cache->all_triangles = Batch_create(GL_TRIANGLES, MBC_get_pos_in_order(dm), MBC_get_triangles_in_order(dm)); + } + + return cache->all_triangles; +} + +static Batch *MBC_get_fancy_edges(DerivedMesh *dm) +{ + MeshBatchCache *cache = MBC_get(dm); + + if (cache->fancy_edges == NULL) { + /* create batch from DM */ + static VertexFormat format = { 0 }; + static unsigned pos_id, n1_id, n2_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + +#if USE_10_10_10 /* takes 1/3 the space */ + n1_id = add_attrib(&format, "N1", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); + n2_id = add_attrib(&format, "N2", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); +#else + n1_id = add_attrib(&format, "N1", COMP_F32, 3, KEEP_FLOAT); + n2_id = add_attrib(&format, "N2", COMP_F32, 3, KEEP_FLOAT); +#endif + } + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + + const MVert *verts = dm->getVertArray(dm); + const MEdge *edges = dm->getEdgeArray(dm); + const MPoly *polys = dm->getPolyArray(dm); + const MLoop *loops = dm->getLoopArray(dm); + const int edge_ct = dm->getNumEdges(dm); + const int poly_ct = dm->getNumPolys(dm); + + /* need normal of each face, and which faces are adjacent to each edge */ + typedef struct { + int count; + int face_index[2]; + } AdjacentFaces; + + float (*face_normal)[3] = MEM_mallocN(poly_ct * 3 * sizeof(float), "face_normal"); + AdjacentFaces *adj_faces = MEM_callocN(edge_ct * sizeof(AdjacentFaces), "adj_faces"); + + for (int i = 0; i < poly_ct; ++i) { + const MPoly *poly = polys + i; + + BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, verts, face_normal[i]); + + for (int j = poly->loopstart; j < (poly->loopstart + poly->totloop); ++j) { + AdjacentFaces *adj = adj_faces + loops[j].e; + if (adj->count < 2) + adj->face_index[adj->count] = i; + adj->count++; + } + } + + const int vertex_ct = edge_ct * 2; /* these are GL_LINE verts, not mesh verts */ + VertexBuffer_allocate_data(vbo, vertex_ct); + for (int i = 0; i < edge_ct; ++i) { + const MEdge *edge = edges + i; + const AdjacentFaces *adj = adj_faces + i; + +#if USE_10_10_10 + PackedNormal n1value = { .x = 0, .y = 0, .z = +511 }; + PackedNormal n2value = { .x = 0, .y = 0, .z = -511 }; + + if (adj->count == 2) { + n1value = convert_i10_v3(face_normal[adj->face_index[0]]); + n2value = convert_i10_v3(face_normal[adj->face_index[1]]); + } + + const PackedNormal *n1 = &n1value; + const PackedNormal *n2 = &n2value; +#else + const float dummy1[3] = { 0.0f, 0.0f, +1.0f }; + const float dummy2[3] = { 0.0f, 0.0f, -1.0f }; + + const float *n1 = (adj->count == 2) ? face_normal[adj->face_index[0]] : dummy1; + const float *n2 = (adj->count == 2) ? face_normal[adj->face_index[1]] : dummy2; +#endif + + setAttrib(vbo, pos_id, 2 * i, &verts[edge->v1].co); + setAttrib(vbo, n1_id, 2 * i, n1); + setAttrib(vbo, n2_id, 2 * i, n2); + + setAttrib(vbo, pos_id, 2 * i + 1, &verts[edge->v2].co); + setAttrib(vbo, n1_id, 2 * i + 1, n1); + setAttrib(vbo, n2_id, 2 * i + 1, n2); + } + + MEM_freeN(adj_faces); + MEM_freeN(face_normal); + + cache->fancy_edges = Batch_create(GL_LINES, vbo, NULL); + } + + return cache->fancy_edges; +} + +static bool edge_is_real(const MEdge *edges, int edge_ct, int v1, int v2) +{ + /* TODO: same thing, except not ridiculously slow */ + + for (int e = 0; e < edge_ct; ++e) { + const MEdge *edge = edges + e; + if ((edge->v1 == v1 && edge->v2 == v2) || (edge->v1 == v2 && edge->v2 == v1)) { + return true; + } + } + + return false; +} + +static void add_overlay_tri(VertexBuffer *vbo, unsigned pos_id, unsigned edgeMod_id, const MVert *verts, const MEdge *edges, int edge_ct, int v1, int v2, int v3, int base_vert_idx) +{ + const float edgeMods[2] = { 0.0f, 1.0f }; + + const float *pos = verts[v1].co; + setAttrib(vbo, pos_id, base_vert_idx + 0, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 0, edgeMods + (edge_is_real(edges, edge_ct, v2, v3) ? 1 : 0)); + + pos = verts[v2].co; + setAttrib(vbo, pos_id, base_vert_idx + 1, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 1, edgeMods + (edge_is_real(edges, edge_ct, v3, v1) ? 1 : 0)); + + pos = verts[v3].co; + setAttrib(vbo, pos_id, base_vert_idx + 2, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 2, edgeMods + (edge_is_real(edges, edge_ct, v1, v2) ? 1 : 0)); +} + +static Batch *MBC_get_overlay_edges(DerivedMesh *dm) +{ + MeshBatchCache *cache = MBC_get(dm); + + if (cache->overlay_edges == NULL) { + /* create batch from DM */ + static VertexFormat format = { 0 }; + static unsigned pos_id, edgeMod_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + edgeMod_id = add_attrib(&format, "edgeWidthModulator", GL_FLOAT, 1, KEEP_FLOAT); + } + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + + const int vertex_ct = dm->getNumVerts(dm); + const int edge_ct = dm->getNumEdges(dm); + const int tessface_ct = dm->getNumTessFaces(dm); + const MVert *verts = dm->getVertArray(dm); + const MEdge *edges = dm->getEdgeArray(dm); + const MFace *tessfaces = dm->getTessFaceArray(dm); + + VertexBuffer_allocate_data(vbo, tessface_ct * 6); /* up to 2 triangles per tessface */ + + int gpu_vert_idx = 0; + for (int i = 0; i < tessface_ct; ++i) { + const MFace *tess = tessfaces + i; + add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v1, tess->v2, tess->v3, gpu_vert_idx); + gpu_vert_idx += 3; + /* tessface can be triangle or quad */ + if (tess->v4) { + add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v3, tess->v2, tess->v4, gpu_vert_idx); + gpu_vert_idx += 3; + } + } + + VertexBuffer_resize_data(vbo, gpu_vert_idx); + + cache->overlay_edges = Batch_create(GL_TRIANGLES, vbo, NULL); + } + + return cache->overlay_edges; +} + +static void drawcube_size(float size, unsigned pos); +static void drawcircle_size(float size, unsigned pos); +static void draw_empty_sphere(float size, unsigned pos); +static void draw_empty_cone(float size, unsigned pos); -static void drawcube_size(float size); -static void drawcircle_size(float size); -static void draw_empty_sphere(float size); -static void draw_empty_cone(float size); static void draw_box(const float vec[8][3], bool solid); static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac) @@ -414,7 +754,7 @@ static const float cosval[CIRCLE_RESOL] = { * \param viewmat_local_unit is typically the 'rv3d->viewmatob' * copied into a 3x3 matrix and normalized. */ -static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis) +static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis, unsigned pos) { int line_type; float buffer[4][3]; @@ -501,54 +841,67 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3] return; } + immBegin(line_type, n); for (int i = 0; i < n; i++) { mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]); add_v3_v3(buffer[i], c); + immVertex3fv(pos, buffer[i]); } + immEnd(); + /* TODO: recode this function for clarity once we're not in a hurry to modernize GL usage */ + +#if 0 glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, buffer); glDrawArrays(line_type, 0, n); glDisableClientState(GL_VERTEX_ARRAY); +#endif } -void drawaxes(const float viewmat_local[4][4], float size, char drawtype) +void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4]) { int axis; float v1[3] = {0.0, 0.0, 0.0}; float v2[3] = {0.0, 0.0, 0.0}; float v3[3] = {0.0, 0.0, 0.0}; - glLineWidth(1); + glLineWidth(1.0f); - switch (drawtype) { + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + if (color) { + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4ubv(color); + } + else { + immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY); + } + switch (drawtype) { case OB_PLAINAXES: + immBegin(GL_LINES, 6); for (axis = 0; axis < 3; axis++) { - glBegin(GL_LINES); - v1[axis] = size; v2[axis] = -size; - glVertex3fv(v1); - glVertex3fv(v2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); /* reset v1 & v2 to zero */ v1[axis] = v2[axis] = 0.0f; - - glEnd(); } + immEnd(); break; - case OB_SINGLE_ARROW: - glBegin(GL_LINES); + case OB_SINGLE_ARROW: + immBegin(GL_LINES, 2); /* in positive z direction only */ v1[2] = size; - glVertex3fv(v1); - glVertex3fv(v2); - glEnd(); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); /* square pyramid */ - glBegin(GL_TRIANGLES); + immBegin(GL_TRIANGLES, 12); v2[0] = size * 0.035f; v2[1] = size * 0.035f; v3[0] = size * -0.035f; v3[1] = size * 0.035f; @@ -564,28 +917,27 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype) v3[0] = -v3[0]; } - glVertex3fv(v1); - glVertex3fv(v2); - glVertex3fv(v3); - + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immVertex3fv(pos, v3); } - glEnd(); - + immEnd(); break; + case OB_CUBE: - drawcube_size(size); + drawcube_size(size, pos); break; case OB_CIRCLE: - drawcircle_size(size); + drawcircle_size(size, pos); break; case OB_EMPTY_SPHERE: - draw_empty_sphere(size); + draw_empty_sphere(size, pos); break; case OB_EMPTY_CONE: - draw_empty_cone(size); + draw_empty_cone(size, pos); break; case OB_ARROWS: @@ -599,34 +951,34 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype) for (axis = 0; axis < 3; axis++) { const int arrow_axis = (axis == 0) ? 1 : 0; - glBegin(GL_LINES); + immBegin(GL_LINES, 6); v2[axis] = size; - glVertex3fv(v1); - glVertex3fv(v2); - + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + v1[axis] = size * 0.85f; v1[arrow_axis] = -size * 0.08f; - glVertex3fv(v1); - glVertex3fv(v2); - + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + v1[arrow_axis] = size * 0.08f; - glVertex3fv(v1); - glVertex3fv(v2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); - glEnd(); - - v2[axis] += size * 0.125f; + immEnd(); - draw_xyz_wire(viewmat_local_unit, v2, size, axis); + v2[axis] += size * 0.125f; + draw_xyz_wire(viewmat_local_unit, v2, size, axis, pos); /* reset v1 & v2 to zero */ v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f; } - break; } } + + immUnbindProgram(); } @@ -634,102 +986,111 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype) static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview) { Image *ima = ob->data; - ImBuf *ibuf; - ImageUser iuser = *ob->iuser; - /* Support multi-view */ - if (ima && (sview == STEREO_RIGHT_ID)) { - iuser.multiview_eye = sview; - iuser.flag |= IMA_SHOW_STEREO; - BKE_image_multiview_index(ima, &iuser); - } + const float ob_alpha = ob->col[3]; + float width, height; - ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); + int bindcode = 0; - if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) { - IMB_rect_from_float(ibuf); - } + if (ima) { + ImageUser iuser = *ob->iuser; - int ima_x, ima_y; + /* Support multi-view */ + if (ima && (sview == STEREO_RIGHT_ID)) { + iuser.multiview_eye = sview; + iuser.flag |= IMA_SHOW_STEREO; + BKE_image_multiview_index(ima, &iuser); + } - /* Get the buffer dimensions so we can fallback to fake ones */ - if (ibuf && ibuf->rect) { - ima_x = ibuf->x; - ima_y = ibuf->y; + if (ob_alpha > 0.0f) { + bindcode = GPU_verify_image(ima, &iuser, GL_TEXTURE_2D, 0, false, false, false); + /* don't bother drawing the image if alpha = 0 */ + } + + int w, h; + BKE_image_get_size(ima, &iuser, &w, &h); + width = w; + height = h; } else { - ima_x = 1; - ima_y = 1; + /* if no image, make it a 1x1 empty square, honor scale & offset */ + width = height = 1.0f; } - float sca_x = 1.0f; - float sca_y = 1.0f; + const float aspect = height / width; - /* Get the image aspect even if the buffer is invalid */ - if (ima) { - if (ima->aspx > ima->aspy) { - sca_y = ima->aspy / ima->aspx; - } - else if (ima->aspx < ima->aspy) { - sca_x = ima->aspx / ima->aspy; - } - } + float left = ob->ima_ofs[0]; + float right = ob->ima_ofs[0] + ob->empty_drawsize; + float top = ob->ima_ofs[1] + ob->empty_drawsize * aspect; + float bottom = ob->ima_ofs[1]; - /* Calculate the scale center based on object's origin */ - float ofs_x = ob->ima_ofs[0] * ima_x; - float ofs_y = ob->ima_ofs[1] * ima_y; + bool use_blend = false; - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); + if (bindcode) { + use_blend = ob_alpha < 1.0f || BKE_image_has_alpha(ima); - /* Calculate Image scale */ - float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y); + if (use_blend) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - /* Set the object scale */ - glScalef(scale * sca_x, scale * sca_y, 1.0f); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + unsigned texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + immUniform1f("alpha", ob_alpha); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ - if (ibuf && ibuf->rect) { - const bool use_clip = (U.glalphaclip != 1.0f); - int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP) ? GL_NEAREST : GL_LINEAR; - /* Setup GL params */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + immBegin(GL_TRIANGLE_FAN, 4); + immAttrib2f(texCoord, 0.0f, 0.0f); + immVertex2f(pos, left, bottom); - if (use_clip) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); - } + immAttrib2f(texCoord, 1.0f, 0.0f); + immVertex2f(pos, right, bottom); - /* Use the object color and alpha */ - glColor4fv(ob->col); + immAttrib2f(texCoord, 1.0f, 1.0f); + immVertex2f(pos, right, top); - /* Draw the Image on the screen */ - glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect); + immAttrib2f(texCoord, 0.0f, 1.0f); + immVertex2f(pos, left, top); + immEnd(); - glDisable(GL_BLEND); + immUnbindProgram(); - if (use_clip) { - glDisable(GL_ALPHA_TEST); - glAlphaFunc(GL_ALWAYS, 0.0f); - } + glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */ } - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); + /* Draw the image outline */ + glLineWidth(1.5f); + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_FLOAT); + + const bool picking = dflag & DRAW_CONSTCOLOR; + if (picking) { + /* TODO: deal with picking separately, use this function just to draw */ + immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY); + if (use_blend) { + glDisable(GL_BLEND); + } + + imm_draw_line_box(pos, left, bottom, right, top); } + else { + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ubv(ob_wire_col); + glEnable(GL_LINE_SMOOTH); - /* Calculate the outline vertex positions */ - glBegin(GL_LINE_LOOP); - glVertex2f(ofs_x, ofs_y); - glVertex2f(ofs_x + ima_x, ofs_y); - glVertex2f(ofs_x + ima_x, ofs_y + ima_y); - glVertex2f(ofs_x, ofs_y + ima_y); - glEnd(); + if (!use_blend) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - /* Reset GL settings */ - glPopMatrix(); + imm_draw_line_box(pos, left, bottom, right, top); - BKE_image_release_ibuf(ima, ibuf, NULL); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); + } + + immUnbindProgram(); } static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4]) @@ -759,50 +1120,65 @@ void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][ glDisableClientState(GL_VERTEX_ARRAY); } +static void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos) +{ + float verts[CIRCLE_RESOL][3]; + + circball_array_fill(verts, cent, rad, tmat); + + immBegin(GL_LINE_LOOP, CIRCLE_RESOL); + for (int i = 0; i < CIRCLE_RESOL; ++i) { + immVertex3fv(pos, verts[i]); + } + immEnd(); +} + /* circle for object centers, special_color is for library or ob users */ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color) { - const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f; - float verts[CIRCLE_RESOL][3]; + const float outlineWidth = 1.0f * U.pixelsize; + const float size = U.obcenter_dia * U.pixelsize + outlineWidth; + + if (v3d->zbuf) { + glDisable(GL_DEPTH_TEST); + /* TODO(merwin): fit things like this into plates/buffers design */ + } - /* using glDepthFunc guarantees that it does write z values, - * but not checks for it, so centers remain visible independent of draw order */ - if (v3d->zbuf) glDepthFunc(GL_ALWAYS); - /* write to near buffer always */ - glDepthRange(0.0, 0.0); glEnable(GL_BLEND); - + GPU_enable_program_point_size(); + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + immUniform1f("size", size); + if (special_color) { - if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155); - else glColor4ub(0x55, 0xCC, 0xCC, 155); + if (selstate == ACTIVE || selstate == SELECT) immUniformColor4ub(0x88, 0xFF, 0xFF, 155); + else immUniformColor4ub(0x55, 0xCC, 0xCC, 155); } else { - if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80); - else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80); - else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80); + if (selstate == ACTIVE) immUniformThemeColorShadeAlpha(TH_ACTIVE, 0, -80); + else if (selstate == SELECT) immUniformThemeColorShadeAlpha(TH_SELECT, 0, -80); + else if (selstate == DESELECT) immUniformThemeColorShadeAlpha(TH_TRANSFORM, 0, -80); } - circball_array_fill(verts, co, size, rv3d->viewinv); - - /* enable vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, verts); - - /* 1. draw filled, blended polygon */ - glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL); + /* set up outline */ + float outlineColor[4]; + UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor); + immUniform4fv("outlineColor", outlineColor); + immUniform1f("outlineWidth", outlineWidth); - /* 2. draw outline */ - glLineWidth(1); - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30); - glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, co); + immEnd(); - /* finish up */ - glDisableClientState(GL_VERTEX_ARRAY); + immUnbindProgram(); - glDepthRange(0.0, 1.0); + GPU_disable_program_point_size(); glDisable(GL_BLEND); - if (v3d->zbuf) glDepthFunc(GL_LEQUAL); + if (v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + } } /* *********** text drawing for object/particles/armature ************* */ @@ -919,7 +1295,7 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo if (v3d->zbuf) glDisable(GL_DEPTH_TEST); } else { - glDepthMask(0); + glDepthMask(GL_FALSE); } for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) { @@ -944,7 +1320,7 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } else { - glDepthMask(1); + glDepthMask(GL_TRUE); } glMatrixMode(GL_PROJECTION); @@ -974,9 +1350,9 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo /* draws a cube given the scaling of the cube, assuming that * all required matrices have been set (used for drawing empties) */ -static void drawcube_size(float size) +static void drawcube_size(float size, unsigned pos) { - const GLfloat pos[8][3] = { + const GLfloat verts[8][3] = { {-size, -size, -size}, {-size, -size, size}, {-size, size, -size}, @@ -989,13 +1365,21 @@ static void drawcube_size(float size) const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6}; +#if 0 glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, pos); + glVertexPointer(3, GL_FLOAT, 0, verts); glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices); glDisableClientState(GL_VERTEX_ARRAY); +#else + immBegin(GL_LINES, 24); + for (int i = 0; i < 24; ++i) { + immVertex3fv(pos, verts[indices[i]]); + } + immEnd(); +#endif } -static void drawshadbuflimits(Lamp *la, float mat[4][4]) +static void drawshadbuflimits(const Lamp *la, const float mat[4][4], unsigned pos) { float sta[3], end[3], lavec[3]; @@ -1005,16 +1389,16 @@ static void drawshadbuflimits(Lamp *la, float mat[4][4]) madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta); madd_v3_v3v3fl(end, mat[3], lavec, la->clipend); - glBegin(GL_LINES); - glVertex3fv(sta); - glVertex3fv(end); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3fv(pos, sta); + immVertex3fv(pos, end); + immEnd(); - glPointSize(3.0); - glBegin(GL_POINTS); - glVertex3fv(sta); - glVertex3fv(end); - glEnd(); + glPointSize(3.0f); + immBegin(GL_POINTS, 2); + immVertex3fv(pos, sta); + immVertex3fv(pos, end); + immEnd(); } static void spotvolume(float lvec[3], float vvec[3], const float inp) @@ -1080,62 +1464,63 @@ static void spotvolume(float lvec[3], float vvec[3], const float inp) mul_m3_v3(mat2, vvec); } -static void draw_spot_cone(Lamp *la, float x, float z) +static void draw_spot_cone(Lamp *la, float x, float z, unsigned pos) { z = fabsf(z); - glBegin(GL_TRIANGLE_FAN); - glVertex3f(0.0f, 0.0f, -x); + const bool square = (la->mode & LA_SQUARE); + + immBegin(GL_TRIANGLE_FAN, square ? 6 : 34); + immVertex3f(pos, 0.0f, 0.0f, -x); - if (la->mode & LA_SQUARE) { - glVertex3f(z, z, 0); - glVertex3f(-z, z, 0); - glVertex3f(-z, -z, 0); - glVertex3f(z, -z, 0); - glVertex3f(z, z, 0); + if (square) { + immVertex3f(pos, z, z, 0); + immVertex3f(pos, -z, z, 0); + immVertex3f(pos, -z, -z, 0); + immVertex3f(pos, z, -z, 0); + immVertex3f(pos, z, z, 0); } else { for (int a = 0; a < 33; a++) { float angle = a * M_PI * 2 / (33 - 1); - glVertex3f(z * cosf(angle), z * sinf(angle), 0); + immVertex3f(pos, z * cosf(angle), z * sinf(angle), 0.0f); } } - glEnd(); + immEnd(); } -static void draw_transp_spot_volume(Lamp *la, float x, float z) +static void draw_transp_spot_volume(Lamp *la, float x, float z, unsigned pos) { glEnable(GL_CULL_FACE); glEnable(GL_BLEND); - glDepthMask(0); + glDepthMask(GL_FALSE); /* draw backside darkening */ glCullFace(GL_FRONT); glBlendFunc(GL_ZERO, GL_SRC_ALPHA); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); - draw_spot_cone(la, x, z); + draw_spot_cone(la, x, z, pos); /* draw front side lighting */ glCullFace(GL_BACK); glBlendFunc(GL_ONE, GL_ONE); - glColor4f(0.2f, 0.2f, 0.2f, 1.0f); + immUniformColor4f(0.2f, 0.2f, 0.2f, 1.0f); - draw_spot_cone(la, x, z); + draw_spot_cone(la, x, z, pos); /* restore state */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); - glDepthMask(1); + glDepthMask(GL_TRUE); glDisable(GL_CULL_FACE); - glCullFace(GL_BACK); } #ifdef WITH_GAMEENGINE -static void draw_transp_sun_volume(Lamp *la) +static void draw_transp_sun_volume(Lamp *la, unsigned pos) { float box[8][3]; @@ -1148,50 +1533,46 @@ static void draw_transp_sun_volume(Lamp *la) box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta; /* draw edges */ - draw_box(box, false); + imm_draw_box(box, false, pos); /* draw faces */ glEnable(GL_CULL_FACE); glEnable(GL_BLEND); - glDepthMask(0); + glDepthMask(GL_FALSE); /* draw backside darkening */ glCullFace(GL_FRONT); glBlendFunc(GL_ZERO, GL_SRC_ALPHA); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); - draw_box(box, true); + imm_draw_box(box, true, pos); /* draw front side lighting */ glCullFace(GL_BACK); glBlendFunc(GL_ONE, GL_ONE); - glColor4f(0.2f, 0.2f, 0.2f, 1.0f); + immUniformColor4f(0.2f, 0.2f, 0.2f, 1.0f); - draw_box(box, true); + imm_draw_box(box, true, pos); /* restore state */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); - glDepthMask(1); + glDepthMask(GL_TRUE); glDisable(GL_CULL_FACE); - glCullFace(GL_BACK); } #endif -static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact) +void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact) { Object *ob = base->object; const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]); Lamp *la = ob->data; float vec[3], lvec[3], vvec[3], circrad; - float lampsize; float imat[4][4]; - unsigned char curcol[4]; - unsigned char col[4]; /* cone can't be drawn for duplicated lamps, because duplilist would be freed */ /* the moment of view3d_draw_transp() call */ const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object); @@ -1219,118 +1600,158 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, if ((drawcone || drawshadowbox) && !v3d->transp) { /* in this case we need to draw delayed */ - ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag); + ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag); return; } - + /* we first draw only the screen aligned & fixed scale stuff */ - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); + gpuMatrixBegin3D_legacy(); + gpuPushMatrix(); + gpuLoadMatrix3D(rv3d->viewmat); /* lets calculate the scale: */ - lampsize = pixsize * ((float)U.obcenter_dia * 0.5f); + const float lampsize_px = U.obcenter_dia; + const float lampsize = pixsize * lampsize_px * 0.5f; /* and view aligned matrix: */ copy_m4_m4(imat, rv3d->viewinv); normalize_v3(imat[0]); normalize_v3(imat[1]); + const unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + /* lamp center */ copy_v3_v3(vec, ob->obmat[3]); + float curcol[4]; if ((dflag & DRAW_CONSTCOLOR) == 0) { /* for AA effects */ - curcol[0] = ob_wire_col[0]; - curcol[1] = ob_wire_col[1]; - curcol[2] = ob_wire_col[2]; - curcol[3] = 154; - glColor4ubv(curcol); + rgb_uchar_to_float(curcol, ob_wire_col); + curcol[3] = 0.6f; + /* TODO: pay attention to GL_BLEND */ } - glLineWidth(1); + glLineWidth(1.0f); + setlinestyle(3); if (lampsize > 0.0f) { + const float outlineWidth = 1.5f * U.pixelsize; + const float lampdot_size = lampsize_px * U.pixelsize + outlineWidth; + /* Inner Circle */ if ((dflag & DRAW_CONSTCOLOR) == 0) { + const float *color = curcol; if (ob->id.us > 1) { if (is_obact || (ob->flag & SELECT)) { - glColor4ub(0x88, 0xFF, 0xFF, 155); + static const float active_color[4] = {0.533f, 1.0f, 1.0f, 1.0f}; + color = active_color; } else { - glColor4ub(0x77, 0xCC, 0xCC, 155); + static const float inactive_color[4] = {0.467f, 0.8f, 0.8f, 1.0f}; + color = inactive_color; } } + + GPU_enable_program_point_size(); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH); + immUniform1f("size", lampdot_size); + immUniform1f("outlineWidth", outlineWidth); + immUniformColor3fvAlpha(color, 0.3f); + immUniform4fv("outlineColor", color); + + immBegin(GL_POINTS, 1); + immVertex3fv(pos, vec); + immEnd(); + + immUnbindProgram(); + + glDisable(GL_BLEND); + GPU_disable_program_point_size(); } - - /* Inner Circle */ - glEnable(GL_BLEND); - drawcircball(GL_LINE_LOOP, vec, lampsize, imat); - glDisable(GL_BLEND); - drawcircball(GL_POLYGON, vec, lampsize, imat); - + else { + /* CONSTCOLOR in effect */ + /* TODO: separate picking from drawing */ + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + /* color doesn't matter, so don't set */ + glPointSize(lampdot_size); + + immBegin(GL_POINTS, 1); + immVertex3fv(pos, vec); + immEnd(); + + immUnbindProgram(); + } + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + /* TODO(merwin): short term, use DEPTH_ONLY for picking + * long term, separate picking from drawing + */ + /* restore */ if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (ob->id.us > 1) - glColor4ubv(curcol); + immUniformColor4fv(curcol); } /* Outer circle */ circrad = 3.0f * lampsize; - setlinestyle(3); - drawcircball(GL_LINE_LOOP, vec, circrad, imat); + imm_drawcircball(vec, circrad, imat, pos); /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */ if (la->type != LA_HEMI) { if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) { - drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat); + imm_drawcircball(vec, circrad + 3.0f * pixsize, imat, pos); } } } else { - setlinestyle(3); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(curcol); circrad = 0.0f; } - + /* draw the pretty sun rays */ if (la->type == LA_SUN) { float v1[3], v2[3], mat[3][3]; short axis; - + /* setup a 45 degree rotation matrix */ axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2); /* vectors */ mul_v3_v3fl(v1, imat[0], circrad * 1.2f); mul_v3_v3fl(v2, imat[0], circrad * 2.5f); - + /* center */ - glTranslate3fv(vec); - + gpuPushMatrix(); + gpuTranslate3fv(vec); + setlinestyle(3); - - glBegin(GL_LINES); + + immBegin(GL_LINES, 16); for (axis = 0; axis < 8; axis++) { - glVertex3fv(v1); - glVertex3fv(v2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); mul_m3_v3(mat, v1); mul_m3_v3(mat, v2); } - glEnd(); - - glTranslatef(-vec[0], -vec[1], -vec[2]); + immEnd(); + gpuPopMatrix(); } - + if (la->type == LA_LOCAL) { if (la->mode & LA_SPHERE) { - drawcircball(GL_LINE_LOOP, vec, la->dist, imat); + imm_drawcircball(vec, la->dist, imat, pos); } } - - glPopMatrix(); /* back in object space */ + + gpuPopMatrix(); /* back in object space */ zero_v3(vec); - + if (is_view) { /* skip drawing extra info */ } @@ -1362,24 +1783,18 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, {z_abs, -z_abs, x}, {-z_abs, z_abs, x}, }; - const unsigned char indices[] = { - 0, 1, 3, - 0, 3, 2, - 0, 2, 4, - 0, 1, 4, - }; - - /* Draw call: - * activate and specify pointer to vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vertices); - /* draw the pyramid */ - glDrawElements(GL_LINE_STRIP, 12, GL_UNSIGNED_BYTE, indices); - /* deactivate vertex arrays after drawing */ - glDisableClientState(GL_VERTEX_ARRAY); + immBegin(GL_LINES, 16); + for (int i = 1; i <= 4; ++i) { + immVertex3fv(pos, vertices[0]); /* apex to corner */ + immVertex3fv(pos, vertices[i]); + int next_i = (i == 4) ? 1 : (i + 1); + immVertex3fv(pos, vertices[i]); /* corner to next corner */ + immVertex3fv(pos, vertices[next_i]); + } + immEnd(); - glTranslatef(0.0f, 0.0f, x); + gpuTranslate3f(0.0f, 0.0f, x); /* draw the square representing spotbl */ if (la->type == LA_SPOT) { @@ -1389,22 +1804,21 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, * previously it adjusted to always to show it but that seems * confusing because it doesn't show the actual blend size */ if (blend != 0.0f && blend != z_abs) { - fdrawbox(blend, -blend, -blend, blend); + imm_draw_line_box_3D(pos, blend, -blend, -blend, blend); } } } else { - /* draw the angled sides of the cone */ - glBegin(GL_LINE_STRIP); - glVertex3fv(vvec); - glVertex3fv(vec); - glVertex3fv(lvec); - glEnd(); + immBegin(GL_LINE_STRIP, 3); + immVertex3fv(pos, vvec); + immVertex3fv(pos, vec); + immVertex3fv(pos, lvec); + immEnd(); /* draw the circle at the end of the cone */ - glTranslatef(0.0f, 0.0f, x); - circ(0.0f, 0.0f, z_abs); + gpuTranslate3f(0.0f, 0.0f, x); + imm_draw_lined_circle_3D(pos, 0.0f, 0.0f, z_abs, 32); /* draw the circle representing spotbl */ if (la->type == LA_SPOT) { @@ -1414,17 +1828,17 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, * previously it adjusted to always to show it but that seems * confusing because it doesn't show the actual blend size */ if (blend != 0.0f && blend != z_abs) { - circ(0.0f, 0.0f, blend); + imm_draw_lined_circle_3D(pos, 0.0f, 0.0f, blend, 32); } } } if (drawcone) - draw_transp_spot_volume(la, x, z); + draw_transp_spot_volume(la, x, z, pos); /* draw clip start, useful for wide cones where its not obvious where the start is */ - glTranslatef(0.0, 0.0, -x); /* reverse translation above */ - glBegin(GL_LINES); + gpuTranslate3f(0.0f, 0.0f, -x); /* reverse translation above */ + immBegin(GL_LINES, 2); if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) { float lvec_clip[3]; float vvec_clip[3]; @@ -1433,41 +1847,40 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac); interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac); - glVertex3fv(lvec_clip); - glVertex3fv(vvec_clip); + immVertex3fv(pos, lvec_clip); + immVertex3fv(pos, vvec_clip); } /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */ else { - glVertex3f(0.0, 0.0, -circrad); - glVertex3f(0.0, 0.0, -la->dist); + immVertex3f(pos, 0.0f, 0.0f, -circrad); + immVertex3f(pos, 0.0f, 0.0f, -la->dist); } - glEnd(); + immEnd(); } else if (ELEM(la->type, LA_HEMI, LA_SUN)) { - /* draw the line from the circle along the dist */ - glBegin(GL_LINES); + immBegin(GL_LINES, 2); vec[2] = -circrad; - glVertex3fv(vec); + immVertex3fv(pos, vec); vec[2] = -la->dist; - glVertex3fv(vec); - glEnd(); - + immVertex3fv(pos, vec); + immEnd(); + if (la->type == LA_HEMI) { /* draw the hemisphere curves */ short axis, steps, dir; float outdist, zdist, mul; zero_v3(vec); - outdist = 0.14; mul = 1.4; dir = 1; - + outdist = 0.14f; mul = 1.4f; dir = 1; + setlinestyle(4); /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */ for (axis = 0; axis < 4; axis++) { - float v[3] = {0.0, 0.0, 0.0}; - zdist = 0.02; - - glBegin(GL_LINE_STRIP); - + float v[3] = {0.0f, 0.0f, 0.0f}; + zdist = 0.02f; + + immBegin(GL_LINE_STRIP, 6); + for (steps = 0; steps < 6; steps++) { if (axis == 0 || axis == 1) { /* x axis up, x axis down */ /* make the arcs start at the edge of the energy circle */ @@ -1480,13 +1893,13 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, } v[2] = v[2] - steps * zdist; - - glVertex3fv(v); - + + immVertex3fv(pos, v); + zdist = zdist * mul; } - - glEnd(); + + immEnd(); /* flip the direction */ dir = -dir; } @@ -1494,96 +1907,92 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, #ifdef WITH_GAMEENGINE if (drawshadowbox) { - draw_transp_sun_volume(la); + draw_transp_sun_volume(la, pos); } #endif - } else if (la->type == LA_AREA) { setlinestyle(3); if (la->area_shape == LA_AREA_SQUARE) - fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f); + imm_draw_line_box_3D(pos, -la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f); else if (la->area_shape == LA_AREA_RECT) - fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f); + imm_draw_line_box_3D(pos, -la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f); - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, -circrad); - glVertex3f(0.0, 0.0, -la->dist); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, -circrad); + immVertex3f(pos, 0.0f, 0.0f, -la->dist); + immEnd(); } - + /* and back to viewspace */ - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); + gpuPushMatrix(); + gpuLoadMatrix3D(rv3d->viewmat); copy_v3_v3(vec, ob->obmat[3]); setlinestyle(0); - + if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) { - drawshadbuflimits(la, ob->obmat); + drawshadbuflimits(la, ob->obmat, pos); } - + if ((dflag & DRAW_CONSTCOLOR) == 0) { - UI_GetThemeColor4ubv(TH_LAMP, col); - glColor4ubv(col); + immUniformThemeColor(TH_LAMP); } glEnable(GL_BLEND); - + if (vec[2] > 0) vec[2] -= circrad; else vec[2] += circrad; - - glBegin(GL_LINES); - glVertex3fv(vec); + + immBegin(GL_LINES, 2); + immVertex3fv(pos, vec); vec[2] = 0; - glVertex3fv(vec); - glEnd(); - - glPointSize(2.0); - glBegin(GL_POINTS); - glVertex3fv(vec); - glEnd(); - + immVertex3fv(pos, vec); + immEnd(); + + glPointSize(2.0f); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, vec); + immEnd(); + glDisable(GL_BLEND); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* restore for drawing extra stuff */ - glColor3ubv(ob_wire_col); - } - /* and finally back to org object space! */ - glPopMatrix(); + + immUnbindProgram(); + gpuMatrixEnd(); } -static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3]) +static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3], unsigned pos) { - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, -sta); - glVertex3f(0.0, 0.0, -end); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3f(pos, 0.0f, 0.0f, -sta); + immVertex3f(pos, 0.0f, 0.0f, -end); + immEnd(); if (!(dflag & DRAW_PICKING)) { - glPointSize(3.0); - glBegin(GL_POINTS); + glPointSize(3.0f); + /* would like smooth round points here, but that means binding another shader... + * if it's really desired, pull these points into their own function to be called after */ + immBegin(GL_POINTS, 2); if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(col); + immUniformColor3ubv(col); } - glVertex3f(0.0, 0.0, -sta); - glVertex3f(0.0, 0.0, -end); - glEnd(); + immVertex3f(pos, 0.0f, 0.0f, -sta); + immVertex3f(pos, 0.0f, 0.0f, -end); + immEnd(); } } /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */ /* qdn: now also enabled for Blender to set focus point for defocus composite node */ -static void draw_focus_cross(float dist, float size) +static void draw_focus_cross(float dist, float size, unsigned pos) { - glBegin(GL_LINES); - glVertex3f(-size, 0.0f, -dist); - glVertex3f(size, 0.0f, -dist); - glVertex3f(0.0f, -size, -dist); - glVertex3f(0.0f, size, -dist); - glEnd(); + immBegin(GL_LINES, 4); + immVertex3f(pos, -size, 0.0f, -dist); + immVertex3f(pos, size, 0.0f, -dist); + immVertex3f(pos, 0.0f, -size, -dist); + immVertex3f(pos, 0.0f, size, -dist); + immEnd(); } #ifdef VIEW3D_CAMERA_BORDER_HACK @@ -1679,16 +2088,19 @@ static void draw_viewport_object_reconstruction( const int v3d_drawtype = view3d_effective_drawtype(v3d); if (v3d_drawtype == OB_WIRE) { + unsigned char color[4]; + const unsigned char *color_ptr = NULL; if ((dflag & DRAW_CONSTCOLOR) == 0) { if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) { - glColor3ubv(ob_wire_col); + color_ptr = ob_wire_col; } else { - glColor3fv(track->color); + rgba_float_to_uchar(color, track->color); + color_ptr = color; } } - drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype); + drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr); } else if (v3d_drawtype > OB_WIRE) { if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) { @@ -1714,17 +2126,21 @@ static void draw_viewport_object_reconstruction( draw_bundle_sphere(); } else { + unsigned char color[4]; + const unsigned char *color_ptr = NULL; if ((dflag & DRAW_CONSTCOLOR) == 0) { if (selected) { - glColor3ubv(ob_wire_col); + color_ptr = ob_wire_col; } else { - if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color); - else UI_ThemeColor(TH_WIRE); + if (track->flag & TRACK_CUSTOMCOLOR) rgba_float_to_uchar(color, track->color); + else UI_GetThemeColor4ubv(TH_WIRE, color); + + color_ptr = color; } } - drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype); + drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr); } } @@ -1806,59 +2222,68 @@ static void draw_viewport_reconstruction( GPU_select_load_id(base->selcol); } -static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode) -{ - glBegin(mode); - glVertex3fv(near_plane[0]); - glVertex3fv(far_plane[0]); - glVertex3fv(far_plane[1]); - glVertex3fv(near_plane[1]); - glEnd(); - - glBegin(mode); - glVertex3fv(near_plane[1]); - glVertex3fv(far_plane[1]); - glVertex3fv(far_plane[2]); - glVertex3fv(near_plane[2]); - glEnd(); - - glBegin(mode); - glVertex3fv(near_plane[2]); - glVertex3fv(near_plane[1]); - glVertex3fv(far_plane[1]); - glVertex3fv(far_plane[2]); - glEnd(); - - glBegin(mode); - glVertex3fv(far_plane[0]); - glVertex3fv(near_plane[0]); - glVertex3fv(near_plane[3]); - glVertex3fv(far_plane[3]); - glEnd(); -} - /* camera frame */ -static void drawcamera_frame(float vec[4][3], const GLenum mode) +static void drawcamera_frame(float vec[4][3], bool filled, unsigned pos) { - glBegin(mode); - glVertex3fv(vec[0]); - glVertex3fv(vec[1]); - glVertex3fv(vec[2]); - glVertex3fv(vec[3]); - glEnd(); + immBegin(filled ? GL_QUADS : GL_LINE_LOOP, 4); + immVertex3fv(pos, vec[0]); + immVertex3fv(pos, vec[1]); + immVertex3fv(pos, vec[2]); + immVertex3fv(pos, vec[3]); + immEnd(); } /* center point to camera frame */ -static void drawcamera_framelines(float vec[4][3], float origin[3]) -{ - glBegin(GL_LINE_STRIP); - glVertex3fv(vec[1]); - glVertex3fv(origin); - glVertex3fv(vec[0]); - glVertex3fv(vec[3]); - glVertex3fv(origin); - glVertex3fv(vec[2]); - glEnd(); +static void drawcamera_framelines(float vec[4][3], float origin[3], unsigned pos) +{ + immBegin(GL_LINES, 8); + immVertex3fv(pos, origin); + immVertex3fv(pos, vec[0]); + immVertex3fv(pos, origin); + immVertex3fv(pos, vec[1]); + immVertex3fv(pos, origin); + immVertex3fv(pos, vec[2]); + immVertex3fv(pos, origin); + immVertex3fv(pos, vec[3]); + immEnd(); +} + +static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], bool filled, unsigned pos) +{ + drawcamera_frame(near_plane, filled, pos); + drawcamera_frame(far_plane, filled, pos); + + if (filled) { + immBegin(GL_QUADS, 16); /* TODO(merwin): use GL_TRIANGLE_STRIP here */ + immVertex3fv(pos, near_plane[0]); + immVertex3fv(pos, far_plane[0]); + immVertex3fv(pos, far_plane[1]); + immVertex3fv(pos, near_plane[1]); + + immVertex3fv(pos, near_plane[1]); + immVertex3fv(pos, far_plane[1]); + immVertex3fv(pos, far_plane[2]); + immVertex3fv(pos, near_plane[2]); + + immVertex3fv(pos, near_plane[2]); + immVertex3fv(pos, near_plane[1]); + immVertex3fv(pos, far_plane[1]); + immVertex3fv(pos, far_plane[2]); + + immVertex3fv(pos, far_plane[0]); + immVertex3fv(pos, near_plane[0]); + immVertex3fv(pos, near_plane[3]); + immVertex3fv(pos, far_plane[3]); + immEnd(); + } + else { + immBegin(GL_LINES, 8); + for (int i = 0; i < 4; ++i) { + immVertex3fv(pos, near_plane[i]); + immVertex3fv(pos, far_plane[i]); + } + immEnd(); + } } static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob) @@ -1870,7 +2295,7 @@ static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob) static void drawcamera_stereo3d( Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam, - float vec[4][3], float drawsize, const float scale[3]) + float vec[4][3], float drawsize, const float scale[3], unsigned pos) { float obmat[4][4]; float vec_lr[2][4][3]; @@ -1886,15 +2311,15 @@ static void drawcamera_stereo3d( zero_v3(tvec); - glPushMatrix(); + /* caller bound GPU_SHADER_3D_UNIFORM_COLOR, passed in pos attribute ID */ for (int i = 0; i < 2; i++) { ob = BKE_camera_multiview_render(scene, ob, names[i]); cam_lr[i] = ob->data; - glLoadMatrixf(rv3d->viewmat); + gpuLoadMatrix3D(rv3d->viewmat); BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat); - glMultMatrixf(obmat); + gpuMultMatrix3D(obmat); copy_m3_m3(vec_lr[i], vec); copy_v3_v3(vec_lr[i][3], vec[3]); @@ -1911,10 +2336,10 @@ static void drawcamera_stereo3d( if (is_stereo3d_cameras) { /* camera frame */ - drawcamera_frame(vec_lr[i], GL_LINE_LOOP); + drawcamera_frame(vec_lr[i], false, pos); /* center point to camera frame */ - drawcamera_framelines(vec_lr[i], tvec); + drawcamera_framelines(vec_lr[i], tvec, pos); } /* connecting line */ @@ -1928,21 +2353,21 @@ static void drawcamera_stereo3d( } } - /* the remaining drawing takes place in the view space */ - glLoadMatrixf(rv3d->viewmat); + gpuLoadMatrix3D(rv3d->viewmat); if (is_stereo3d_cameras) { /* draw connecting lines */ - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(2, 0xAAAA); + glPushAttrib(GL_ENABLE_BIT); /* TODO(merwin): new state tracking! */ + glLineStipple(2, 0xAAAA); + glEnable(GL_LINE_STIPPLE); - glBegin(GL_LINES); - glVertex3fv(origin[0]); - glVertex3fv(origin[1]); - glEnd(); + immBegin(GL_LINES, 2); + immVertex3fv(pos, origin[0]); + immVertex3fv(pos, origin[1]); + immEnd(); - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + glPopAttrib(); } /* draw convergence plane */ @@ -1967,21 +2392,21 @@ static void drawcamera_stereo3d( add_v3_v3(local_plane[i], axis_center); } - glColor3f(0.0f, 0.0f, 0.0f); + immUniformColor3f(0.0f, 0.0f, 0.0f); /* camera frame */ - drawcamera_frame(local_plane, GL_LINE_LOOP); + drawcamera_frame(local_plane, false, pos); if (v3d->stereo3d_convergence_alpha > 0.0f) { glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */ - glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha); + immUniformColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha); - drawcamera_frame(local_plane, GL_QUADS); + drawcamera_frame(local_plane, true, pos); glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ + glDepthMask(GL_TRUE); /* restore write in zbuffer */ } } @@ -2006,37 +2431,31 @@ static void drawcamera_stereo3d( } /* camera frame */ - glColor3f(0.0f, 0.0f, 0.0f); + immUniformColor3f(0.0f, 0.0f, 0.0f); - drawcamera_frame(near_plane, GL_LINE_LOOP); - drawcamera_frame(far_plane, GL_LINE_LOOP); - drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP); + drawcamera_volume(near_plane, far_plane, false, pos); if (v3d->stereo3d_volume_alpha > 0.0f) { glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */ if (i == 0) - glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha); + immUniformColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha); else - glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha); + immUniformColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha); - drawcamera_frame(near_plane, GL_QUADS); - drawcamera_frame(far_plane, GL_QUADS); - drawcamera_volume(near_plane, far_plane, GL_QUADS); + drawcamera_volume(near_plane, far_plane, true, pos); glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ + glDepthMask(GL_TRUE); /* restore write in zbuffer */ } } } - - glPopMatrix(); } /* flag similar to draw_object() */ -static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, - const short dflag, const unsigned char ob_wire_col[4]) +void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, + const short dflag, const unsigned char ob_wire_col[4]) { /* a standing up pyramid with (0,0,0) as top */ Camera *cam; @@ -2099,8 +2518,14 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale, asp, shift, &drawsize, vec); - glDisable(GL_CULL_FACE); - glLineWidth(1); + gpuMatrixBegin3D_legacy(); + + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + if (ob_wire_col) { + immUniformColor3ubv(ob_wire_col); + } + glLineWidth(1.0f); /* camera frame */ if (!is_stereo3d_cameras) { @@ -2109,27 +2534,30 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base float obmat[4][4]; bool is_left = v3d->multiview_eye == STEREO_LEFT_ID; - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); + gpuPushMatrix(); + gpuLoadMatrix3D(rv3d->viewmat); BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat); - glMultMatrixf(obmat); + gpuMultMatrix3D(obmat); - drawcamera_frame(vec, GL_LINE_LOOP); - glPopMatrix(); + drawcamera_frame(vec, false, pos); + gpuPopMatrix(); } else { - drawcamera_frame(vec, GL_LINE_LOOP); + drawcamera_frame(vec, false, pos); } } - if (is_view) + if (is_view) { + immUnbindProgram(); + gpuMatrixEnd(); return; + } zero_v3(tvec); /* center point to camera frame */ if (!is_stereo3d_cameras) - drawcamera_framelines(vec, tvec); + drawcamera_framelines(vec, tvec, pos); /* arrow on top */ tvec[2] = vec[1][2]; /* copy the depth */ @@ -2138,22 +2566,25 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base * for active cameras. We actually draw both outline+filled * for active cameras so the wire can be seen side-on */ for (int i = 0; i < 2; i++) { - if (i == 0) glBegin(GL_LINE_LOOP); - else if (i == 1 && is_active) glBegin(GL_TRIANGLES); + if (i == 0) immBegin(GL_LINE_LOOP, 3); + else if (i == 1 && is_active) { + glDisable(GL_CULL_FACE); /* TODO: declarative state tracking */ + immBegin(GL_TRIANGLES, 3); + } else break; tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]); tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]); - glVertex3fv(tvec); /* left */ + immVertex3fv(pos, tvec); /* left */ tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]); - glVertex3fv(tvec); /* right */ + immVertex3fv(pos, tvec); /* right */ tvec[0] = shift[0]; tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]); - glVertex3fv(tvec); /* top */ + immVertex3fv(pos, tvec); /* top */ - glEnd(); + immEnd(); } if ((dflag & DRAW_SCENESET) == 0) { @@ -2164,16 +2595,15 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base copy_m4_m4(nobmat, ob->obmat); normalize_m4(nobmat); - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); - glMultMatrixf(nobmat); + gpuLoadMatrix3D(rv3d->viewmat); + gpuMultMatrix3D(nobmat); if (cam->flag & CAM_SHOWLIMITS) { const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120}; - draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col)); + draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col), pos); /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */ - draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize); + draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize, pos); } if (cam->flag & CAM_SHOWMIST) { @@ -2182,57 +2612,66 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base if (world) { draw_limit_line(world->miststa, world->miststa + world->mistdist, - dflag, (is_active ? col_hi : col)); + dflag, (is_active ? col_hi : col), pos); } } - glPopMatrix(); } } /* stereo cameras drawing */ if (is_stereo3d) { - drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale); + drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale, pos); } + + immUnbindProgram(); + gpuMatrixEnd(); } /* flag similar to draw_object() */ -static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d), - Object *UNUSED(ob), int UNUSED(flag)) +void drawspeaker(const unsigned char ob_wire_col[3]) { - float vec[3]; + VertexFormat *format = immVertexFormat(); + unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); - glEnable(GL_BLEND); - glLineWidth(1); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (ob_wire_col) { + immUniformColor3ubv(ob_wire_col); + } + + glLineWidth(1.0f); + + const int segments = 16; for (int j = 0; j < 3; j++) { - vec[2] = 0.25f * j - 0.125f; + float z = 0.25f * j - 0.125f; - glBegin(GL_LINE_LOOP); - for (int i = 0; i < 16; i++) { - vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); - vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); - glVertex3fv(vec); + immBegin(GL_LINE_LOOP, segments); + for (int i = 0; i < segments; i++) { + float x = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); + float y = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); + immVertex3f(pos, x, y, z); } - glEnd(); + immEnd(); } for (int j = 0; j < 4; j++) { - vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f; - vec[1] = ((j % 2) * (j - 2)) * 0.5f; - glBegin(GL_LINE_STRIP); + float x = (((j + 1) % 2) * (j - 1)) * 0.5f; + float y = ((j % 2) * (j - 2)) * 0.5f; + immBegin(GL_LINE_STRIP, 3); for (int i = 0; i < 3; i++) { if (i == 1) { - vec[0] *= 0.5f; - vec[1] *= 0.5f; + x *= 0.5f; + y *= 0.5f; } - vec[2] = 0.25f * i - 0.125f; - glVertex3fv(vec); + float z = 0.25f * i - 0.125f; + immVertex3f(pos, x, y, z); } - glEnd(); + immEnd(); } - glDisable(GL_BLEND); + immUnbindProgram(); } static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel) @@ -2357,7 +2796,7 @@ static void drawlattice(View3D *v3d, Object *ob) } } - glLineWidth(1); + glLineWidth(1.0f); glBegin(GL_LINES); for (w = 0; w < lt->pntsw; w++) { int wxt = (w == 0 || w == lt->pntsw - 1); @@ -3075,7 +3514,7 @@ static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm) data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE); if (data.cd_layer_offset != -1) { - glLineWidth(3.0); + glLineWidth(3.0f); dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data); } } @@ -3121,7 +3560,7 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm) data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT); if (data.cd_layer_offset != -1) { - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2.0f); glBegin(GL_POINTS); dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP); glEnd(); @@ -3134,7 +3573,7 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm) data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT); if (data.cd_layer_offset != -1) { - glLineWidth(3.0); + glLineWidth(3.0f); dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data); } } @@ -3155,7 +3594,7 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, { ToolSettings *ts = scene->toolsettings; - if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */ + if (v3d->zbuf) glDepthMask(GL_FALSE); /* disable write in zbuffer, zbuf select */ for (int sel = 0; sel < 2; sel++) { unsigned char col[4], fcol[4]; @@ -3203,7 +3642,7 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, } } - if (v3d->zbuf) glDepthMask(1); + if (v3d->zbuf) glDepthMask(GL_TRUE); } static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, @@ -3687,7 +4126,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE); bool use_depth_offset = false; - glLineWidth(1); + glLineWidth(1.0f); BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); @@ -3696,7 +4135,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, draw_mesh_paint_weight_faces(finalDM, true, draw_em_fancy__setFaceOpts, me->edit_btmesh); ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); + glDepthMask(GL_FALSE); use_depth_offset = true; } else { @@ -3743,7 +4182,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, UI_ThemeColor(TH_WIRE_EDIT); ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); + glDepthMask(GL_FALSE); use_depth_offset = true; } else { @@ -3793,7 +4232,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */ /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */ if (check_object_draw_texture(scene, v3d, dt)) @@ -3809,7 +4248,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ + glDepthMask(GL_TRUE); /* restore write in zbuffer */ } else if (efa_act) { /* even if draw faces is off it would be nice to draw the stipple face @@ -3824,7 +4263,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3); glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */ #ifdef WITH_FREESTYLE draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act); @@ -3833,7 +4272,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ + glDepthMask(GL_TRUE); /* restore write in zbuffer */ } /* here starts all fancy draw-extra over */ @@ -3847,7 +4286,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, else { if (me->drawflag & ME_DRAWSEAMS) { UI_ThemeColor(TH_EDGE_SEAM); - glLineWidth(2); + glLineWidth(2.0f); draw_dm_edges_seams(em, cageDM); @@ -3856,7 +4295,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, if (me->drawflag & ME_DRAWSHARP) { UI_ThemeColor(TH_EDGE_SHARP); - glLineWidth(2); + glLineWidth(2.0f); draw_dm_edges_sharp(em, cageDM); @@ -3866,7 +4305,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #ifdef WITH_FREESTYLE if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) { UI_ThemeColor(TH_FREESTYLE_EDGE_MARK); - glLineWidth(2); + glLineWidth(2.0f); draw_dm_edges_freestyle(em, cageDM); @@ -3881,7 +4320,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, draw_dm_bweights(em, scene, cageDM); } - glLineWidth(1); + glLineWidth(1.0f); draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act); } @@ -3919,7 +4358,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, } if (use_depth_offset) { - glDepthMask(1); + glDepthMask(GL_TRUE); ED_view3d_polygon_offset(rv3d, 0.0); GPU_object_material_unbind(); } @@ -3930,15 +4369,94 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, #endif } +static void draw_em_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, + Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt) +{ + /* for now... something simple! */ + + Batch *surface = MBC_get_all_triangles(cageDM); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + glEnable(GL_BLEND); + + /* disable depth writes for transparent surface, so it doesn't interfere with itself */ + glDepthMask(GL_FALSE); + + Batch_set_builtin_program(surface, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4f(surface, "color", 1.0f, 0.5f, 0.0f, 0.5f); + Batch_draw(surface); + +#if 0 /* until I understand finalDM better */ + if (finalDM != cageDM) { + puts("finalDM != cageDM"); + Batch *finalSurface = MBC_get_all_triangles(finalDM); + Batch_set_builtin_program(finalSurface, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4f(finalSurface, "color", 0.0f, 0.0f, 0.0f, 0.05f); + Batch_draw(finalSurface); + } +#endif + + glDepthMask(GL_TRUE); + + /* now write surface depth so other objects won't poke through + * NOTE: does not help as much as desired + * TODO: draw edit object last to avoid this mess + */ + Batch_set_builtin_program(surface, GPU_SHADER_3D_DEPTH_ONLY); + Batch_draw(surface); + + if (GLEW_VERSION_3_2) { + Batch *overlay = MBC_get_overlay_edges(cageDM); + Batch_set_builtin_program(overlay, GPU_SHADER_EDGES_OVERLAY); + Batch_Uniform2f(overlay, "viewportSize", ar->winx, ar->winy); + Batch_draw(overlay); + +#if 0 /* TODO: use this SIMPLE variant for pure triangle meshes */ + Batch_set_builtin_program(surface, GPU_SHADER_EDGES_OVERLAY_SIMPLE); + /* use these defaults: + * const float edgeColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + * Batch_Uniform4f(surface, "fillColor", edgeColor[0], edgeColor[1], edgeColor[2], 0.0f); + * Batch_Uniform4fv(surface, "outlineColor", edgeColor); + * Batch_Uniform1f(surface, "outlineWidth", 1.0f); + */ + Batch_Uniform2f(surface, "viewportSize", ar->winx, ar->winy); + Batch_draw(surface); +#endif + } + else { + Batch *edges = MBC_get_all_edges(cageDM); + Batch_set_builtin_program(edges, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); + glEnable(GL_LINE_SMOOTH); + glLineWidth(1.5f); + Batch_draw(edges); + glDisable(GL_LINE_SMOOTH); + } + +#if 0 /* looks good even without points */ + Batch *verts = MBC_get_all_verts(cageDM); + glEnable(GL_BLEND); + + Batch_set_builtin_program(verts, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); + Batch_Uniform4f(verts, "color", 0.0f, 0.0f, 0.0f, 1.0f); + Batch_Uniform1f(verts, "size", UI_GetThemeValuef(TH_VERTEX_SIZE) * 1.5f); + Batch_draw(verts); + + glDisable(GL_BLEND); +#endif +} + /* Mesh drawing routines */ -static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) +void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) /* LEGACY */ { if ((v3d->transp == false) && /* not when we draw the transparent pass */ (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */ { glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - glDepthMask(0); + glDepthMask(GL_FALSE); /* if transparent, we cannot draw the edges for solid select... edges * have no material info. GPU_object_material_visible will skip the @@ -3952,7 +4470,49 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) dm->drawEdges(dm, 0, 1); } - glDepthMask(1); + glDepthMask(GL_TRUE); + } +} + +static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, const bool is_active) +{ + if ((v3d->transp == false) && /* not when we draw the transparent pass */ + (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */ + { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + glDepthMask(GL_FALSE); + + float outline_color[4]; + UI_GetThemeColor4fv((is_active ? TH_ACTIVE : TH_SELECT), outline_color); + +#if 1 /* new version that draws only silhouette edges */ + Batch *fancy_edges = MBC_get_fancy_edges(dm); + + if (rv3d->persp == RV3D_ORTHO) { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO); + /* set eye vector, transformed to object coords */ + float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ + mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye); + Batch_Uniform3fv(fancy_edges, "eye", eye); + } + else { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP); + } + + Batch_Uniform1b(fancy_edges, "drawFront", false); + Batch_Uniform1b(fancy_edges, "drawBack", false); + Batch_Uniform1b(fancy_edges, "drawSilhouette", true); + Batch_Uniform4fv(fancy_edges, "silhouetteColor", outline_color); + + Batch_draw(fancy_edges); +#else /* alternate version that matches look of old viewport (but more efficient) */ + Batch *batch = MBC_get_all_edges(dm); + Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR); + Batch_Uniform4fv(batch, "color", outline_color); + Batch_draw(batch); +#endif + + glDepthMask(GL_TRUE); } } @@ -4015,7 +4575,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D else if ((no_faces && no_edges) || ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob))) { - glPointSize(1.5); + glPointSize(1.5f); dm->drawVerts(dm); } else if ((dt == OB_WIRE) || no_faces) { @@ -4198,14 +4758,14 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D */ if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) { ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ + glDepthMask(GL_FALSE); /* disable write in zbuffer, selected edge wires show better */ } glLineWidth(1.0f); dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0); if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) { - glDepthMask(1); + glDepthMask(GL_TRUE); ED_view3d_polygon_offset(rv3d, 0.0); } } @@ -4237,7 +4797,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3 /* If we are drawing shadows and any of the materials don't cast a shadow, * then don't draw the object */ if (v3d->flag2 & V3D_RENDER_SHADOW) { - for (int i = 1; i <= ob->totcol; ++i) { + for (int i = 0; i < ob->totcol; ++i) { Material *ma = give_current_material(ob, i); if (ma && !(ma->mode2 & MA_CASTSHADOW)) { return true; @@ -4339,6 +4899,455 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3 return retval; } +static void make_color_variations(const unsigned char base_ubyte[4], float low[4], float med[4], float high[4], const bool other_obedit) +{ + /* original idea: nice variations (lighter & darker shades) of base color + * current implementation uses input color as high; med & low get closer to background color + */ + + float bg[3]; + UI_GetThemeColor3fv(TH_BACK, bg); + + float base[4]; + rgba_uchar_to_float(base, base_ubyte); + + if (other_obedit) { + /* this object should fade away so user can focus on the object being edited */ + interp_v3_v3v3(low, bg, base, 0.1f); + interp_v3_v3v3(med, bg, base, 0.2f); + interp_v3_v3v3(high, bg, base, 0.25f); + } + else { + interp_v3_v3v3(low, bg, base, 0.333f); + interp_v3_v3v3(med, bg, base, 0.667f); + copy_v3_v3(high, base); + } + + /* use original alpha */ + low[3] = base[3]; + med[3] = base[3]; + high[3] = base[3]; +} + +static void draw_mesh_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const unsigned char ob_wire_col[4], const short dflag, const bool other_obedit) +{ + if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { + /* too complicated! use existing methods */ + /* TODO: move this into a separate depth pre-pass */ + draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + return; + } + +#ifdef WITH_GAMEENGINE + Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, scene) : base->object; +#else + Object *ob = base->object; +#endif + Mesh *me = ob->data; + eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; /* could be bool draw_wire_overlay */ + bool no_edges, no_faces; + DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); + const bool is_obact = (ob == OBACT); + int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0; + + if (!dm) + return; + + const bool solid = dt >= OB_SOLID; + if (solid) { + DM_update_materials(dm, ob); + } + + /* Check to draw dynamic paint colors (or weights from WeightVG modifiers). + * Note: Last "preview-active" modifier in stack will win! */ + if (DM_get_loop_data_layer(dm, CD_PREVIEW_MLOOPCOL) && modifiers_isPreview(ob)) + draw_flags |= DRAW_MODIFIERS_PREVIEW; + + /* Unwanted combination */ + if (draw_flags & DRAW_FACE_SELECT) { + draw_wire = OBDRAW_WIRE_OFF; + } + else if (ob->dtx & OB_DRAWWIRE) { + draw_wire = OBDRAW_WIRE_ON; + } + + /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */ + if (dm->type == DM_TYPE_CCGDM) { + no_edges = !subsurf_has_edges(dm); + no_faces = !subsurf_has_faces(dm); + } + else { + no_edges = (dm->getNumEdges(dm) == 0); + no_faces = (dm->getNumPolys(dm) == 0); + } + + if (solid) { + /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */ + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + } + + if (dt == OB_BOUNDBOX) { + if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0) + draw_bounding_volume(ob, ob->boundtype); + } + else if ((no_faces && no_edges) || + ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob))) + { + glPointSize(1.5f); + // dm->drawVerts(dm); + // TODO: draw smooth round points as a batch + } + else if ((dt == OB_WIRE) || no_faces) { + draw_wire = OBDRAW_WIRE_ON; + + /* enable depth for wireframes */ + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + glLineWidth(1.0f); + +#if 1 /* fancy wireframes */ + + Batch *fancy_edges = MBC_get_fancy_edges(dm); + + if (rv3d->persp == RV3D_ORTHO) { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO); + /* set eye vector, transformed to object coords */ + float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ + mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye); + Batch_Uniform3fv(fancy_edges, "eye", eye); + } + else { + Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP); + } + + float frontColor[4]; + float backColor[4]; + float outlineColor[4]; + make_color_variations(ob_wire_col, backColor, frontColor, outlineColor, other_obedit); + + Batch_Uniform4fv(fancy_edges, "frontColor", frontColor); + Batch_Uniform4fv(fancy_edges, "backColor", backColor); + Batch_Uniform1b(fancy_edges, "drawFront", true); + Batch_Uniform1b(fancy_edges, "drawBack", true); /* false here = backface cull */ + Batch_Uniform1b(fancy_edges, "drawSilhouette", false); + + Batch_draw(fancy_edges); + + /* extra oomph for the silhouette contours */ + glLineWidth(2.0f); + Batch_use_program(fancy_edges); /* hack to make the following uniforms stick */ + Batch_Uniform1b(fancy_edges, "drawFront", false); + Batch_Uniform1b(fancy_edges, "drawBack", false); + Batch_Uniform1b(fancy_edges, "drawSilhouette", true); + Batch_Uniform4fv(fancy_edges, "silhouetteColor", outlineColor); + + Batch_draw(fancy_edges); + +#else /* simple wireframes */ + + Batch *batch = MBC_get_all_edges(dm); + Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR); + + float color[4]; + rgba_uchar_to_float(color, ob_wire_col); + + Batch_Uniform4fv(batch, "color", color); + + Batch_draw(batch); +#endif + } + else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) || + check_object_draw_texture(scene, v3d, dt)) + { + bool draw_loose = true; + + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & SELECT) && + !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) && + (draw_wire == OBDRAW_WIRE_OFF)) + { + draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT)); + } + + if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) { + Paint *p; + + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + + if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene))) { + GPUVertexAttribs gattribs; + float planes[4][4]; + float (*fpl)[4] = NULL; + const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING); + + if (ob->sculpt->partial_redraw) { + if (ar->do_draw & RGN_DRAW_PARTIAL) { + ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob); + fpl = planes; + ob->sculpt->partial_redraw = 0; + } + } + + GPU_object_material_bind(1, &gattribs); + dm->drawFacesSolid(dm, fpl, fast, NULL); + draw_loose = false; + } + else + dm->drawFacesGLSL(dm, GPU_object_material_bind); + + GPU_object_material_unbind(); + + glFrontFace(GL_CCW); + + if (draw_flags & DRAW_FACE_SELECT) + draw_mesh_face_select(rv3d, me, dm, false); + } + else { + draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags); + } + + if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) { + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(ob_wire_col); + } + glLineWidth(1.0f); + dm->drawLooseEdges(dm); + } + } + } + else if (dt == OB_SOLID) { + if (draw_flags & DRAW_MODIFIERS_PREVIEW) { + /* for object selection draws no shade */ + if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { + /* TODO: draw basic faces with GPU_SHADER_3D_DEPTH_ONLY */ + } + else { + const float specular[3] = {0.47f, 0.47f, 0.47f}; + + /* draw outline */ + /* TODO: move this into a separate pass */ + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & SELECT) && + (draw_wire == OBDRAW_WIRE_OFF) && + (ob->sculpt == NULL)) + { + draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT)); + } + + /* materials arent compatible with vertex colors */ + GPU_end_object_materials(); + + /* set default specular */ + GPU_basic_shader_colors(NULL, specular, 35, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); + + dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS); + + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + } + } + else { + Paint *p; + + if ((v3d->flag & V3D_SELECT_OUTLINE) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (base->flag & SELECT) && + (draw_wire == OBDRAW_WIRE_OFF) && + (ob->sculpt == NULL)) + { + /* TODO: move this into a separate pass */ + draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT)); + } + + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + + if (ob->sculpt && (p = BKE_paint_get_active(scene))) { + float planes[4][4]; + float (*fpl)[4] = NULL; + const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING); + + if (ob->sculpt->partial_redraw) { + if (ar->do_draw & RGN_DRAW_PARTIAL) { + ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob); + fpl = planes; + ob->sculpt->partial_redraw = 0; + } + } + + dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind); + } + else + dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); + + glFrontFace(GL_CCW); + + GPU_object_material_unbind(); + + if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(ob_wire_col); + } + glLineWidth(1.0f); + dm->drawLooseEdges(dm); + } + } + } + else if (dt == OB_PAINT) { + draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags); + + /* since we already draw wire as wp guide, don't draw over the top */ + draw_wire = OBDRAW_WIRE_OFF; + } + + if ((draw_wire != OBDRAW_WIRE_OFF) && /* draw extra wire */ + /* when overriding with render only, don't bother */ + (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0)) // <-- is this "== 0" in the right spot??? + { + /* When using wireframe object draw in particle edit mode + * the mesh gets in the way of seeing the particles, fade the wire color + * with the background. */ + + if ((dflag & DRAW_CONSTCOLOR) == 0) { + /* TODO: + * Batch_UniformColor4ubv(ob_wire_col); + */ + } + + /* If drawing wire and drawtype is not OB_WIRE then we are + * overlaying the wires. + * + * No need for polygon offset because new technique is AWESOME. + */ +#if 0 + glLineWidth(1.0f); + dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0); +#else + /* something */ +#endif + } + +#if 0 // (merwin) what is this for? + if (is_obact && BKE_paint_select_vert_test(ob)) { + const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0; + glColor3f(0.0f, 0.0f, 0.0f); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + if (!use_depth) glDisable(GL_DEPTH_TEST); + else ED_view3d_polygon_offset(rv3d, 1.0); + drawSelectedVertices(dm, ob->data); + if (!use_depth) glEnable(GL_DEPTH_TEST); + else ED_view3d_polygon_offset(rv3d, 0.0); + } +#endif + + dm->release(dm); +} + +static bool draw_mesh_object_new(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const unsigned char ob_wire_col[4], const short dflag) +{ + Object *ob = base->object; + Object *obedit = scene->obedit; + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + bool do_alpha_after = false, drawlinked = false, retval = false; + + if (v3d->flag2 & V3D_RENDER_SHADOW) { + /* TODO: handle shadow pass separately */ + return true; + } + + if (obedit && ob != obedit && ob->data == obedit->data) { + if (BKE_key_from_object(ob) || BKE_key_from_object(obedit)) {} + else if (ob->modifiers.first || obedit->modifiers.first) {} + else drawlinked = true; + } + + /* backface culling */ + const bool solid = dt > OB_WIRE; + const bool cullBackface = solid && (v3d->flag2 & V3D_BACKFACE_CULLING); + if (cullBackface) { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + } + + if (ob == obedit || drawlinked) { + DerivedMesh *finalDM, *cageDM; + + if (obedit != ob) { + /* linked to the edit object */ + finalDM = cageDM = editbmesh_get_derived_base( + ob, em, scene->customdata_mask); + } + else { + cageDM = editbmesh_get_derived_cage_and_final( + scene, ob, em, scene->customdata_mask, + &finalDM); + } + + const bool use_material = solid && ((me->drawflag & ME_DRAWEIGHT) == 0); + +#if 0 // why update if not being used? + DM_update_materials(finalDM, ob); + if (cageDM != finalDM) { + DM_update_materials(cageDM, ob); + } +#endif // moved to below + + if (use_material) { + DM_update_materials(finalDM, ob); + if (cageDM != finalDM) { + DM_update_materials(cageDM, ob); + } + + const bool glsl = draw_glsl_material(scene, ob, v3d, dt); + + GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); + } + + draw_em_fancy_new(scene, ar, v3d, ob, em, cageDM, finalDM, dt); + + if (use_material) { + GPU_end_object_materials(); + } + + if (obedit != ob) + finalDM->release(finalDM); + } + else { + /* ob->bb was set by derived mesh system, do NULL check just to be sure */ + if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) { + if (solid) { + const bool glsl = draw_glsl_material(scene, ob, v3d, dt); + + if (dt == OB_SOLID || glsl) { + const bool check_alpha = check_alpha_pass(base); + GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, + (check_alpha) ? &do_alpha_after : NULL); + } + } + + const bool other_obedit = obedit && (obedit != ob); + + draw_mesh_fancy_new(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag, other_obedit); + + GPU_end_object_materials(); + + if (me->totvert == 0) retval = true; + } + } + + if (cullBackface) + glDisable(GL_CULL_FACE); + + return retval; +} + /* ************** DRAW DISPLIST ****************** */ @@ -6093,7 +7102,7 @@ static void drawhandlesN_active(Nurb *nu) if (nu->hide) return; UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); + glLineWidth(2.0f); glBegin(GL_LINES); @@ -6118,72 +7127,100 @@ static void drawhandlesN_active(Nurb *nu) glColor3ub(0, 0, 0); } -static void drawvertsN(Nurb *nu, const char sel, const bool hide_handles, const void *vert) +static void drawvertsN(const Nurb *nurb, const bool hide_handles, const void *vert) { - if (nu->hide) return; + const Nurb *nu; - const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX; + // just quick guesstimate of how many verts to draw + int count = 0; + for (nu = nurb; nu; nu = nu->next) { + if (!nu->hide) { + if (nu->type == CU_BEZIER) { + count += nu->pntsu * 3; + } + else { + count += nu->pntsu * nu->pntsv; + } + } + } + if (count == 0) return; - UI_ThemeColor(color); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_UNSIGNED_BYTE, 3, NORMALIZE_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + + unsigned char vert_color[3]; + unsigned char vert_color_select[3]; + unsigned char vert_color_active[3]; + UI_GetThemeColor3ubv(TH_VERTEX, vert_color); + UI_GetThemeColor3ubv(TH_VERTEX_SELECT, vert_color_select); + UI_GetThemeColor3ubv(TH_ACTIVE_VERT, vert_color_active); glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + immBeginAtMost(GL_POINTS, count); - glBegin(GL_POINTS); - - if (nu->type == CU_BEZIER) { + for (nu = nurb; nu; nu = nu->next) { - BezTriple *bezt = nu->bezt; - int a = nu->pntsu; - while (a--) { - if (bezt->hide == 0) { - if (sel == 1 && bezt == vert) { - UI_ThemeColor(TH_ACTIVE_VERT); + if (nu->hide) continue; - if (bezt->f2 & SELECT) glVertex3fv(bezt->vec[1]); - if (!hide_handles) { - if (bezt->f1 & SELECT) glVertex3fv(bezt->vec[0]); - if (bezt->f3 & SELECT) glVertex3fv(bezt->vec[2]); - } + if (nu->type == CU_BEZIER) { - UI_ThemeColor(color); - } - else if (hide_handles) { - if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]); - } - else { - if ((bezt->f1 & SELECT) == sel) glVertex3fv(bezt->vec[0]); - if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]); - if ((bezt->f3 & SELECT) == sel) glVertex3fv(bezt->vec[2]); + const BezTriple *bezt = nu->bezt; + int a = nu->pntsu; + while (a--) { + if (bezt->hide == 0) { + if (bezt == vert) { + immAttrib3ubv(color, bezt->f2 & SELECT ? vert_color_active : vert_color); + immVertex3fv(pos, bezt->vec[1]); + if (!hide_handles) { + immAttrib3ubv(color, bezt->f1 & SELECT ? vert_color_active : vert_color); + immVertex3fv(pos, bezt->vec[0]); + immAttrib3ubv(color, bezt->f3 & SELECT ? vert_color_active : vert_color); + immVertex3fv(pos, bezt->vec[2]); + } + } + else { + immAttrib3ubv(color, bezt->f2 & SELECT ? vert_color_select : vert_color); + immVertex3fv(pos, bezt->vec[1]); + if (!hide_handles) { + immAttrib3ubv(color, bezt->f1 & SELECT ? vert_color_select : vert_color); + immVertex3fv(pos, bezt->vec[0]); + immAttrib3ubv(color, bezt->f3 & SELECT ? vert_color_select : vert_color); + immVertex3fv(pos, bezt->vec[2]); + } + } } + bezt++; } - bezt++; } - } - else { - BPoint *bp = nu->bp; - int a = nu->pntsu * nu->pntsv; - while (a--) { - if (bp->hide == 0) { - if (bp == vert) { - UI_ThemeColor(TH_ACTIVE_VERT); - glVertex3fv(bp->vec); - UI_ThemeColor(color); - } - else { - if ((bp->f1 & SELECT) == sel) glVertex3fv(bp->vec); + else { + const BPoint *bp = nu->bp; + int a = nu->pntsu * nu->pntsv; + while (a--) { + if (bp->hide == 0) { + if (bp == vert) { + immAttrib3ubv(color, vert_color_active); + } + else { + immAttrib3ubv(color, bp->f1 & SELECT ? vert_color_select : vert_color); + } + immVertex3fv(pos, bp->vec); } + bp++; } - bp++; } } - - glEnd(); + + immEnd(); + immUnbindProgram(); } static void editnurb_draw_active_poly(Nurb *nu) { UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); + glLineWidth(2.0f); BPoint *bp = nu->bp; for (int b = 0; b < nu->pntsv; b++) { @@ -6203,7 +7240,7 @@ static void editnurb_draw_active_poly(Nurb *nu) static void editnurb_draw_active_nurbs(Nurb *nu) { UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); + glLineWidth(2.0f); glBegin(GL_LINES); BPoint *bp = nu->bp; @@ -6258,7 +7295,7 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel) editnurb_draw_active_poly(nu); } - glLineWidth(1); + glLineWidth(1.0f); UI_ThemeColor(TH_NURB_ULINE); bp = nu->bp; @@ -6279,7 +7316,7 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel) editnurb_draw_active_nurbs(nu); } - glLineWidth(1); + glLineWidth(1.0f); glBegin(GL_LINES); @@ -6395,7 +7432,6 @@ static void draw_editnurb( for (nu = nurb; nu; nu = nu->next) { if (nu->type == CU_BEZIER && (cu->drawflag & CU_HIDE_HANDLES) == 0) drawhandlesN(nu, 1, hide_handles); - drawvertsN(nu, 0, hide_handles, NULL); } if (v3d->zbuf) glDepthFunc(GL_LEQUAL); @@ -6446,11 +7482,9 @@ static void draw_editnurb( } if (v3d->zbuf) glDepthFunc(GL_ALWAYS); - - for (nu = nurb; nu; nu = nu->next) { - drawvertsN(nu, 1, hide_handles, vert); - } - + + drawvertsN(nu, hide_handles, vert); + if (v3d->zbuf) glDepthFunc(GL_LEQUAL); } @@ -6598,56 +7632,58 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b } /* draw a sphere for use as an empty drawtype */ -static void draw_empty_sphere(float size) -{ - static GLuint displist = 0; - - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - glPushMatrix(); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0.0, 1, 16, 1); - - glRotatef(90, 0, 1, 0); - gluDisk(qobj, 0.0, 1, 16, 1); - - glRotatef(90, 1, 0, 0); - gluDisk(qobj, 0.0, 1, 16, 1); - - gluDeleteQuadric(qobj); - - glPopMatrix(); - glEndList(); - } - - glScalef(size, size, size); - glCallList(displist); - glScalef(1.0f / size, 1.0f / size, 1.0f / size); +static void draw_empty_sphere(float size, unsigned pos) +{ +#define NSEGMENTS 16 + /* a single ring of vertices */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = size * cosf(angle); + p[i][1] = size * sinf(angle); + } + + immBegin(GL_LINE_LOOP, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, p[i][0], p[i][1], 0.0f); + immEnd(); + immBegin(GL_LINE_LOOP, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, p[i][0], 0.0f, p[i][1]); + immEnd(); + immBegin(GL_LINE_LOOP, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, 0.0f, p[i][0], p[i][1]); + immEnd(); +#undef NSEGMENTS } /* draw a cone for use as an empty drawtype */ -static void draw_empty_cone(float size) +static void draw_empty_cone(float size, unsigned pos) { - const float radius = size; +#define NSEGMENTS 8 + /* a single ring of vertices */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = size * cosf(angle); + p[i][1] = size * sinf(angle); + } - GLUquadricObj *qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - - glPushMatrix(); - - glScalef(radius, size * 2.0f, radius); - glRotatef(-90.0, 1.0, 0.0, 0.0); - gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1); + /* cone sides */ + immBegin(GL_LINES, NSEGMENTS * 2); + for (int i = 0; i < NSEGMENTS; ++i) { + immVertex3f(pos, 0.0f, 2.0f * size, 0.0f); + immVertex3f(pos, p[i][0], 0.0f, p[i][1]); + } + immEnd(); - glPopMatrix(); - - gluDeleteQuadric(qobj); + /* end ring */ + immBegin(GL_LINE_LOOP, NSEGMENTS); + for (int i = 0; i < NSEGMENTS; ++i) + immVertex3f(pos, p[i][0], 0.0f, p[i][1]); + immEnd(); +#undef NSEGMENTS } static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start) @@ -6718,20 +7754,19 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta /* draws a circle on x-z plane given the scaling of the circle, assuming that * all required matrices have been set (used for drawing empties) */ -static void drawcircle_size(float size) +static void drawcircle_size(float size, unsigned pos) { - glBegin(GL_LINE_LOOP); + immBegin(GL_LINE_LOOP, CIRCLE_RESOL); /* coordinates are: cos(degrees * 11.25) = x, sin(degrees * 11.25) = y, 0.0f = z */ for (short degrees = 0; degrees < CIRCLE_RESOL; degrees++) { float x = cosval[degrees]; float y = sinval[degrees]; - - glVertex3f(x * size, 0.0f, y * size); + + immVertex3f(pos, x * size, 0.0f, y * size); } - - glEnd(); + immEnd(); } /* needs fixing if non-identity matrix used */ @@ -6758,6 +7793,29 @@ static void drawtube(const float vec[3], float radius, float height, float tmat[ } /* needs fixing if non-identity matrix used */ +static void imm_drawtube(const float vec[3], float radius, float height, float tmat[4][4], unsigned pos) +{ + float cur[3]; + imm_drawcircball(vec, radius, tmat, pos); + + copy_v3_v3(cur, vec); + cur[2] += height; + + imm_drawcircball(cur, radius, tmat, pos); + + immBegin(GL_LINES, 8); + immVertex3f(pos, vec[0] + radius, vec[1], vec[2]); + immVertex3f(pos, cur[0] + radius, cur[1], cur[2]); + immVertex3f(pos, vec[0] - radius, vec[1], vec[2]); + immVertex3f(pos, cur[0] - radius, cur[1], cur[2]); + immVertex3f(pos, vec[0], vec[1] + radius, vec[2]); + immVertex3f(pos, cur[0], cur[1] + radius, cur[2]); + immVertex3f(pos, vec[0], vec[1] - radius, vec[2]); + immVertex3f(pos, cur[0], cur[1] - radius, cur[2]); + immEnd(); +} + +/* needs fixing if non-identity matrix used */ static void drawcone(const float vec[3], float radius, float height, float tmat[4][4]) { float cur[3]; @@ -6773,12 +7831,35 @@ static void drawcone(const float vec[3], float radius, float height, float tmat[ glVertex3f(vec[0], vec[1], vec[2]); glVertex3f(cur[0] - radius, cur[1], cur[2]); glVertex3f(vec[0], vec[1], vec[2]); + glVertex3f(cur[0], cur[1] + radius, cur[2]); glVertex3f(vec[0], vec[1], vec[2]); glVertex3f(cur[0], cur[1] - radius, cur[2]); glEnd(); } +/* needs fixing if non-identity matrix used */ +static void imm_drawcone(const float vec[3], float radius, float height, float tmat[4][4], unsigned pos) +{ + float cur[3]; + + copy_v3_v3(cur, vec); + cur[2] += height; + + imm_drawcircball(cur, radius, tmat, pos); + + immBegin(GL_LINES, 8); + immVertex3f(pos, vec[0], vec[1], vec[2]); + immVertex3f(pos, cur[0] + radius, cur[1], cur[2]); + immVertex3f(pos, vec[0], vec[1], vec[2]); + immVertex3f(pos, cur[0] - radius, cur[1], cur[2]); + immVertex3f(pos, vec[0], vec[1], vec[2]); + immVertex3f(pos, cur[0], cur[1] + radius, cur[2]); + immVertex3f(pos, vec[0], vec[1], vec[2]); + immVertex3f(pos, cur[0], cur[1] - radius, cur[2]); + immEnd(); +} + /* return true if nothing was drawn */ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt, const short dflag, const unsigned char ob_wire_col[4]) @@ -7027,6 +8108,30 @@ static void draw_box(const float vec[8][3], bool solid) glDisableClientState(GL_VERTEX_ARRAY); } +static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos) +{ + static const GLubyte quad_indices[24] = {0,1,2,3,7,6,5,4,4,5,1,0,3,2,6,7,3,7,4,0,1,5,6,2}; + static const GLubyte line_indices[24] = {0,1,1,2,2,3,3,0,0,4,4,5,5,6,6,7,7,4,1,5,2,6,3,7}; + + const GLubyte *indices; + GLenum prim_type; + + if (solid) { + indices = quad_indices; + prim_type = GL_QUADS; + } + else { + indices = line_indices; + prim_type = GL_LINES; + } + + immBegin(prim_type, 24); + for (int i = 0; i < 24; ++i) { + immVertex3fv(pos, vec[indices[i]]); + } + immEnd(); +} + static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin) { float size[3], cent[3]; @@ -7076,7 +8181,7 @@ static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin) gluDeleteQuadric(qobj); } -static void draw_bounding_volume(Object *ob, char type) +void draw_bounding_volume(Object *ob, char type) { BoundBox bb_local; BoundBox *bb = NULL; @@ -7177,7 +8282,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, RegionView3D *rv3d = ar->regiondata; Object *ob = base->object; - glDepthMask(0); + glDepthMask(GL_FALSE); if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { bool has_faces = false; @@ -7224,7 +8329,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } } - glDepthMask(1); + glDepthMask(GL_TRUE); } static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4]) @@ -7239,8 +8344,8 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const } ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ - glLineWidth(1); + glDepthMask(GL_FALSE); /* disable write in zbuffer, selected edge wires show better */ + glLineWidth(1.0f); if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { if (ED_view3d_boundbox_clip(rv3d, ob->bb)) { @@ -7259,7 +8364,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const } } - glDepthMask(1); + glDepthMask(GL_TRUE); ED_view3d_polygon_offset(rv3d, 0.0); } } @@ -7283,7 +8388,7 @@ static void draw_hooks(Object *ob) setlinestyle(0); } - glPointSize(3.0); + glPointSize(3.0f); glBegin(GL_POINTS); glVertex3fv(vec); glEnd(); @@ -7324,7 +8429,7 @@ static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data, setlinestyle(0); } -static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_wire_col[4]) +void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_wire_col[4]) { Object *ob = base->object; int colindex = 0; @@ -7418,7 +8523,7 @@ static void draw_object_matcap_check(View3D *v3d, Object *ob) v3d->flag2 |= V3D_SHOW_SOLID_MATCAP; } -static void draw_rigidbody_shape(Object *ob) +void draw_rigidbody_shape(Object *ob) { BoundBox *bb = NULL; float size[3], vec[8][3]; @@ -7650,9 +8755,23 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } } + /* TODO Viewport: draw only for selection */ + if (!IS_VIEWPORT_LEGACY(v3d)) { + if ((dflag & DRAW_PICKING) == 0) { + if ((dt == OB_BOUNDBOX) || ELEM(ob->type, OB_EMPTY, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + goto afterdraw; + } + } + } + switch (ob->type) { case OB_MESH: - empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + if (IS_VIEWPORT_LEGACY(v3d)) { + empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + } + else { + empty_object = draw_mesh_object_new(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); + } if ((dflag & DRAW_CONSTCOLOR) == 0) { /* mesh draws wire itself */ dtx &= ~OB_DRAWWIRE; @@ -7721,7 +8840,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short draw_empty_image(ob, dflag, ob_wire_col, v3d->multiview_eye); } else { - drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); + drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, ob_wire_col); } } break; @@ -7739,7 +8858,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short break; case OB_SPEAKER: if (!render_override) - drawspeaker(scene, v3d, rv3d, ob, dflag); + drawspeaker(ob_wire_col); break; case OB_LATTICE: if (!render_override) { @@ -7773,11 +8892,14 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short break; default: if (!render_override) { - drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS); + drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS, ob_wire_col); } break; } + /* TODO Viewport: some elements are being drawn for object selection only */ +afterdraw: + if (!render_override) { if (ob->soft /*&& dflag & OB_SBMOTION*/) { float mrt[3][3], msc[3][3], mtr[3][3]; @@ -7858,6 +8980,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* draw code for smoke, only draw domains */ if (smd && smd->domain) { SmokeDomainSettings *sds = smd->domain; + const bool show_smoke = (CFRA >= sds->point_cache[0]->startframe); float viewnormal[3]; glLoadMatrixf(rv3d->viewmat); @@ -7890,7 +9013,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } /* don't show smoke before simulation starts, this could be made an option in the future */ - if (sds->fluid && CFRA >= sds->point_cache[0]->startframe) { + if (sds->fluid && show_smoke) { float p0[3], p1[3]; /* get view vector */ @@ -7954,7 +9077,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (dtx && (G.f & G_RENDER_OGL) == 0) { if (dtx & OB_AXIS) { - drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS); + drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS, NULL); } if (dtx & OB_DRAWBOUNDOX) { draw_bounding_volume(ob, ob->boundtype); @@ -8041,10 +9164,15 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if ((base->sx != IS_CLIPPED) && (U.obcenter_dia != 0.0)) { + unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + /* TODO: short term, use DEPTH_ONLY shader or set appropriate color */ + /* TODO: long term, solve picking & selection problem better */ glPointSize(U.obcenter_dia); - glBegin(GL_POINTS); - glVertex3fv(ob->obmat[3]); - glEnd(); + immBegin(GL_POINTS, 1); + immVertex3fv(pos, ob->obmat[3]); + immEnd(); + immUnbindProgram(); } } else if ((dflag & DRAW_CONSTCOLOR) == 0) { @@ -8501,7 +9629,7 @@ void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object draw_empty_image(ob, DRAW_CONSTCOLOR, NULL, v3d->multiview_eye); } else { - drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); + drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, NULL); /* TODO: use proper color */ } break; } diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c index 9414d39467d..2baa6304cd9 100644 --- a/source/blender/editors/space_view3d/drawsimdebug.c +++ b/source/blender/editors/space_view3d/drawsimdebug.c @@ -40,6 +40,8 @@ #include "BKE_effect.h" +#include "GPU_immediate.h" + #include "view3d_intern.h" #include "BIF_gl.h" @@ -47,95 +49,129 @@ static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4]) { + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", GL_FLOAT, 3, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + + /* count element types */ GHashIterator iter; + int num_dots = 0; + int num_circles = 0; + int num_lines = 0; + int num_vectors = 0; + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { + SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + switch (elem->type) { + case SIM_DEBUG_ELEM_DOT: ++num_dots; break; + case SIM_DEBUG_ELEM_CIRCLE: ++num_circles; break; + case SIM_DEBUG_ELEM_LINE: ++num_lines; break; + case SIM_DEBUG_ELEM_VECTOR: ++num_vectors; break; + } + } /**** dots ****/ glPointSize(3.0f); - glBegin(GL_POINTS); + immBegin(GL_POINTS, num_dots); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_DOT) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + immAttrib3fv(color, elem->color); + immVertex3fv(pos, elem->v1); } - glEnd(); + immEnd(); /**** circles ****/ { - float circle[16][2] = { +#define CIRCLERES 16 + float circle[CIRCLERES][2] = { {0.000000, 1.000000}, {0.382683, 0.923880}, {0.707107, 0.707107}, {0.923880, 0.382683}, {1.000000, -0.000000}, {0.923880, -0.382683}, {0.707107, -0.707107}, {0.382683, -0.923880}, {-0.000000, -1.000000}, {-0.382683, -0.923880}, {-0.707107, -0.707107}, {-0.923879, -0.382684}, {-1.000000, 0.000000}, {-0.923879, 0.382684}, {-0.707107, 0.707107}, {-0.382683, 0.923880} }; + + immBegin(GL_LINES, num_circles * CIRCLERES * 2); + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); float radius = elem->v2[0]; - float co[3]; + float co[3], nco[3]; int i; if (elem->type != SIM_DEBUG_ELEM_CIRCLE) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glBegin(GL_LINE_LOOP); - for (i = 0; i < 16; ++i) { - co[0] = radius * circle[i][0]; - co[1] = radius * circle[i][1]; - co[2] = 0.0f; - mul_mat3_m4_v3(imat, co); - add_v3_v3(co, elem->v1); + immAttrib3fv(color, elem->color); + zero_v3(co); + for (i = 0; i <= CIRCLERES; ++i) { + int ni = i % CIRCLERES; + nco[0] = radius * circle[ni][0]; + nco[1] = radius * circle[ni][1]; + nco[2] = 0.0f; + mul_mat3_m4_v3(imat, nco); + add_v3_v3(nco, elem->v1); - glVertex3f(co[0], co[1], co[2]); + if (i > 0) { + immVertex3fv(pos, co); + immVertex3fv(pos, nco); + } + + copy_v3_v3(co, nco); } - glEnd(); } + + immEnd(); +#undef CIRCLERES } /**** lines ****/ - glBegin(GL_LINES); + immBegin(GL_LINES, num_lines * 2); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_LINE) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); - glVertex3f(elem->v2[0], elem->v2[1], elem->v2[2]); + immAttrib3fv(color, elem->color); + immVertex3fv(pos, elem->v1); + immVertex3fv(pos, elem->v2); } - glEnd(); + immEnd(); /**** vectors ****/ glPointSize(2.0f); - glBegin(GL_POINTS); + immBegin(GL_POINTS, num_vectors); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_VECTOR) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + immAttrib3fv(color, elem->color); + immVertex3fv(pos, elem->v1); } - glEnd(); + immEnd(); - glBegin(GL_LINES); + immBegin(GL_LINES, num_vectors * 2); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); float t[3]; if (elem->type != SIM_DEBUG_ELEM_VECTOR) continue; - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + immAttrib3fv(color, elem->color); + immVertex3fv(pos, elem->v1); add_v3_v3v3(t, elem->v1, elem->v2); - glVertex3f(t[0], t[1], t[2]); + immVertex3fv(pos, t); } - glEnd(); + immEnd(); + + immUnbindProgram(); /**** strings ****/ @@ -163,9 +199,6 @@ void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar) invert_m4_m4(imat, rv3d->viewmatob); -// glDepthMask(GL_FALSE); -// glEnable(GL_BLEND); - glPushMatrix(); glLoadMatrixf(rv3d->viewmat); @@ -174,7 +207,4 @@ void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar) view3d_cached_text_draw_end(v3d, ar, false, NULL); glPopMatrix(); - -// glDepthMask(GL_TRUE); -// glDisable(GL_BLEND); } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 075b1faf502..90fa54c7a16 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -57,6 +57,7 @@ #include "GPU_compositing.h" #include "GPU_framebuffer.h" #include "GPU_material.h" +#include "GPU_viewport.h" #include "BIF_gl.h" @@ -582,6 +583,11 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar) GPU_fx_compositor_destroy(rv3d->compositor); rv3d->compositor = NULL; } + + if (rv3d->viewport) { + GPU_viewport_free(rv3d->viewport); + rv3d->viewport = NULL; + } } static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) @@ -739,6 +745,9 @@ static void view3d_main_region_free(ARegion *ar) if (rv3d->compositor) { GPU_fx_compositor_destroy(rv3d->compositor); } + if (rv3d->viewport) { + GPU_viewport_free(rv3d->viewport); + } MEM_freeN(rv3d); ar->regiondata = NULL; @@ -763,6 +772,7 @@ static void *view3d_main_region_duplicate(void *poin) new->sms = NULL; new->smooth_timer = NULL; new->compositor = NULL; + new->viewport = NULL; return new; } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index f23e587e55d..8f6bd4aaac8 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -28,945 +28,328 @@ * \ingroup spview3d */ -#include <string.h> -#include <stdio.h> #include <math.h> -#include "DNA_armature_types.h" -#include "DNA_camera_types.h" -#include "DNA_customdata_types.h" -#include "DNA_object_types.h" -#include "DNA_group_types.h" -#include "DNA_mesh_types.h" -#include "DNA_key_types.h" -#include "DNA_lamp_types.h" -#include "DNA_scene_types.h" -#include "DNA_world_types.h" -#include "DNA_brush_types.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_jitter.h" -#include "BLI_utildefines.h" -#include "BLI_endian_switch.h" -#include "BLI_threads.h" +#include "BIF_gl.h" +#include "BIF_glutil.h" -#include "BKE_anim.h" #include "BKE_camera.h" #include "BKE_context.h" -#include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" -#include "BKE_image.h" -#include "BKE_key.h" -#include "BKE_main.h" +#include "BKE_scene.h" #include "BKE_object.h" -#include "BKE_global.h" #include "BKE_paint.h" -#include "BKE_scene.h" -#include "BKE_screen.h" #include "BKE_unit.h" -#include "BKE_movieclip.h" -#include "RE_engine.h" - -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" -#include "IMB_colormanagement.h" - -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "BLF_api.h" -#include "WM_api.h" +#include "BLI_math.h" +#include "BLI_rect.h" +#include "BLI_threads.h" -#include "BLF_api.h" -#include "BLT_translation.h" +#include "DNA_brush_types.h" +#include "DNA_camera_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_view3d_types.h" +#include "DNA_windowmanager_types.h" -#include "ED_armature.h" -#include "ED_keyframing.h" -#include "ED_gpencil.h" #include "ED_screen.h" -#include "ED_space_api.h" -#include "ED_screen_types.h" #include "ED_transform.h" +#include "GPU_matrix.h" +#include "GPU_immediate.h" +#include "GPU_material.h" +#include "GPU_viewport.h" + +#include "MEM_guardedalloc.h" + #include "UI_interface.h" -#include "UI_interface_icons.h" #include "UI_resources.h" -#include "GPU_draw.h" -#include "GPU_framebuffer.h" -#include "GPU_material.h" -#include "GPU_compositing.h" -#include "GPU_extensions.h" +#include "RE_engine.h" + +#include "WM_api.h" #include "view3d_intern.h" /* own include */ /* prototypes */ -static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar); -static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, - float winmat[4][4], const char *viewname); - -/* handy utility for drawing shapes in the viewport for arbitrary code. - * could add lines and points too */ -// #define DEBUG_DRAW -#ifdef DEBUG_DRAW -static void bl_debug_draw(void); -/* add these locally when using these functions for testing */ -extern void bl_debug_draw_quad_clear(void); -extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]); -extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]); -extern void bl_debug_color_set(const unsigned int col); -#endif +static void draw_all_objects(const bContext *C, ARegion *ar, const bool only_depth, const bool use_depth); -void circf(float x, float y, float rad) -{ - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_FILL); - - glPushMatrix(); - - glTranslatef(x, y, 0.0); - - gluDisk(qobj, 0.0, rad, 32, 1); - - glPopMatrix(); - - gluDeleteQuadric(qobj); -} - -void circ(float x, float y, float rad) -{ - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - - glPushMatrix(); - - glTranslatef(x, y, 0.0); - - gluDisk(qobj, 0.0, rad, 32, 1); - - glPopMatrix(); - - gluDeleteQuadric(qobj); -} - - -/* ********* custom clipping *********** */ - -static void view3d_draw_clipping(RegionView3D *rv3d) -{ - BoundBox *bb = rv3d->clipbb; - - if (bb) { - const unsigned int clipping_index[6][4] = { - {0, 1, 2, 3}, - {0, 4, 5, 1}, - {4, 7, 6, 5}, - {7, 3, 2, 6}, - {1, 5, 6, 2}, - {7, 4, 0, 3} - }; - - /* fill in zero alpha for rendering & re-projection [#31530] */ - unsigned char col[4]; - UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col); - glColor4ubv(col); - - glEnable(GL_BLEND); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, bb->vec); - glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index); - glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_BLEND); - } -} +typedef struct DrawData { + rcti border_rect; + bool render_border; + bool clip_border; + bool is_render; + GPUViewport *viewport; +} DrawData; -void ED_view3d_clipping_set(RegionView3D *rv3d) +static void view3d_draw_data_init(const bContext *C, ARegion *ar, RegionView3D *rv3d, DrawData *draw_data) { - double plane[4]; - const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6; - unsigned int a; + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); - for (a = 0; a < tot; a++) { - copy_v4db_v4fl(plane, rv3d->clip[a]); - glClipPlane(GL_CLIP_PLANE0 + a, plane); - glEnable(GL_CLIP_PLANE0 + a); - } -} + draw_data->is_render = (v3d->drawtype == OB_RENDER); -/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */ -void ED_view3d_clipping_disable(void) -{ - unsigned int a; + draw_data->render_border = ED_view3d_calc_render_border(scene, v3d, ar, &draw_data->border_rect); + draw_data->clip_border = (draw_data->render_border && !BLI_rcti_compare(&ar->drawrct, &draw_data->border_rect)); - for (a = 0; a < 6; a++) { - glDisable(GL_CLIP_PLANE0 + a); - } + draw_data->viewport = rv3d->viewport; } -void ED_view3d_clipping_enable(void) -{ - unsigned int a; - for (a = 0; a < 6; a++) { - glEnable(GL_CLIP_PLANE0 + a); - } -} +/* ******************** general functions ***************** */ -static bool view3d_clipping_test(const float co[3], const float clip[6][4]) +static bool use_depth_doit(Scene *scene, View3D *v3d) { - if (plane_point_side_v3(clip[0], co) > 0.0f) - if (plane_point_side_v3(clip[1], co) > 0.0f) - if (plane_point_side_v3(clip[2], co) > 0.0f) - if (plane_point_side_v3(clip[3], co) > 0.0f) - return false; + if (v3d->drawtype > OB_WIRE) + return true; - return true; + /* special case (depth for wire color) */ + if (v3d->drawtype <= OB_WIRE) { + if (scene->obedit && scene->obedit->type == OB_MESH) { + Mesh *me = scene->obedit->data; + if (me->drawflag & ME_DRAWEIGHT) { + return true; + } + } + } + return false; } -/* for 'local' ED_view3d_clipping_local must run first - * then all comparisons can be done in localspace */ -bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local) +static bool use_depth(const bContext *C) { - return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip); -} - -/* ********* end custom clipping *********** */ - - -static void drawgrid_draw(ARegion *ar, double wx, double wy, double x, double y, double dx) -{ - double verts[2][2]; - - x += (wx); - y += (wy); - - /* set fixed 'Y' */ - verts[0][1] = 0.0f; - verts[1][1] = (double)ar->winy; - - /* iter over 'X' */ - verts[0][0] = verts[1][0] = x - dx * floor(x / dx); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_DOUBLE, 0, verts); - - while (verts[0][0] < ar->winx) { - glDrawArrays(GL_LINES, 0, 2); - verts[0][0] = verts[1][0] = verts[0][0] + dx; - } - - /* set fixed 'X' */ - verts[0][0] = 0.0f; - verts[1][0] = (double)ar->winx; - - /* iter over 'Y' */ - verts[0][1] = verts[1][1] = y - dx * floor(y / dx); - while (verts[0][1] < ar->winy) { - glDrawArrays(GL_LINES, 0, 2); - verts[0][1] = verts[1][1] = verts[0][1] + dx; - } - - glDisableClientState(GL_VERTEX_ARRAY); + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + return use_depth_doit(scene, v3d); } -#define GRID_MIN_PX_D 6.0 -#define GRID_MIN_PX_F 6.0f - -static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit) +/** + * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore + */ +void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) { - /* extern short bgpicmode; */ RegionView3D *rv3d = ar->regiondata; - double wx, wy, x, y, fw, fx, fy, dx; - double vec4[4]; - unsigned char col[3], col2[3]; - - fx = rv3d->persmat[3][0]; - fy = rv3d->persmat[3][1]; - fw = rv3d->persmat[3][3]; - - wx = (ar->winx / 2.0); /* because of rounding errors, grid at wrong location */ - wy = (ar->winy / 2.0); - - x = (wx) * fx / fw; - y = (wy) * fy / fw; - - vec4[0] = vec4[1] = v3d->grid; - - vec4[2] = 0.0; - vec4[3] = 1.0; - mul_m4_v4d(rv3d->persmat, vec4); - fx = vec4[0]; - fy = vec4[1]; - fw = vec4[3]; - - dx = fabs(x - (wx) * fx / fw); - if (dx == 0) dx = fabs(y - (wy) * fy / fw); - - glLineWidth(1.0f); - glDepthMask(GL_FALSE); /* disable write in zbuffer */ - /* check zoom out */ - UI_ThemeColor(TH_GRID); - - if (unit->system) { - /* Use GRID_MIN_PX * 2 for units because very very small grid - * items are less useful when dealing with units */ - const void *usys; - int len, i; - double dx_scalar; - float blend_fac; - - bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len); - - if (usys) { - i = len; - while (i--) { - double scalar = bUnit_GetScaler(usys, i); - - dx_scalar = dx * scalar / (double)unit->scale_length; - if (dx_scalar < (GRID_MIN_PX_D * 2.0)) - continue; + /* setup window matrices */ + if (winmat) + copy_m4_m4(rv3d->winmat, winmat); + else + view3d_winmatrix_set(ar, v3d, NULL); - /* Store the smallest drawn grid size units name so users know how big each grid cell is */ - if (*grid_unit == NULL) { - *grid_unit = bUnit_GetNameDisplay(usys, i); - rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length); - } - blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar); + /* setup view matrix */ + if (viewmat) + copy_m4_m4(rv3d->viewmat, viewmat); + else + view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - /* tweak to have the fade a bit nicer */ - blend_fac = (blend_fac * blend_fac) * 2.0f; - CLAMP(blend_fac, 0.3f, 1.0f); + /* update utility matrices */ + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + invert_m4_m4(rv3d->persinv, rv3d->persmat); + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + /* calculate GLSL view dependent values */ - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, blend_fac); + /* store window coordinates scaling/offset */ + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + rctf cameraborder; + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); + rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); + rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); - drawgrid_draw(ar, wx, wy, x, y, dx_scalar); - } - } + rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx; + rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy; } else { - const double sublines = v3d->gridsubdiv; - const float sublines_fl = v3d->gridsubdiv; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - if (dx < GRID_MIN_PX_D) { - /* pass */ - } - else { - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx); - } - } - else { /* start blending out */ - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, sublines * dx); - } - } - else { /* start blending out (GRID_MIN_PX < dx < (GRID_MIN_PX * 10)) */ - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, sublines * dx); - } - } - else { - if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ - rv3d->gridview /= sublines_fl; - dx /= sublines; - if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ - rv3d->gridview /= sublines_fl; - dx /= sublines; - if (dx > (GRID_MIN_PX_D * 10.0)) { - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx); - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } - } + rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; + rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f; } + /* calculate pixelsize factor once, is used for lamps and obcenters */ + { + /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])' + * because of float point precision problems at large values [#23908] */ + float v1[3], v2[3]; + float len_px, len_sc; - x += (wx); - y += (wy); - UI_GetThemeColor3ubv(TH_GRID, col); + v1[0] = rv3d->persmat[0][0]; + v1[1] = rv3d->persmat[1][0]; + v1[2] = rv3d->persmat[2][0]; - setlinestyle(0); - - /* center cross */ - /* horizontal line */ - if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) - UI_make_axis_color(col, col2, 'Y'); - else UI_make_axis_color(col, col2, 'X'); - glColor3ubv(col2); - - fdrawline(0.0, y, (float)ar->winx, y); - - /* vertical line */ - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) - UI_make_axis_color(col, col2, 'Y'); - else UI_make_axis_color(col, col2, 'Z'); - glColor3ubv(col2); + v2[0] = rv3d->persmat[0][1]; + v2[1] = rv3d->persmat[1][1]; + v2[2] = rv3d->persmat[2][1]; - fdrawline(x, 0.0, x, (float)ar->winy); + len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); + len_sc = (float)MAX2(ar->winx, ar->winy); - glDepthMask(GL_TRUE); /* enable write in zbuffer */ + rv3d->pixsize = len_px / len_sc; + } } -#undef GRID_MIN_PX -/** could move this elsewhere, but tied into #ED_view3d_grid_scale */ -float ED_scene_grid_scale(Scene *scene, const char **grid_unit) +static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) { - /* apply units */ - if (scene->unit.system) { - const void *usys; - int len; - - bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len); - - if (usys) { - int i = bUnit_GetBaseUnit(usys); - if (grid_unit) - *grid_unit = bUnit_GetNameDisplay(usys, i); - return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length; - } - } + RegionView3D *rv3d = ar->regiondata; - return 1.0f; -} + ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat); -float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) -{ - return v3d->grid * ED_scene_grid_scale(scene, grid_unit); + /* set for opengl */ + /* TODO(merwin): transition to GPU_matrix API */ + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(rv3d->winmat); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(rv3d->viewmat); } -static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth) +static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d) { - float grid, grid_scale; - unsigned char col_grid[3]; - const int gridlines = v3d->gridlines / 2; - - if (v3d->gridlines < 3) return; - - /* use 'grid_scale' instead of 'v3d->grid' from now on */ - grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit); - grid = gridlines * grid_scale; - - if (!write_depth) - glDepthMask(GL_FALSE); - - UI_GetThemeColor3ubv(TH_GRID, col_grid); - - glLineWidth(1); - - /* draw the Y axis and/or grid lines */ - if (v3d->gridflag & V3D_SHOW_FLOOR) { - const int sublines = v3d->gridsubdiv; - float vert[4][3] = {{0.0f}}; - unsigned char col_bg[3]; - unsigned char col_grid_emphasise[3], col_grid_light[3]; - int a; - int prev_emphasise = -1; - - UI_GetThemeColor3ubv(TH_BACK, col_bg); - - /* emphasise division lines lighter instead of darker, if background is darker than grid */ - UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10); - UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise, - (((col_grid[0] + col_grid[1] + col_grid[2]) + 30) > - (col_bg[0] + col_bg[1] + col_bg[2])) ? 20 : -10); - - /* set fixed axis */ - vert[0][0] = vert[2][1] = grid; - vert[1][0] = vert[3][1] = -grid; - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vert); + wmWindow *win = CTX_wm_window(C); - for (a = -gridlines; a <= gridlines; a++) { - const float line = a * grid_scale; - const int is_emphasise = (a % sublines) == 0; + if ((scene->r.scemode & R_MULTIVIEW) == 0) + return false; - if (is_emphasise != prev_emphasise) { - glColor3ubv(is_emphasise ? col_grid_emphasise : col_grid_light); - prev_emphasise = is_emphasise; - } + if (WM_stereo3d_enabled(win, true) == false) + return false; - /* set variable axis */ - vert[0][1] = vert[1][1] = vert[2][0] = vert[3][0] = line; + if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) + return false; - glDrawArrays(GL_LINES, 0, 4); - } + if (scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) { + if (v3d->stereo3d_camera == STEREO_MONO_ID) + return false; - glDisableClientState(GL_VERTEX_ARRAY); - } - - /* draw the Z axis line */ - /* check for the 'show Z axis' preference */ - if (v3d->gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) { - glBegin(GL_LINES); - int axis; - for (axis = 0; axis < 3; axis++) { - if (v3d->gridflag & (V3D_SHOW_X << axis)) { - float vert[3]; - unsigned char tcol[3]; - - UI_make_axis_color(col_grid, tcol, 'X' + axis); - glColor3ubv(tcol); - - zero_v3(vert); - vert[axis] = grid; - glVertex3fv(vert); - vert[axis] = -grid; - glVertex3fv(vert); - } - } - glEnd(); + return BKE_scene_multiview_is_stereo3d(&scene->r); } - - glDepthMask(GL_TRUE); -} - -static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d) -{ - int co[2]; - - /* we don't want the clipping for cursor */ - if (ED_view3d_project_int_global(ar, ED_view3d_cursor3d_get(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - const float f5 = 0.25f * U.widget_unit; - const float f10 = 0.5f * U.widget_unit; - const float f20 = U.widget_unit; - - glLineWidth(1); - setlinestyle(0); - cpack(0xFF); - circ((float)co[0], (float)co[1], f10); - setlinestyle(4); - cpack(0xFFFFFF); - circ((float)co[0], (float)co[1], f10); - setlinestyle(0); - - UI_ThemeColor(TH_VIEW_OVERLAY); - sdrawline(co[0] - f20, co[1], co[0] - f5, co[1]); - sdrawline(co[0] + f5, co[1], co[0] + f20, co[1]); - sdrawline(co[0], co[1] - f20, co[0], co[1] - f5); - sdrawline(co[0], co[1] + f5, co[0], co[1] + f20); - } + return true; } -/* Draw a live substitute of the view icon, which is always shown - * colors copied from transform_manipulator.c, we should keep these matching. */ -static void draw_view_axis(RegionView3D *rv3d, rcti *rect) +/* setup the view and win matrices for the multiview cameras + * + * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called + * we have no winmatrix (i.e., projection matrix) defined at that time. + * Since the camera and the camera shift are needed for the winmat calculation + * we do a small hack to replace it temporarily so we don't need to change the + * view3d)main_region_setup_view() code to account for that. + */ +static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) { - const float k = U.rvisize * U.pixelsize; /* axis size */ - const float toll = 0.5; /* used to see when view is quasi-orthogonal */ - float startx = k + 1.0f; /* axis center in screen coordinates, x=y */ - float starty = k + 1.0f; - float ydisp = 0.0; /* vertical displacement to allow obj info text */ - int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */ - float vec[3]; - float dx, dy; + bool is_left; + const char *names[2] = { STEREO_LEFT_NAME, STEREO_RIGHT_NAME }; + const char *viewname; - int axis_order[3] = {0, 1, 2}; - int axis_i; + /* show only left or right camera */ + if (v3d->stereo3d_camera != STEREO_3D_ID) + v3d->multiview_eye = v3d->stereo3d_camera; - startx += rect->xmin; - starty += rect->ymin; + is_left = v3d->multiview_eye == STEREO_LEFT_ID; + viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID]; - axis_sort_v3(rv3d->viewinv[2], axis_order); + /* update the viewport matrices with the new camera */ + if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { + Camera *data; + float viewmat[4][4]; + float shiftx; - /* thickness of lines is proportional to k */ - glLineWidth(2); + data = (Camera *)v3d->camera->data; + shiftx = data->shiftx; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + BLI_lock_thread(LOCK_VIEW3D); + data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname); - for (axis_i = 0; axis_i < 3; axis_i++) { - int i = axis_order[axis_i]; - const char axis_text[2] = {'x' + i, '\0'}; + BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); - zero_v3(vec); - vec[i] = 1.0f; - mul_qt_v3(rv3d->viewquat, vec); - dx = vec[0] * k; - dy = vec[1] * k; + data->shiftx = shiftx; + BLI_unlock_thread(LOCK_VIEW3D); + } + else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ + float viewmat[4][4]; + Object *view_ob = v3d->camera; + Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - UI_ThemeColorShadeAlpha(TH_AXIS_X + i, 0, bright); - glBegin(GL_LINES); - glVertex2f(startx, starty + ydisp); - glVertex2f(startx + dx, starty + dy + ydisp); - glEnd(); + BLI_lock_thread(LOCK_VIEW3D); + v3d->camera = camera; - if (fabsf(dx) > toll || fabsf(dy) > toll) { - BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1); + BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); - /* BLF_draw_default disables blending */ - glEnable(GL_BLEND); - } + v3d->camera = view_ob; + BLI_unlock_thread(LOCK_VIEW3D); } - - glDisable(GL_BLEND); } -#ifdef WITH_INPUT_NDOF -/* draw center and axis of rotation for ongoing 3D mouse navigation */ -static void draw_rotation_guide(RegionView3D *rv3d) -{ - float o[3]; /* center of rotation */ - float end[3]; /* endpoints for drawing */ - - float color[4] = {0.0f, 0.4235f, 1.0f, 1.0f}; /* bright blue so it matches device LEDs */ - - negate_v3_v3(o, rv3d->ofs); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPointSize(5); - glEnable(GL_POINT_SMOOTH); - glDepthMask(0); /* don't overwrite zbuf */ - - if (rv3d->rot_angle != 0.0f) { - /* -- draw rotation axis -- */ - float scaled_axis[3]; - const float scale = rv3d->dist; - mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale); +/* ******************** debug ***************** */ +#define VIEW3D_DRAW_DEBUG 1 +/* TODO: expand scope of this flag so UI reflects the underlying code */ - glBegin(GL_LINE_STRIP); - color[3] = 0.0f; /* more transparent toward the ends */ - glColor4fv(color); - add_v3_v3v3(end, o, scaled_axis); - glVertex3fv(end); +#if VIEW3D_DRAW_DEBUG -#if 0 - color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */ - /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */ -#endif +static void view3d_draw_debug_store_depth(ARegion *ar, DrawData *draw_data) +{ + GPUViewport *viewport = draw_data->viewport; + GLint viewport_size[4]; + glGetIntegerv(GL_VIEWPORT, viewport_size); - color[3] = 0.5f; /* more opaque toward the center */ - glColor4fv(color); - glVertex3fv(o); + const int x = viewport_size[0]; + const int y = viewport_size[1]; + const int w = viewport_size[2]; + const int h = viewport_size[3]; - color[3] = 0.0f; - glColor4fv(color); - sub_v3_v3v3(end, o, scaled_axis); - glVertex3fv(end); - glEnd(); - - /* -- draw ring around rotation center -- */ + if (GPU_viewport_debug_depth_is_valid(viewport)) { + if ((GPU_viewport_debug_depth_width(viewport) != w) || + (GPU_viewport_debug_depth_height(viewport) != h)) { -#define ROT_AXIS_DETAIL 13 - - const float s = 0.05f * scale; - const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL); - float angle; - int i; - - float q[4]; /* rotate ring so it's perpendicular to axis */ - const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f; - if (!upright) { - const float up[3] = {0.0f, 0.0f, 1.0f}; - float vis_angle, vis_axis[3]; - - cross_v3_v3v3(vis_axis, up, rv3d->rot_axis); - vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis)); - axis_angle_to_quat(q, vis_axis, vis_angle); - } - - color[3] = 0.25f; /* somewhat faint */ - glColor4fv(color); - glBegin(GL_LINE_LOOP); - for (i = 0, angle = 0.0f; i < ROT_AXIS_DETAIL; ++i, angle += step) { - float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f}; - - if (!upright) { - mul_qt_v3(q, p); - } - - add_v3_v3(p, o); - glVertex3fv(p); - } - glEnd(); - -#undef ROT_AXIS_DETAIL + GPU_viewport_debug_depth_free(viewport); } - - color[3] = 1.0f; /* solid dot */ } - else - color[3] = 0.5f; /* see-through dot */ - - /* -- draw rotation center -- */ - glColor4fv(color); - glBegin(GL_POINTS); - glVertex3fv(o); - glEnd(); - -#if 0 - /* find screen coordinates for rotation center, then draw pretty icon */ - mul_m4_v3(rv3d->persinv, rot_center); - UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN); - /* ^^ just playing around, does not work */ -#endif - glDisable(GL_BLEND); - glDisable(GL_POINT_SMOOTH); - glDepthMask(1); -} -#endif /* WITH_INPUT_NDOF */ - -static void draw_view_icon(RegionView3D *rv3d, rcti *rect) -{ - BIFIconID icon; - - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) - icon = ICON_AXIS_TOP; - else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) - icon = ICON_AXIS_FRONT; - else if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) - icon = ICON_AXIS_SIDE; - else return; - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon); - - glDisable(GL_BLEND); -} - -static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d) -{ - const char *name = NULL; - - switch (rv3d->view) { - case RV3D_VIEW_FRONT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho"); - else name = IFACE_("Front Persp"); - break; - case RV3D_VIEW_BACK: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho"); - else name = IFACE_("Back Persp"); - break; - case RV3D_VIEW_TOP: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Ortho"); - else name = IFACE_("Top Persp"); - break; - case RV3D_VIEW_BOTTOM: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Ortho"); - else name = IFACE_("Bottom Persp"); - break; - case RV3D_VIEW_RIGHT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Ortho"); - else name = IFACE_("Right Persp"); - break; - case RV3D_VIEW_LEFT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Ortho"); - else name = IFACE_("Left Persp"); - break; - - default: - if (rv3d->persp == RV3D_CAMOB) { - if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) { - Camera *cam; - cam = v3d->camera->data; - if (cam->type == CAM_PERSP) { - name = IFACE_("Camera Persp"); - } - else if (cam->type == CAM_ORTHO) { - name = IFACE_("Camera Ortho"); - } - else { - BLI_assert(cam->type == CAM_PANO); - name = IFACE_("Camera Pano"); - } - } - else { - name = IFACE_("Object as Camera"); - } - } - else { - name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Ortho") : IFACE_("User Persp"); - } - break; + if (!GPU_viewport_debug_depth_is_valid(viewport)) { + char error[256]; + if (!GPU_viewport_debug_depth_create(viewport, w, h, 0, error)) { + fprintf(stderr, "Failed to create depth buffer for debug: %s\n", error); + return; + } } - - return name; + + GPU_viewport_debug_depth_store(viewport, x, y); } -static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect) +static void view3d_draw_debug_post_solid(const bContext *C, ARegion *ar, DrawData *draw_data) { - RegionView3D *rv3d = ar->regiondata; - const char *name = view3d_get_name(v3d, rv3d); - /* increase size for unicode languages (Chinese in utf-8...) */ -#ifdef WITH_INTERNATIONAL - char tmpstr[96]; -#else - char tmpstr[32]; -#endif + View3D *v3d = CTX_wm_view3d(C); - if (v3d->localvd) { - BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name); - name = tmpstr; + if ((v3d->tmp_compat_flag & V3D_DEBUG_SHOW_SCENE_DEPTH) != 0) { + view3d_draw_debug_store_depth(ar, draw_data); } - - UI_ThemeColor(TH_TEXT_HI); -#ifdef WITH_INTERNATIONAL - BLF_draw_default(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); -#else - BLF_draw_default_ascii(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); -#endif } -/* draw info beside axes in bottom left-corner: - * framenum, object name, bone name (if available), marker name (if available) - */ - -static void draw_selected_name(Scene *scene, Object *ob, rcti *rect) +static void view3d_draw_debug(const bContext *C, ARegion *ar, DrawData *draw_data) { - const int cfra = CFRA; - const char *msg_pin = " (Pinned)"; - const char *msg_sep = " : "; - - char info[300]; - const char *markern; - char *s = info; - short offset = 1.5f * UI_UNIT_X + rect->xmin; - - s += sprintf(s, "(%d)", cfra); - - /* - * info can contain: - * - a frame (7 + 2) - * - 3 object names (MAX_NAME) - * - 2 BREAD_CRUMB_SEPARATORs (6) - * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room! - * - a marker name (MAX_NAME + 3) - */ - - /* get name of marker on current frame (if available) */ - markern = BKE_scene_find_marker_name(scene, cfra); - - /* check if there is an object */ - if (ob) { - *s++ = ' '; - s += BLI_strcpy_rlen(s, ob->id.name + 2); - - /* name(s) to display depends on type of object */ - if (ob->type == OB_ARMATURE) { - bArmature *arm = ob->data; - - /* show name of active bone too (if possible) */ - if (arm->edbo) { - if (arm->act_edbone) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_edbone->name); - } - } - else if (ob->mode & OB_MODE_POSE) { - if (arm->act_bone) { + View3D *v3d = CTX_wm_view3d(C); - if (arm->act_bone->layer & arm->layer) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_bone->name); - } - } - } - } - else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { - Key *key = NULL; - KeyBlock *kb = NULL; - - /* try to display active bone and active shapekey too (if they exist) */ - - if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) { - Object *armobj = BKE_object_pose_armature_get(ob); - if (armobj && armobj->mode & OB_MODE_POSE) { - bArmature *arm = armobj->data; - if (arm->act_bone) { - if (arm->act_bone->layer & arm->layer) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_bone->name); - } - } - } - } + if ((v3d->tmp_compat_flag & V3D_DEBUG_SHOW_COMBINED_DEPTH) != 0) { + /* store */ + view3d_draw_debug_store_depth(ar, draw_data); + } - key = BKE_key_from_object(ob); - if (key) { - kb = BLI_findlink(&key->block, ob->shapenr - 1); - if (kb) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, kb->name); - if (ob->shapeflag & OB_SHAPE_LOCK) { - s += BLI_strcpy_rlen(s, IFACE_(msg_pin)); - } - } - } + if (((v3d->tmp_compat_flag & V3D_DEBUG_SHOW_SCENE_DEPTH) != 0) || + ((v3d->tmp_compat_flag & V3D_DEBUG_SHOW_COMBINED_DEPTH) != 0)) + { + /* draw */ + if (GPU_viewport_debug_depth_is_valid(draw_data->viewport)) { + GPU_viewport_debug_depth_draw(draw_data->viewport, v3d->debug.znear, v3d->debug.zfar); } - - /* color depends on whether there is a keyframe */ - if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) - UI_ThemeColor(TH_TIME_KEYFRAME); - else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) - UI_ThemeColor(TH_TIME_GP_KEYFRAME); - else - UI_ThemeColor(TH_TEXT_HI); } else { - /* no object */ - if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) - UI_ThemeColor(TH_TIME_GP_KEYFRAME); - else - UI_ThemeColor(TH_TEXT_HI); + /* cleanup */ + GPU_viewport_debug_depth_free(draw_data->viewport); } +} - if (markern) { - s += sprintf(s, " <%s>", markern); - } - - if (U.uiflag & USER_SHOW_ROTVIEWICON) - offset = U.widget_unit + (U.rvisize * 2) + rect->xmin; +#endif /* VIEW3D_DRAW_DEBUG */ - BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info)); -} +/* ******************** view border ***************** */ static void view3d_camera_border( const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, @@ -1021,7 +404,7 @@ void ED_view3d_calc_camera_border( view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false); } -static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float fac) +static void drawviewborder_grid3(unsigned pos, float x1, float x2, float y1, float y2, float fac) { float x3, y3, x4, y4; @@ -1030,29 +413,29 @@ static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float f x4 = x1 + (1.0f - fac) * (x2 - x1); y4 = y1 + (1.0f - fac) * (y2 - y1); - glBegin(GL_LINES); - glVertex2f(x1, y3); - glVertex2f(x2, y3); + immBegin(GL_LINES, 8); + immVertex2f(pos, x1, y3); + immVertex2f(pos, x2, y3); - glVertex2f(x1, y4); - glVertex2f(x2, y4); + immVertex2f(pos, x1, y4); + immVertex2f(pos, x2, y4); - glVertex2f(x3, y1); - glVertex2f(x3, y2); + immVertex2f(pos, x3, y1); + immVertex2f(pos, x3, y2); - glVertex2f(x4, y1); - glVertex2f(x4, y2); - glEnd(); + immVertex2f(pos, x4, y1); + immVertex2f(pos, x4, y2); + immEnd(); } /* harmonious triangle */ -static void drawviewborder_triangle(float x1, float x2, float y1, float y2, const char golden, const char dir) +static void drawviewborder_triangle(unsigned pos, float x1, float x2, float y1, float y2, const char golden, const char dir) { float ofs; float w = x2 - x1; float h = y2 - y1; - glBegin(GL_LINES); + immBegin(GL_LINES, 6); if (w > h) { if (golden) { ofs = w * (1.0f - (1.0f / 1.61803399f)); @@ -1062,14 +445,14 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons } if (dir == 'B') SWAP(float, y1, y2); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); - glVertex2f(x2, y1); - glVertex2f(x1 + (w - ofs), y2); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x1 + (w - ofs), y2); - glVertex2f(x1, y2); - glVertex2f(x1 + ofs, y1); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x1 + ofs, y1); } else { if (golden) { @@ -1080,16 +463,16 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons } if (dir == 'B') SWAP(float, x1, x2); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); - glVertex2f(x2, y1); - glVertex2f(x1, y1 + ofs); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x1, y1 + ofs); - glVertex2f(x1, y2); - glVertex2f(x2, y1 + (h - ofs)); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y1 + (h - ofs)); } - glEnd(); + immEnd(); } static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) @@ -1105,14 +488,14 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) return; if (v3d->camera->type == OB_CAMERA) ca = v3d->camera->data; - + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); /* the offsets */ x1 = viewborder.xmin; y1 = viewborder.ymin; x2 = viewborder.xmax; y2 = viewborder.ymax; - + glLineWidth(1.0f); /* apply offsets so the real 3D camera shows through */ @@ -1126,43 +509,47 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) y1i = (int)(y1 - 1.0001f); x2i = (int)(x2 + (1.0f - 0.0001f)); y2i = (int)(y2 + (1.0f - 0.0001f)); - + + /* use the same program for everything */ + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* passepartout, specified in camera edit buttons */ if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) { const float winx = (ar->winx + 1); const float winy = (ar->winy + 1); - if (ca->passepartalpha == 1.0f) { - glColor3f(0, 0, 0); - } - else { + float alpha = 1.0f; + + if (ca->passepartalpha != 1.0f) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glColor4f(0, 0, 0, ca->passepartalpha); + alpha = ca->passepartalpha; } + immUniformColor4f(0.0f, 0.0f, 0.0f, alpha); + if (x1i > 0.0f) - glRectf(0.0, winy, x1i, 0.0); + immRectf(pos, 0.0f, winy, x1i, 0.0f); if (x2i < winx) - glRectf(x2i, winy, winx, 0.0); + immRectf(pos, x2i, winy, winx, 0.0f); if (y2i < winy) - glRectf(x1i, winy, x2i, y2i); + immRectf(pos, x1i, winy, x2i, y2i); if (y2i > 0.0f) - glRectf(x1i, y1i, x2i, 0.0); - + immRectf(pos, x1i, y1i, x2i, 0.0f); + glDisable(GL_BLEND); } setlinestyle(0); - UI_ThemeColor(TH_BACK); - - fdrawbox(x1i, y1i, x2i, y2i); + immUniformThemeColor(TH_BACK); + imm_draw_line_box(pos, x1i, y1i, x2i, y2i); #ifdef VIEW3D_CAMERA_BORDER_HACK if (view3d_camera_border_hack_test == true) { - glColor3ubv(view3d_camera_border_hack_col); - fdrawbox(x1i + 1, y1i + 1, x2i - 1, y2i - 1); + immUniformColor3ubv(view3d_camera_border_hack_col); + imm_draw_line_box(pos, x1i + 1, y1i + 1, x2i - 1, y2i - 1); view3d_camera_border_hack_test = false; } #endif @@ -1171,12 +558,12 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) /* outer line not to confuse with object selecton */ if (v3d->flag2 & V3D_LOCK_CAMERA) { - UI_ThemeColor(TH_REDALERT); - fdrawbox(x1i - 1, y1i - 1, x2i + 1, y2i + 1); + immUniformThemeColor(TH_REDALERT); + imm_draw_line_box(pos, x1i - 1, y1i - 1, x2i + 1, y2i + 1); } - UI_ThemeColor(TH_VIEW_OVERLAY); - fdrawbox(x1i, y1i, x2i, y2i); + immUniformThemeColor(TH_VIEW_OVERLAY); + imm_draw_line_box(pos, x1i, y1i, x2i, y2i); /* border */ if (scene->r.mode & R_BORDER) { @@ -1187,8 +574,8 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1); y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1); - cpack(0x4040FF); - sdrawbox(x3, y3, x4, y4); + imm_cpack(0x4040FF); + imm_draw_line_box(pos, x3, y3, x4, y4); } /* safety border */ @@ -1196,71 +583,74 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) if (ca->dtx & CAM_DTX_CENTER) { float x3, y3; - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - x3 = x1 + 0.5f * (x2 - x1); y3 = y1 + 0.5f * (y2 - y1); - glBegin(GL_LINES); - glVertex2f(x1, y3); - glVertex2f(x2, y3); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + immBegin(GL_LINES, 4); - glVertex2f(x3, y1); - glVertex2f(x3, y2); - glEnd(); + immVertex2f(pos, x1, y3); + immVertex2f(pos, x2, y3); + + immVertex2f(pos, x3, y1); + immVertex2f(pos, x3, y2); + + immEnd(); } if (ca->dtx & CAM_DTX_CENTER_DIAG) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - glBegin(GL_LINES); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + immBegin(GL_LINES, 4); - glVertex2f(x1, y2); - glVertex2f(x2, y1); - glEnd(); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); + + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y1); + + immEnd(); } if (ca->dtx & CAM_DTX_THIRDS) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_grid3(x1, x2, y1, y2, 1.0f / 3.0f); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_grid3(pos, x1, x2, y1, y2, 1.0f / 3.0f); } if (ca->dtx & CAM_DTX_GOLDEN) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_grid3(x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f)); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_grid3(pos, x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f)); } if (ca->dtx & CAM_DTX_GOLDEN_TRI_A) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 0, 'A'); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_triangle(pos, x1, x2, y1, y2, 0, 'A'); } if (ca->dtx & CAM_DTX_GOLDEN_TRI_B) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 0, 'B'); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_triangle(pos, x1, x2, y1, y2, 0, 'B'); } if (ca->dtx & CAM_DTX_HARMONY_TRI_A) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 1, 'A'); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_triangle(pos, x1, x2, y1, y2, 1, 'A'); } if (ca->dtx & CAM_DTX_HARMONY_TRI_B) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 1, 'B'); + immUniformThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + drawviewborder_triangle(pos, x1, x2, y1, y2, 1, 'B'); } if (ca->flag & CAM_SHOW_SAFE_MARGINS) { UI_draw_safe_areas( - x1, x2, y1, y2, + pos, x1, x2, y1, y2, scene->safe_areas.title, scene->safe_areas.action); if (ca->flag & CAM_SHOW_SAFE_CENTER) { UI_draw_safe_areas( - x1, x2, y1, y2, + pos, x1, x2, y1, y2, scene->safe_areas.title_center, scene->safe_areas.action_center); } @@ -1298,8 +688,9 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) } /* draw */ - UI_ThemeColorShade(TH_VIEW_OVERLAY, 100); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f); + float color[4]; + UI_GetThemeColorShade4fv(TH_VIEW_OVERLAY, 100, color); + UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f, color); } } @@ -1312,1387 +703,753 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) x1i, y1i - (0.7f * U.widget_unit), 0.0f, v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2); } -} -/* *********************** backdraw for selection *************** */ + immUnbindProgram(); +} -static void backdrawview3d(Scene *scene, wmWindow *win, ARegion *ar, View3D *v3d) +static void drawrenderborder(ARegion *ar, View3D *v3d) { - RegionView3D *rv3d = ar->regiondata; - struct Base *base = scene->basact; - int multisample_enabled; - - BLI_assert(ar->regiontype == RGN_TYPE_WINDOW); + /* use the same program for everything */ + unsigned pos = add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) || - BKE_paint_select_face_test(base->object))) - { - /* do nothing */ - } - /* texture paint mode sampling */ - else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) && - (v3d->drawtype > OB_WIRE)) - { - /* do nothing */ - } - else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) && - V3D_IS_ZBUF(v3d)) - { - /* do nothing */ - } - else if (scene->obedit && - V3D_IS_ZBUF(v3d)) - { - /* do nothing */ - } - else { - v3d->flag &= ~V3D_INVALID_BACKBUF; - return; - } - - if (!(v3d->flag & V3D_INVALID_BACKBUF)) - return; + glLineWidth(1.0f); + setlinestyle(3); + imm_cpack(0x4040FF); -#if 0 - if (test) { - if (qtest()) { - addafterqueue(ar->win, BACKBUFDRAW, 1); - return; - } - } -#endif + imm_draw_line_box( + pos, v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy, + v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy); - if (v3d->drawtype > OB_WIRE) v3d->zbuf = true; - - /* dithering and AA break color coding, so disable */ - glDisable(GL_DITHER); - - multisample_enabled = glIsEnabled(GL_MULTISAMPLE); - if (multisample_enabled) - glDisable(GL_MULTISAMPLE); - - if (win->multisamples != USER_MULTISAMPLE_NONE) { - /* for multisample we use an offscreen FBO. multisample drawing can fail - * with color coded selection drawing, and reading back depths from such - * a buffer can also cause a few seconds freeze on OS X / NVidia. */ - int w = BLI_rcti_size_x(&ar->winrct); - int h = BLI_rcti_size_y(&ar->winrct); - char error[256]; + setlinestyle(0); - if (rv3d->gpuoffscreen) { - if (GPU_offscreen_width(rv3d->gpuoffscreen) != w || - GPU_offscreen_height(rv3d->gpuoffscreen) != h) - { - GPU_offscreen_free(rv3d->gpuoffscreen); - rv3d->gpuoffscreen = NULL; - } - } + immUnbindProgram(); +} - if (!rv3d->gpuoffscreen) { - rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error); +/* ******************** offline engine ***************** */ - if (!rv3d->gpuoffscreen) - fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); - } - } +static bool view3d_draw_render_draw(const bContext *C, Scene *scene, + ARegion *ar, View3D *v3d, + bool clip_border, const rcti *border_rect) +{ + RegionView3D *rv3d = ar->regiondata; + RenderEngineType *type; + GLint scissor[4]; - if (rv3d->gpuoffscreen) - GPU_offscreen_bind(rv3d->gpuoffscreen, true); - else - glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); + /* create render engine */ + if (!rv3d->render_engine) { + RenderEngine *engine; - glClearColor(0.0, 0.0, 0.0, 0.0); - if (v3d->zbuf) { - glEnable(GL_DEPTH_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - else { - glClear(GL_COLOR_BUFFER_BIT); - glDisable(GL_DEPTH_TEST); - } - - if (rv3d->rflag & RV3D_CLIPPING) - ED_view3d_clipping_set(rv3d); - - G.f |= G_BACKBUFSEL; - - if (base && (base->lay & v3d->lay)) - draw_object_backbufsel(scene, v3d, rv3d, base->object); - - if (rv3d->gpuoffscreen) - GPU_offscreen_unbind(rv3d->gpuoffscreen, true); - else - ar->swap = 0; /* mark invalid backbuf for wm draw */ + type = RE_engines_find(scene->r.engine); - v3d->flag &= ~V3D_INVALID_BACKBUF; + if (!(type->view_update && type->view_draw)) + return false; - G.f &= ~G_BACKBUFSEL; - v3d->zbuf = false; - glDisable(GL_DEPTH_TEST); - glEnable(GL_DITHER); - if (multisample_enabled) - glEnable(GL_MULTISAMPLE); + engine = RE_engine_create_ex(type, true); - if (rv3d->rflag & RV3D_CLIPPING) - ED_view3d_clipping_disable(); -} + engine->tile_x = scene->r.tilex; + engine->tile_y = scene->r.tiley; -void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) -{ - RegionView3D *rv3d = ar->regiondata; + type->view_update(engine, C); - if (rv3d->gpuoffscreen) { - GPU_offscreen_bind(rv3d->gpuoffscreen, true); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - glReadPixels(x, y, w, h, format, type, data); - GPU_offscreen_unbind(rv3d->gpuoffscreen, true); - } - else { - glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); + rv3d->render_engine = engine; } -} -/* XXX depth reading exception, for code not using gpu offscreen */ -static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) -{ + /* background draw */ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + ED_region_pixelspace(ar); - glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); -} + if (clip_border) { + /* for border draw, we only need to clear a subset of the 3d view */ + if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) { + glGetIntegerv(GL_SCISSOR_BOX, scissor); + glScissor(border_rect->xmin, border_rect->ymin, + BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect)); + } + else { + return false; + } + } -void ED_view3d_backbuf_validate(ViewContext *vc) -{ - if (vc->v3d->flag & V3D_INVALID_BACKBUF) - backdrawview3d(vc->scene, vc->win, vc->ar, vc->v3d); -} + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + /* don't change depth buffer */ + glClear(GL_COLOR_BUFFER_BIT); /* is this necessary? -- merwin */ -/** - * allow for small values [0.5 - 2.5], - * and large values, FLT_MAX by clamping by the area size - */ -int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist) -{ - return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx)); -} + /* render result draw */ + type = rv3d->render_engine->type; + type->view_draw(rv3d->render_engine, C); -/* samples a single pixel (copied from vpaint) */ -unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) -{ - unsigned int col; - - if (x >= vc->ar->winx || y >= vc->ar->winy) { - return 0; + if (clip_border) { + /* restore scissor as it was before */ + glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); } - ED_view3d_backbuf_validate(vc); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); - view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); - glReadBuffer(GL_BACK); - - if (ENDIAN_ORDER == B_ENDIAN) { - BLI_endian_switch_uint32(&col); - } - - return GPU_select_to_index(col); + return true; } -/* reads full rect, converts indices */ -ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax) +/* ******************** background plates ***************** */ + +static void view3d_draw_background_gradient() { - struct ImBuf *ibuf_clip; - /* clip */ - const rcti clip = { - max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1), - max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)}; - const int size_clip[2] = { - BLI_rcti_size_x(&clip) + 1, - BLI_rcti_size_y(&clip) + 1}; + gpuMatrixBegin3D(); /* TODO: finish 2D API */ - if (UNLIKELY((clip.xmin > clip.xmax) || - (clip.ymin > clip.ymax))) - { - return NULL; - } + glClear(GL_DEPTH_BUFFER_BIT); - ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); + unsigned char col_hi[3], col_lo[3]; - ED_view3d_backbuf_validate(vc); + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); - view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect); + UI_GetThemeColor3ubv(TH_LOW_GRAD, col_lo); + UI_GetThemeColor3ubv(TH_HIGH_GRAD, col_hi); - glReadBuffer(GL_BACK); + immBegin(GL_QUADS, 4); + immAttrib3ubv(color, col_lo); + immVertex2f(pos, -1.0f, -1.0f); + immVertex2f(pos, 1.0f, -1.0f); - if (ENDIAN_ORDER == B_ENDIAN) { - IMB_convert_rgba_to_abgr(ibuf_clip); - } + immAttrib3ubv(color, col_hi); + immVertex2f(pos, 1.0f, 1.0f); + immVertex2f(pos, -1.0f, 1.0f); + immEnd(); - GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); - - if ((clip.xmin == xmin) && - (clip.xmax == xmax) && - (clip.ymin == ymin) && - (clip.ymax == ymax)) - { - return ibuf_clip; + immUnbindProgram(); + + gpuMatrixEnd(); +} + +static void view3d_draw_background_none() +{ + if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { + view3d_draw_background_gradient(); } else { - /* put clipped result into a non-clipped buffer */ - struct ImBuf *ibuf_full; - const int size[2] = { - (xmax - xmin + 1), - (ymax - ymin + 1)}; - - ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect); - - IMB_rectcpy( - ibuf_full, ibuf_clip, - clip.xmin - xmin, clip.ymin - ymin, - 0, 0, - size_clip[0], size_clip[1]); - IMB_freeImBuf(ibuf_clip); - return ibuf_full; + UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } } -/* smart function to sample a rect spiralling outside, nice for backbuf selection */ -unsigned int ED_view3d_backbuf_sample_rect( - ViewContext *vc, const int mval[2], int size, - unsigned int min, unsigned int max, float *r_dist) -{ - struct ImBuf *buf; - const unsigned int *bufmin, *bufmax, *tbuf; - int minx, miny; - int a, b, rc, nr, amount, dirvec[4][2]; - unsigned int index = 0; - - amount = (size - 1) / 2; - - minx = mval[0] - (amount + 1); - miny = mval[1] - (amount + 1); - buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1); - if (!buf) return 0; - - rc = 0; - - dirvec[0][0] = 1; dirvec[0][1] = 0; - dirvec[1][0] = 0; dirvec[1][1] = -size; - dirvec[2][0] = -1; dirvec[2][1] = 0; - dirvec[3][0] = 0; dirvec[3][1] = size; - - bufmin = buf->rect; - tbuf = buf->rect; - bufmax = buf->rect + size * size; - tbuf += amount * size + amount; - - for (nr = 1; nr <= size; nr++) { - - for (a = 0; a < 2; a++) { - for (b = 0; b < nr; b++) { - if (*tbuf && *tbuf >= min && *tbuf < max) { - /* we got a hit */ - - /* get x,y pixel coords from the offset - * (manhatten distance in keeping with other screen-based selection) */ - *r_dist = (float)( - abs(((int)(tbuf - buf->rect) % size) - (size / 2)) + - abs(((int)(tbuf - buf->rect) / size) - (size / 2))); - - /* indices start at 1 here */ - index = (*tbuf - min) + 1; - goto exit; - } - - tbuf += (dirvec[rc][0] + dirvec[rc][1]); - - if (tbuf < bufmin || tbuf >= bufmax) { - goto exit; - } - } - rc++; - rc &= 3; - } - } +static void view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d) +{ + if (scene->world) { + GPUMaterial *gpumat = GPU_material_world(scene, scene->world); -exit: - IMB_freeImBuf(buf); - return index; -} + /* calculate full shader for background */ + GPU_material_bind(gpumat, 1, 1, 1.0f, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); + if (GPU_material_bound(gpumat)) { -/* ************************************************************* */ + glClear(GL_DEPTH_BUFFER_BIT); -static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) -{ - if (BKE_image_is_stereo(ima)) { - iuser->flag |= IMA_SHOW_STEREO; + /* TODO viewport (dfelinto): GPU_material_bind relies on immediate mode, + * we can't get rid of the following code without a bigger refactor + * or we dropping this functionality. */ + + glBegin(GL_TRIANGLE_STRIP); + glVertex2f(-1.0f, -1.0f); + glVertex2f(1.0f, -1.0f); + glVertex2f(-1.0f, 1.0f); + glVertex2f(1.0f, 1.0f); + glEnd(); - if ((scene->r.scemode & R_MULTIVIEW) == 0) { - iuser->multiview_eye = STEREO_LEFT_ID; + GPU_material_unbind(gpumat); } - else if (v3d->stereo3d_camera != STEREO_3D_ID) { - /* show only left or right camera */ - iuser->multiview_eye = v3d->stereo3d_camera; + else { + view3d_draw_background_none(); } - - BKE_image_multiview_index(ima, iuser); } else { - iuser->flag &= ~IMA_SHOW_STEREO; + view3d_draw_background_none(); } } -static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame) -{ - RegionView3D *rv3d = ar->regiondata; - BGpic *bgpic; - int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0; - - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - bgpic->iuser.scene = scene; /* Needed for render results. */ +/* ******************** solid plates ***************** */ - if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag) - continue; +/** + * Clear the buffer and draw the proper shader + */ +static void view3d_draw_background(const bContext *C) +{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); - if ((bgpic->view == 0) || /* zero for any */ - (bgpic->view & (1 << rv3d->view)) || /* check agaist flags */ - (rv3d->persp == RV3D_CAMOB && bgpic->view == (1 << RV3D_VIEW_CAMERA))) - { - float image_aspect[2]; - float fac, asp, zoomx, zoomy; - float x1, y1, x2, y2, centx, centy; - - ImBuf *ibuf = NULL, *freeibuf, *releaseibuf; - void *lock; - rctf clip_rect; - - Image *ima = NULL; - MovieClip *clip = NULL; - - /* disable individual images */ - if ((bgpic->flag & V3D_BGPIC_DISABLED)) - continue; - - freeibuf = NULL; - releaseibuf = NULL; - if (bgpic->source == V3D_BGPIC_IMAGE) { - ima = bgpic->ima; - if (ima == NULL) - continue; - BKE_image_user_frame_calc(&bgpic->iuser, CFRA, 0); - if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) { - ibuf = NULL; /* frame is out of range, dont show */ - } - else { - view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser); - ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock); - releaseibuf = ibuf; - } + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + /* Background functions do not read or write depth, but they do clear or completely + * overwrite color buffer. It's more efficient to clear color & depth in once call, so + * background functions do this even though they don't use depth. + */ - image_aspect[0] = ima->aspx; - image_aspect[1] = ima->aspy; - } - else if (bgpic->source == V3D_BGPIC_MOVIE) { - /* TODO: skip drawing when out of frame range (as image sequences do above) */ + switch (v3d->debug.background) { + case V3D_DEBUG_BACKGROUND_WORLD: + view3d_draw_background_world(scene, v3d, rv3d); + break; + case V3D_DEBUG_BACKGROUND_GRADIENT: + view3d_draw_background_gradient(); + break; + case V3D_DEBUG_BACKGROUND_NONE: + default: + view3d_draw_background_none(); + break; + } +} - if (bgpic->flag & V3D_BGPIC_CAMERACLIP) { - if (scene->camera) - clip = BKE_object_movieclip_get(scene, scene->camera, true); - } - else { - clip = bgpic->clip; - } +/** + * + */ +static void view3d_draw_render_solid_surfaces(const bContext *C, ARegion *ar, const bool run_screen_shaders) +{ + /* TODO viewport */ + draw_all_objects(C, ar, false, use_depth(C)); +} - if (clip == NULL) - continue; +/** + * + */ +static void view3d_draw_render_transparent_surfaces(const bContext *C) +{ + /* TODO viewport */ +} - BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA); - ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser); +/** + * + */ +static void view3d_draw_post_draw(const bContext *C) +{ + /* TODO viewport */ +} - image_aspect[0] = clip->aspx; - image_aspect[1] = clip->aspy; +/* ******************** geometry overlay ***************** */ - /* working with ibuf from image and clip has got different workflow now. - * ibuf acquired from clip is referenced by cache system and should - * be dereferenced after usage. */ - freeibuf = ibuf; - } - else { - /* perhaps when loading future files... */ - BLI_assert(0); - copy_v2_fl(image_aspect, 1.0f); - } +/** + * Front/back wire frames + */ +static void view3d_draw_wire_plates(const bContext *C) +{ + /* TODO viewport */ +} - if (ibuf == NULL) - continue; +/** + * Special treatment for selected objects + */ +static void view3d_draw_outline_plates(const bContext *C) +{ + /* TODO viewport */ +} - if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */ - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); +/* ******************** other elements ***************** */ - continue; - } - if (ibuf->rect == NULL) - IMB_rect_from_float(ibuf); +#define DEBUG_GRID 0 - if (rv3d->persp == RV3D_CAMOB) { +static void gridline_range(double x0, double dx, double max, int* first_out, int* count_out) +{ + /* determine range of gridlines that appear in this Area -- similar calc but separate ranges for x & y + * x0 is gridline 0, the axis in screen space + * Area covers [0 .. max) pixels */ - if (do_camera_frame) { - rctf vb; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); - x1 = vb.xmin; - y1 = vb.ymin; - x2 = vb.xmax; - y2 = vb.ymax; - } - else { - x1 = ar->winrct.xmin; - y1 = ar->winrct.ymin; - x2 = ar->winrct.xmax; - y2 = ar->winrct.ymax; - } + int first = (int)ceil(-x0 / dx); + int last = (int)floor((max - x0) / dx); - /* apply offset last - camera offset is different to offset in blender units */ - /* so this has some sane way of working - this matches camera's shift _exactly_ */ - { - const float max_dim = max_ff(x2 - x1, y2 - y1); - const float xof_scale = bgpic->xof * max_dim; - const float yof_scale = bgpic->yof * max_dim; - - x1 += xof_scale; - y1 += yof_scale; - x2 += xof_scale; - y2 += yof_scale; - } + if (first <= last) { + *first_out = first; + *count_out = last - first + 1; + } + else { + *first_out = 0; + *count_out = 0; + } - centx = (x1 + x2) / 2.0f; - centy = (y1 + y2) / 2.0f; - - /* aspect correction */ - if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) { - /* apply aspect from clip */ - const float w_src = ibuf->x * image_aspect[0]; - const float h_src = ibuf->y * image_aspect[1]; - - /* destination aspect is already applied from the camera frame */ - const float w_dst = x1 - x2; - const float h_dst = y1 - y2; - - const float asp_src = w_src / h_src; - const float asp_dst = w_dst / h_dst; - - if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { - if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) { - /* fit X */ - const float div = asp_src / asp_dst; - x1 = ((x1 - centx) * div) + centx; - x2 = ((x2 - centx) * div) + centx; - } - else { - /* fit Y */ - const float div = asp_dst / asp_src; - y1 = ((y1 - centy) * div) + centy; - y2 = ((y2 - centy) * div) + centy; - } - } - } - } - else { - float tvec[3]; - float sco[2]; - const float mval_f[2] = {1.0f, 0.0f}; - const float co_zero[3] = {0}; - float zfac; - - /* calc window coord */ - zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL); - ED_view3d_win_to_delta(ar, mval_f, tvec, zfac); - fac = max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */ - fac = 1.0f / fac; - - asp = (float)ibuf->y / (float)ibuf->x; - - zero_v3(tvec); - ED_view3d_project_float_v2_m4(ar, tvec, sco, rv3d->persmat); - - x1 = sco[0] + fac * (bgpic->xof - bgpic->size); - y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size); - x2 = sco[0] + fac * (bgpic->xof + bgpic->size); - y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size); - - centx = (x1 + x2) / 2.0f; - centy = (y1 + y2) / 2.0f; - } +#if DEBUG_GRID + printf(" first %d * dx = %f\n", first, x0 + first * dx); + printf(" last %d * dx = %f\n", last, x0 + last * dx); + printf(" count = %d\n", *count_out); +#endif +} - /* complete clip? */ - BLI_rctf_init(&clip_rect, x1, x2, y1, y2); - if (bgpic->rotation) { - BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation); - } +static int gridline_count(ARegion *ar, double x0, double y0, double dx) +{ + /* x0 & y0 establish the "phase" of the grid within this 2D region + * dx is the frequency, shared by x & y directions + * pass in dx of smallest (highest precision) grid we want to draw */ - if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) { - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); +#if DEBUG_GRID + printf(" %s(%f, %f, dx:%f)\n", __FUNCTION__, x0, y0, dx); +#endif - continue; - } + int first, x_ct, y_ct; - zoomx = (x2 - x1) / ibuf->x; - zoomy = (y2 - y1) / ibuf->y; + gridline_range(x0, dx, ar->winx, &first, &x_ct); + gridline_range(y0, dx, ar->winy, &first, &y_ct); - /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */ - if (zoomx < 1.0f || zoomy < 1.0f) { - float tzoom = min_ff(zoomx, zoomy); - int mip = 0; + int total_ct = x_ct + y_ct; - if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) { - IMB_remakemipmap(ibuf, 0); - ibuf->userflags &= ~IB_MIPMAP_INVALID; - } - else if (ibuf->mipmap[0] == NULL) - IMB_makemipmap(ibuf, 0); - - while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) { - tzoom *= 2.0f; - zoomx *= 2.0f; - zoomy *= 2.0f; - mip++; - } - if (mip > 0) - ibuf = ibuf->mipmap[mip - 1]; - } +#if DEBUG_GRID + printf(" %d + %d = %d gridlines\n", x_ct, y_ct, total_ct); +#endif - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - glDepthMask(0); + return total_ct; +} - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +static bool drawgrid_draw(ARegion *ar, double x0, double y0, double dx, int skip_mod, unsigned pos, unsigned col, GLubyte col_value[3]) +{ + /* skip every skip_mod lines relative to each axis; they will be overlaid by another drawgrid_draw + * always skip exact x0 & y0 axes; they will be drawn later in color + * + * set grid color once, just before the first line is drawn + * it's harmless to set same color for every line, or every vertex + * but if no lines are drawn, color must not be set! */ - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - ED_region_pixelspace(ar); +#if DEBUG_GRID + printf(" %s(%f, %f, dx:%f, skip_mod:%d)\n", __FUNCTION__, x0, y0, dx, skip_mod); +#endif - glTranslatef(centx, centy, 0.0); - glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f); + const float x_max = (float)ar->winx; + const float y_max = (float)ar->winy; - if (bgpic->flag & V3D_BGPIC_FLIP_X) { - zoomx *= -1.0f; - x1 = x2; - } - if (bgpic->flag & V3D_BGPIC_FLIP_Y) { - zoomy *= -1.0f; - y1 = y2; - } - glPixelZoom(zoomx, zoomy); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend); + int first, ct; + int x_ct = 0, y_ct = 0; /* count of lines actually drawn */ + int lines_skipped_for_next_unit = 0; - /* could not use glaDrawPixelsAuto because it could fallback to - * glaDrawPixelsSafe in some cases, which will end up in missing - * alpha transparency for the background image (sergey) - */ - glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); + /* draw vertical lines */ + gridline_range(x0, dx, x_max, &first, &ct); - glPixelZoom(1.0, 1.0); - glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + for (int i = first; i < first + ct; ++i) { + if (i == 0) + continue; + else if (skip_mod && (i % skip_mod) == 0) { + ++lines_skipped_for_next_unit; + continue; + } - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + if (x_ct == 0) + immAttrib3ub(col, col_value[0], col_value[1], col_value[2]); - glDisable(GL_BLEND); + float x = (float)(x0 + i * dx); + immVertex2f(pos, x, 0.0f); + immVertex2f(pos, x, y_max); + ++x_ct; + } - glDepthMask(1); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + /* draw horizontal lines */ + gridline_range(y0, dx, y_max, &first, &ct); - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); + for (int i = first; i < first + ct; ++i) { + if (i == 0) + continue; + else if (skip_mod && (i % skip_mod) == 0) { + ++lines_skipped_for_next_unit; + continue; } - } -} -static void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame) -{ - RegionView3D *rv3d = ar->regiondata; + if (x_ct + y_ct == 0) + immAttrib3ub(col, col_value[0], col_value[1], col_value[2]); - if ((v3d->flag & V3D_DISPBGPICS) == 0) - return; + float y = (float)(y0 + i * dx); + immVertex2f(pos, 0.0f, y); + immVertex2f(pos, x_max, y); + ++y_ct; + } - /* disabled - mango request, since footage /w only render is quite useful - * and this option is easy to disable all background images at once */ -#if 0 - if (v3d->flag2 & V3D_RENDER_OVERRIDE) - return; +#if DEBUG_GRID + int total_ct = x_ct + y_ct; + printf(" %d + %d = %d gridlines drawn, %d skipped for next unit\n", x_ct, y_ct, total_ct, lines_skipped_for_next_unit); #endif - if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { - if (rv3d->persp == RV3D_CAMOB) { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); - } - } - else { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); - } + return lines_skipped_for_next_unit > 0; } -/* ****************** View3d afterdraw *************** */ - -typedef struct View3DAfter { - struct View3DAfter *next, *prev; - struct Base *base; - short dflag; -} View3DAfter; +#define GRID_MIN_PX_D 6.0 +#define GRID_MIN_PX_F 6.0f -/* temp storage of Objects that need to be drawn as last */ -void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag) +static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit) { - View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after"); - BLI_assert((base->flag & OB_FROMDUPLI) == 0); - BLI_addtail(lb, v3da); - v3da->base = base; - v3da->dflag = dflag; -} + RegionView3D *rv3d = ar->regiondata; -/* disables write in zbuffer and draws it over */ -static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d) -{ - View3DAfter *v3da; - - glDepthMask(GL_FALSE); - v3d->transp = true; - - while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { - draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } - v3d->transp = false; - - glDepthMask(GL_TRUE); - -} +#if DEBUG_GRID + printf("%s width %d, height %d\n", __FUNCTION__, ar->winx, ar->winy); +#endif -/* clears zbuffer and draws it over */ -static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear) -{ - View3DAfter *v3da; + double fx = rv3d->persmat[3][0]; + double fy = rv3d->persmat[3][1]; + double fw = rv3d->persmat[3][3]; - if (*clear && v3d->zbuf) { - glClear(GL_DEPTH_BUFFER_BIT); - *clear = false; - } + const double wx = 0.5 * ar->winx; /* use double precision to avoid rounding errors */ + const double wy = 0.5 * ar->winy; - v3d->xray = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { - draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } - v3d->xray = false; -} + double x = wx * fx / fw; + double y = wy * fy / fw; + double vec4[4] = { v3d->grid, v3d->grid, 0.0, 1.0 }; + mul_m4_v4d(rv3d->persmat, vec4); + fx = vec4[0]; + fy = vec4[1]; + fw = vec4[3]; -/* clears zbuffer and draws it over */ -static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const bool clear) -{ - View3DAfter *v3da; + double dx = fabs(x - wx * fx / fw); + if (dx == 0) dx = fabs(y - wy * fy / fw); - if (clear && v3d->zbuf) - glClear(GL_DEPTH_BUFFER_BIT); + x += wx; + y += wy; - v3d->xray = true; - v3d->transp = true; - - glDepthMask(GL_FALSE); + /* now x, y, and dx have their final values + * (x,y) is the world origin (0,0,0) mapped to Area-relative screen space + * dx is the distance in pixels between grid lines -- same for horiz or vert grid lines */ - while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { - draw_object(scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } + glLineWidth(1.0f); - v3d->transp = false; - v3d->xray = false; +#if 0 /* TODO: write to UI/widget depth buffer, not scene depth */ + glDepthMask(GL_FALSE); /* disable write in zbuffer */ +#endif - glDepthMask(GL_TRUE); -} + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); -/* *********************** */ + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); -/* - * In most cases call draw_dupli_objects, - * draw_dupli_objects_color was added because when drawing set dupli's - * we need to force the color - */ + unsigned char col[3], col2[3]; + UI_GetThemeColor3ubv(TH_GRID, col); -#if 0 -int dupli_ob_sort(void *arg1, void *arg2) -{ - void *p1 = ((DupliObject *)arg1)->ob; - void *p2 = ((DupliObject *)arg2)->ob; - int val = 0; - if (p1 < p2) val = -1; - else if (p1 > p2) val = 1; - return val; -} -#endif + if (unit->system) { + const void *usys; + int len; + bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len); -static DupliObject *dupli_step(DupliObject *dob) -{ - while (dob && dob->no_draw) - dob = dob->next; - return dob; -} + bool first = true; -static void draw_dupli_objects_color( - Scene *scene, ARegion *ar, View3D *v3d, Base *base, - const short dflag, const int color) -{ - RegionView3D *rv3d = ar->regiondata; - ListBase *lb; - LodLevel *savedlod; - DupliObject *dob_prev = NULL, *dob, *dob_next = NULL; - Base tbase = {NULL}; - BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */ - GLuint displist = 0; - unsigned char color_rgb[3]; - const short dflag_dupli = dflag | DRAW_CONSTCOLOR; - short transflag; - bool use_displist = false; /* -1 is initialize */ - char dt; - short dtx; - DupliApplyData *apply_data; - - if (base->object->restrictflag & OB_RESTRICT_VIEW) return; - if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return; - - if (dflag & DRAW_CONSTCOLOR) { - BLI_assert(color == TH_UNDEFINED); - } - else { - UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb); - } + if (usys) { + int i = len; + while (i--) { + double scalar = bUnit_GetScaler(usys, i); + + double dx_scalar = dx * scalar / (double)unit->scale_length; + if (dx_scalar < (GRID_MIN_PX_D * 2.0)) { + /* very very small grid items are less useful when dealing with units */ + continue; + } - tbase.flag = OB_FROMDUPLI | base->flag; - lb = object_duplilist(G.main->eval_ctx, scene, base->object); - // BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */ + if (first) { + first = false; - apply_data = duplilist_apply(base->object, scene, lb); + /* Store the smallest drawn grid size units name so users know how big each grid cell is */ + *grid_unit = bUnit_GetNameDisplay(usys, i); + rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length); - dob = dupli_step(lb->first); - if (dob) dob_next = dupli_step(dob->next); + int gridline_ct = gridline_count(ar, x, y, dx_scalar); + if (gridline_ct == 0) + goto drawgrid_cleanup; /* nothing to draw */ - for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) { - bool testbb = false; + immBegin(GL_LINES, gridline_ct * 2); + } - tbase.object = dob->ob; + float blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar); + /* tweak to have the fade a bit nicer */ + blend_fac = (blend_fac * blend_fac) * 2.0f; + CLAMP(blend_fac, 0.3f, 1.0f); - /* Make sure lod is updated from dupli's position */ - savedlod = dob->ob->currentlod; + UI_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, blend_fac, col2); -#ifdef WITH_GAMEENGINE - if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - BKE_object_lod_update(dob->ob, rv3d->viewinv[3]); - } + const int skip_mod = (i == 0) ? 0 : (int)round(bUnit_GetScaler(usys, i - 1) / scalar); +#if DEBUG_GRID + printf("%s %f, ", bUnit_GetNameDisplay(usys, i), scalar); + if (i > 0) + printf("next unit is %d times larger\n", skip_mod); + else + printf("largest unit\n"); #endif - - /* extra service: draw the duplicator in drawtype of parent, minimum taken - * to allow e.g. boundbox box objects in groups for LOD */ - dt = tbase.object->dt; - tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); - - /* inherit draw extra, but not if a boundbox under the assumption that this - * is intended to speed up drawing, and drawing extra (especially wire) can - * slow it down too much */ - dtx = tbase.object->dtx; - if (tbase.object->dt != OB_BOUNDBOX) - tbase.object->dtx = base->object->dtx; - - /* negative scale flag has to propagate */ - transflag = tbase.object->transflag; - - if (is_negative_m4(dob->mat)) - tbase.object->transflag |= OB_NEG_SCALE; - else - tbase.object->transflag &= ~OB_NEG_SCALE; - - /* should move outside the loop but possible color is set in draw_object still */ - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(color_rgb); - } - - /* generate displist, test for new object */ - if (dob_prev && dob_prev->ob != dob->ob) { - if (use_displist == true) - glDeleteLists(displist, 1); - - use_displist = false; - } - - if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) { - bb = *bb_tmp; /* must make a copy */ - testbb = true; + if (!drawgrid_draw(ar, x, y, dx_scalar, skip_mod, pos, color, col2)) + break; + } } + } + else { + const double sublines = v3d->gridsubdiv; + const float sublines_fl = v3d->gridsubdiv; + + int grids_to_draw = 2; /* first the faint fine grid, then the bold coarse grid */ - if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) { - /* generate displist */ - if (use_displist == false) { - - /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP) - * however this is very slow, it was probably needed for the NLA - * offset feature (used in group-duplicate.blend but no longer works in 2.5) - * so for now it should be ok to - campbell */ - - if ( /* if this is the last no need to make a displist */ - (dob_next == NULL || dob_next->ob != dob->ob) || - /* lamp drawing messes with matrices, could be handled smarter... but this works */ - (dob->ob->type == OB_LAMP) || - (dob->type == OB_DUPLIGROUP && dob->animated) || - !bb_tmp || - draw_glsl_material(scene, dob->ob, v3d, dt) || - check_object_draw_texture(scene, v3d, dt) || - (v3d->flag2 & V3D_SOLID_MATCAP) != 0) - { - // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2); - use_displist = false; + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + if (dx < GRID_MIN_PX_D) { + rv3d->gridview *= sublines_fl; + dx *= sublines; + grids_to_draw = (dx < GRID_MIN_PX_D) ? 0 : 1; } - else { - // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2); - - /* disable boundbox check for list creation */ - BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1); - /* need this for next part of code */ - unit_m4(dob->ob->obmat); /* obmat gets restored */ - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - draw_object(scene, ar, v3d, &tbase, dflag_dupli); - glEndList(); - - use_displist = true; - BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0); - } } - - if (use_displist) { - glPushMatrix(); - glMultMatrixf(dob->mat); - glCallList(displist); - glPopMatrix(); - } - else { - copy_m4_m4(dob->ob->obmat, dob->mat); - GPU_begin_dupli_object(dob); - draw_object(scene, ar, v3d, &tbase, dflag_dupli); - GPU_end_dupli_object(); + } + else { + if (dx >(GRID_MIN_PX_D * 10.0)) { /* start blending in */ + rv3d->gridview /= sublines_fl; + dx /= sublines; + if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ + rv3d->gridview /= sublines_fl; + dx /= sublines; + if (dx > (GRID_MIN_PX_D * 10.0)) { + grids_to_draw = 1; + } + } } } - - tbase.object->dt = dt; - tbase.object->dtx = dtx; - tbase.object->transflag = transflag; - tbase.object->currentlod = savedlod; + + int gridline_ct = gridline_count(ar, x, y, dx); + if (gridline_ct == 0) + goto drawgrid_cleanup; /* nothing to draw */ + + immBegin(GL_LINES, gridline_ct * 2); + + if (grids_to_draw == 2) { + UI_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0), col2); + if (drawgrid_draw(ar, x, y, dx, v3d->gridsubdiv, pos, color, col2)) + drawgrid_draw(ar, x, y, dx * sublines, 0, pos, color, col); + } + else if (grids_to_draw == 1) { + drawgrid_draw(ar, x, y, dx, 0, pos, color, col); + } } - if (apply_data) { - duplilist_restore(lb, apply_data); - duplilist_free_apply_data(apply_data); + /* draw visible axes */ + /* horizontal line */ + if (0 <= y && y < ar->winy) { + UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ? 'Y' : 'X'); + immAttrib3ub(color, col2[0], col2[1], col2[2]); + immVertex2f(pos, 0.0f, y); + immVertex2f(pos, (float)ar->winx, y); } - free_object_duplilist(lb); - - if (use_displist) - glDeleteLists(displist, 1); -} + /* vertical line */ + if (0 <= x && x < ar->winx) { + UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ? 'Y' : 'Z'); + immAttrib3ub(color, col2[0], col2[1], col2[2]); + immVertex2f(pos, x, 0.0f); + immVertex2f(pos, x, (float)ar->winy); + } -static void draw_dupli_objects(Scene *scene, ARegion *ar, View3D *v3d, Base *base) -{ - /* define the color here so draw_dupli_objects_color can be called - * from the set loop */ - - int color = (base->flag & SELECT) ? TH_SELECT : TH_WIRE; - /* debug */ - if (base->object->dup_group && base->object->dup_group->id.us < 1) - color = TH_REDALERT; - - draw_dupli_objects_color(scene, ar, v3d, base, 0, color); -} + immEnd(); -/* XXX warning, not using gpu offscreen here */ -void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect) -{ - int x, y, w, h; - rcti r; - /* clamp rect by region */ +drawgrid_cleanup: + immUnbindProgram(); - r.xmin = 0; - r.xmax = ar->winx - 1; - r.ymin = 0; - r.ymax = ar->winy - 1; +#if 0 /* depth write is left enabled above */ + glDepthMask(GL_TRUE); /* enable write in zbuffer */ +#endif +} - /* Constrain rect to depth bounds */ - BLI_rcti_isect(&r, rect, rect); +#undef DEBUG_GRID +#undef GRID_MIN_PX_D +#undef GRID_MIN_PX_F - /* assign values to compare with the ViewDepths */ - x = rect->xmin; - y = rect->ymin; +static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth) +{ + /* draw only if there is something to draw */ + if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) { + /* draw how many lines? + * trunc(v3d->gridlines / 2) * 4 + * + 2 for xy axes (possibly with special colors) + * + 1 for z axis (the only line not in xy plane) + * even v3d->gridlines are honored, odd rounded down */ + const int gridlines = v3d->gridlines / 2; + const float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit); + const float grid = gridlines * grid_scale; - w = BLI_rcti_size_x(rect); - h = BLI_rcti_size_y(rect); + const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) && gridlines >= 1; - if (w <= 0 || h <= 0) { - if (d->depths) - MEM_freeN(d->depths); - d->depths = NULL; + bool show_axis_x = v3d->gridflag & V3D_SHOW_X; + bool show_axis_y = v3d->gridflag & V3D_SHOW_Y; + bool show_axis_z = v3d->gridflag & V3D_SHOW_Z; - d->damaged = false; - } - else if (d->w != w || - d->h != h || - d->x != x || - d->y != y || - d->depths == NULL - ) - { - d->x = x; - d->y = y; - d->w = w; - d->h = h; + unsigned char col_grid[3], col_axis[3]; - if (d->depths) - MEM_freeN(d->depths); + glLineWidth(1.0f); - d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset"); - - d->damaged = true; - } + UI_GetThemeColor3ubv(TH_GRID, col_grid); - if (d->damaged) { - /* XXX using special function here, it doesn't use the gpu offscreen system */ - view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); - glGetDoublev(GL_DEPTH_RANGE, d->depth_range); - d->damaged = false; - } -} + if (!write_depth) + glDepthMask(GL_FALSE); -/* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */ -void ED_view3d_depth_update(ARegion *ar) -{ - RegionView3D *rv3d = ar->regiondata; - - /* Create storage for, and, if necessary, copy depth buffer */ - if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths"); - if (rv3d->depths) { - ViewDepths *d = rv3d->depths; - if (d->w != ar->winx || - d->h != ar->winy || - !d->depths) - { - d->w = ar->winx; - d->h = ar->winy; - if (d->depths) - MEM_freeN(d->depths); - d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths"); - d->damaged = true; - } - - if (d->damaged) { - view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); - glGetDoublev(GL_DEPTH_RANGE, d->depth_range); - - d->damaged = false; - } - } -} + if (show_floor) { + const unsigned vertex_ct = 2 * (gridlines * 4 + 2); + const int sublines = v3d->gridsubdiv; -/* utility function to find the closest Z value, use for autodepth */ -float view3d_depth_near(ViewDepths *d) -{ - /* convert to float for comparisons */ - const float near = (float)d->depth_range[0]; - const float far_real = (float)d->depth_range[1]; - float far = far_real; + unsigned char col_bg[3], col_grid_emphasise[3], col_grid_light[3]; - const float *depths = d->depths; - float depth = FLT_MAX; - int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */ + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); - /* far is both the starting 'far' value - * and the closest value found. */ - while (i--) { - depth = *depths++; - if ((depth < far) && (depth > near)) { - far = depth; - } - } + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); - return far == far_real ? FLT_MAX : far; -} + immBegin(GL_LINES, vertex_ct); -void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d) -{ - short zbuf = v3d->zbuf; - RegionView3D *rv3d = ar->regiondata; + /* draw normal grid lines */ + UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10); - view3d_winmatrix_set(ar, v3d, NULL); - view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ + for (int a = 1; a <= gridlines; a++) { + /* skip emphasised divider lines */ + if (a % sublines != 0) { + const float line = a * grid_scale; - mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - invert_m4_m4(rv3d->persinv, rv3d->persmat); - invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + immAttrib3ubv(color, col_grid_light); - glClear(GL_DEPTH_BUFFER_BIT); + immVertex2f(pos, -grid, -line); + immVertex2f(pos, +grid, -line); + immVertex2f(pos, -grid, +line); + immVertex2f(pos, +grid, +line); - glLoadMatrixf(rv3d->viewmat); + immVertex2f(pos, -line, -grid); + immVertex2f(pos, -line, +grid); + immVertex2f(pos, +line, -grid); + immVertex2f(pos, +line, +grid); + } + } - v3d->zbuf = true; - glEnable(GL_DEPTH_TEST); + /* draw emphasised grid lines */ + UI_GetThemeColor3ubv(TH_BACK, col_bg); + /* emphasise division lines lighter instead of darker, if background is darker than grid */ + UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise, + (col_grid[0] + col_grid[1] + col_grid[2] + 30 > + col_bg[0] + col_bg[1] + col_bg[2]) ? 20 : -10); - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true); - } - - v3d->zbuf = zbuf; + if (sublines <= gridlines) { + immAttrib3ubv(color, col_grid_emphasise); -} + for (int a = sublines; a <= gridlines; a += sublines) { + const float line = a * grid_scale; -void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride) -{ - RegionView3D *rv3d = ar->regiondata; - Base *base; - short zbuf = v3d->zbuf; - short flag = v3d->flag; - float glalphaclip = U.glalphaclip; - int obcenter_dia = U.obcenter_dia; - /* no need for color when drawing depth buffer */ - const short dflag_depth = DRAW_CONSTCOLOR; - /* temp set drawtype to solid */ - - /* Setting these temporarily is not nice */ - v3d->flag &= ~V3D_SELECT_OUTLINE; - U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */ - U.obcenter_dia = 0; - - view3d_winmatrix_set(ar, v3d, NULL); - view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - - mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - invert_m4_m4(rv3d->persinv, rv3d->persmat); - invert_m4_m4(rv3d->viewinv, rv3d->viewmat); - - glClear(GL_DEPTH_BUFFER_BIT); - - glLoadMatrixf(rv3d->viewmat); - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_set(rv3d); - } - /* get surface depth without bias */ - rv3d->rflag |= RV3D_ZOFFSET_DISABLED; + immVertex2f(pos, -grid, -line); + immVertex2f(pos, +grid, -line); + immVertex2f(pos, -grid, +line); + immVertex2f(pos, +grid, +line); - v3d->zbuf = true; - glEnable(GL_DEPTH_TEST); - - /* draw set first */ - if (scene->set) { - Scene *sce_iter; - for (SETLOOPER(scene->set, sce_iter, base)) { - if (v3d->lay & base->lay) { - draw_object(scene, ar, v3d, base, 0); - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED); + immVertex2f(pos, -line, -grid); + immVertex2f(pos, -line, +grid); + immVertex2f(pos, +line, -grid); + immVertex2f(pos, +line, +grid); } } - } - } - - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED); - } - draw_object(scene, ar, v3d, base, dflag_depth); - } - } - - /* this isn't that nice, draw xray objects as if they are normal */ - if (v3d->afterdraw_transp.first || - v3d->afterdraw_xray.first || - v3d->afterdraw_xraytransp.first) - { - View3DAfter *v3da; - int mask_orig; - v3d->xray = true; - - /* transp materials can change the depth mask, see #21388 */ - glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); + /* draw X axis */ + if (show_axis_x) { + show_axis_x = false; /* drawing now, won't need to draw later */ + UI_make_axis_color(col_grid, col_axis, 'X'); + immAttrib3ubv(color, col_axis); + } + else + immAttrib3ubv(color, col_grid_emphasise); + immVertex2f(pos, -grid, 0.0f); + immVertex2f(pos, +grid, 0.0f); - if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) { - glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */ - for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) { - draw_object(scene, ar, v3d, v3da->base, dflag_depth); + /* draw Y axis */ + if (show_axis_y) { + show_axis_y = false; /* drawing now, won't need to draw later */ + UI_make_axis_color(col_grid, col_axis, 'Y'); + immAttrib3ubv(color, col_axis); } - glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */ - } + else + immAttrib3ubv(color, col_grid_emphasise); - /* draw 3 passes, transp/xray/xraytransp */ - v3d->xray = false; - v3d->transp = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { - draw_object(scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); - } + immVertex2f(pos, 0.0f, -grid); + immVertex2f(pos, 0.0f, +grid); - v3d->xray = true; - v3d->transp = false; - while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { - draw_object(scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); - } + immEnd(); + immUnbindProgram(); - v3d->xray = true; - v3d->transp = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { - draw_object(scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); + /* done with XY plane */ } - - v3d->xray = false; - v3d->transp = false; + if (show_axis_x || show_axis_y || show_axis_z) { + /* draw axis lines -- sometimes grid floor is off, other times we still need to draw the Z axis */ - glDepthMask(mask_orig); - } - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_disable(); - } - rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; - - v3d->zbuf = zbuf; - if (!v3d->zbuf) glDisable(GL_DEPTH_TEST); - - U.glalphaclip = glalphaclip; - v3d->flag = flag; - U.obcenter_dia = obcenter_dia; -} - -typedef struct View3DShadow { - struct View3DShadow *next, *prev; - GPULamp *lamp; -} View3DShadow; - -static void gpu_render_lamp_update(Scene *scene, View3D *v3d, - Object *ob, Object *par, - float obmat[4][4], unsigned int lay, - ListBase *shadows, SceneRenderLayer *srl) -{ - GPULamp *lamp; - Lamp *la = (Lamp *)ob->data; - View3DShadow *shadow; - unsigned int layers; - - lamp = GPU_lamp_from_blender(scene, ob, par); - - if (lamp) { - GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat); - GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy); - - layers = lay & v3d->lay; - if (srl) - layers &= srl->lay; - - if (layers && - GPU_lamp_has_shadow_buffer(lamp) && - /* keep last, may do string lookup */ - GPU_lamp_override_visible(lamp, srl, NULL)) - { - shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow"); - shadow->lamp = lamp; - BLI_addtail(shadows, shadow); - } - } -} + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); -static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d) -{ - ListBase shadows; - View3DShadow *shadow; - Scene *sce_iter; - Base *base; - Object *ob; - World *world = scene->world; - SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL; - - BLI_listbase_clear(&shadows); - - /* update lamp transform and gather shadow lamps */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - - if (ob->type == OB_LAMP) - gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, ob->lay, &shadows, srl); - - if (ob->transflag & OB_DUPLI) { - DupliObject *dob; - ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); - - for (dob = lb->first; dob; dob = dob->next) - if (dob->ob->type == OB_LAMP) - gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, ob->lay, &shadows, srl); - - free_object_duplilist(lb); - } - } - - /* render shadows after updating all lamps, nested object_duplilist - * don't work correct since it's replacing object matrices */ - for (shadow = shadows.first; shadow; shadow = shadow->next) { - /* this needs to be done better .. */ - float viewmat[4][4], winmat[4][4]; - int drawtype, lay, winsize, flag2 = v3d->flag2; - ARegion ar = {NULL}; - RegionView3D rv3d = {{{0}}}; - - drawtype = v3d->drawtype; - lay = v3d->lay; - - v3d->drawtype = OB_SOLID; - v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp); - v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP); - v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW; - - GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat); - - ar.regiondata = &rv3d; - ar.regiontype = RGN_TYPE_WINDOW; - rv3d.persp = RV3D_CAMOB; - copy_m4_m4(rv3d.winmat, winmat); - copy_m4_m4(rv3d.viewmat, viewmat); - invert_m4_m4(rv3d.viewinv, rv3d.viewmat); - mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); - invert_m4_m4(rv3d.persinv, rv3d.viewinv); - - /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */ - ED_view3d_draw_offscreen( - scene, v3d, &ar, winsize, winsize, viewmat, winmat, - false, false, true, - NULL, NULL, NULL, NULL); - GPU_lamp_shadow_buffer_unbind(shadow->lamp); - - v3d->drawtype = drawtype; - v3d->lay = lay; - v3d->flag2 = flag2; - } - - BLI_freelistN(&shadows); - - /* update world values */ - if (world) { - GPU_mist_update_enable(world->mode & WO_MIST); - GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr); - GPU_horizon_update_color(&world->horr); - GPU_ambient_update_color(&world->ambr); - GPU_zenith_update_color(&world->zenr); - } -} - -/* *********************** customdata **************** */ + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + immBegin(GL_LINES, (show_axis_x + show_axis_y + show_axis_z) * 2); -CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d) -{ - CustomDataMask mask = 0; - const int drawtype = view3d_effective_drawtype(v3d); + if (show_axis_x) { + UI_make_axis_color(col_grid, col_axis, 'X'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, -grid, 0.0f, 0.0f); + immVertex3f(pos, +grid, 0.0f, 0.0f); + } - if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) || - ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) - { - mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; + if (show_axis_y) { + UI_make_axis_color(col_grid, col_axis, 'Y'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, 0.0f, -grid, 0.0f); + immVertex3f(pos, 0.0f, +grid, 0.0f); + } - if (BKE_scene_use_new_shading_nodes(scene)) { - if (drawtype == OB_MATERIAL) - mask |= CD_MASK_ORCO; - } - else { - if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) || - (drawtype == OB_MATERIAL)) - { - mask |= CD_MASK_ORCO; + if (show_axis_z) { + UI_make_axis_color(col_grid, col_axis, 'Z'); + immAttrib3ubv(color, col_axis); + immVertex3f(pos, 0.0f, 0.0f, -grid); + immVertex3f(pos, 0.0f, 0.0f, +grid); } + + immEnd(); + immUnbindProgram(); } - } - return mask; + if (!write_depth) + glDepthMask(GL_TRUE); + } } -/* goes over all modes and view3d settings */ -CustomDataMask ED_view3d_screen_datamask(const bScreen *screen) +/** could move this elsewhere, but tied into #ED_view3d_grid_scale */ +float ED_scene_grid_scale(Scene *scene, const char **grid_unit) { - const Scene *scene = screen->scene; - CustomDataMask mask = CD_MASK_BAREMESH; - const ScrArea *sa; - - /* check if we need tfaces & mcols due to view mode */ - for (sa = screen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_VIEW3D) { - mask |= ED_view3d_datamask(scene, sa->spacedata.first); + /* apply units */ + if (scene->unit.system) { + const void *usys; + int len; + + bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len); + + if (usys) { + int i = bUnit_GetBaseUnit(usys); + if (grid_unit) + *grid_unit = bUnit_GetNameDisplay(usys, i); + return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length; } } - return mask; + return 1.0f; } -/** - * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore - */ -void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) +float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) { - RegionView3D *rv3d = ar->regiondata; - - /* setup window matrices */ - if (winmat) - copy_m4_m4(rv3d->winmat, winmat); - else - view3d_winmatrix_set(ar, v3d, NULL); - - /* setup view matrix */ - if (viewmat) - copy_m4_m4(rv3d->viewmat, viewmat); - else - view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - - /* update utility matrices */ - mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - invert_m4_m4(rv3d->persinv, rv3d->persmat); - invert_m4_m4(rv3d->viewinv, rv3d->viewmat); - - /* calculate GLSL view dependent values */ + return v3d->grid * ED_scene_grid_scale(scene, grid_unit); +} - /* store window coordinates scaling/offset */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { - rctf cameraborder; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); - rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); - rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); - - rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx; - rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy; - } - else { - rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; - rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f; - } +static void view3d_draw_grid(const bContext *C, ARegion *ar) +{ + /* TODO viewport + * Missing is the flags to check whether to draw it + * for now now we are using the flags in v3d itself. + * + * Also for now always assume depth is there, so we + * draw on top of it. + */ /** * Calculate pixel-size factor once, is used for lamps and object centers. * Used by #ED_view3d_pixel_size and typically not accessed directly. @@ -2703,1109 +1460,550 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view * * 'RegionView3D.pixsize' is used for viewport drawing, not rendering. */ - { - /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])' - * because of float point precision problems at large values [#23908] */ - float v1[3], v2[3]; - float len_px, len_sc; - - v1[0] = rv3d->persmat[0][0]; - v1[1] = rv3d->persmat[1][0]; - v1[2] = rv3d->persmat[2][0]; - - v2[0] = rv3d->persmat[0][1]; - v2[1] = rv3d->persmat[1][1]; - v2[2] = rv3d->persmat[2][1]; - - len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); - len_sc = (float)MAX2(ar->winx, ar->winy); - - rv3d->pixsize = len_px / len_sc; - } -} - -/** - * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects - * - * \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set. - * \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here. - */ -static void view3d_draw_objects( - const bContext *C, - Scene *scene, View3D *v3d, ARegion *ar, - const char **grid_unit, - const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) -{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; - Base *base; - const bool do_camera_frame = !draw_offscreen; - const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; - const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); - /* only draw grids after in solid modes, else it hovers over mesh wires */ - const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx; - bool do_composite_xray = false; - bool xrayclear = true; - if (!draw_offscreen) { - ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); - } - - if (rv3d->rflag & RV3D_CLIPPING) - view3d_draw_clipping(rv3d); - - /* set zbuffer after we draw clipping region */ - if (v3d->drawtype > OB_WIRE) { - v3d->zbuf = true; - } - else { - v3d->zbuf = false; - } - - /* special case (depth for wire color) */ - if (v3d->drawtype <= OB_WIRE) { - if (scene->obedit && scene->obedit->type == OB_MESH) { - Mesh *me = scene->obedit->data; - if (me->drawflag & ME_DRAWEIGHT) { - v3d->zbuf = true; - } - } - } - - if (v3d->zbuf) { - glEnable(GL_DEPTH_TEST); - } + const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); + const char *grid_unit = NULL; /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override - * objects if done last */ - if (draw_grids) { - /* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */ - rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit); - - if (!draw_floor) { - ED_region_pixelspace(ar); - *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ - drawgrid(&scene->unit, ar, v3d, grid_unit); - /* XXX make function? replaces persp(1) */ - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(rv3d->winmat); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(rv3d->viewmat); - } - else if (!draw_grids_after) { - drawfloor(scene, v3d, grid_unit, true); - } - } - - /* important to do before clipping */ - if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame); - } + * objects if done last + * needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. + */ + rv3d->gridview = ED_view3d_grid_scale(scene, v3d, &grid_unit); - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_set(rv3d); - } + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); /* read & test depth, but don't alter it. TODO: separate UI depth buffer */ - /* draw set first */ - if (scene->set) { - const short dflag = DRAW_CONSTCOLOR | DRAW_SCENESET; - Scene *sce_iter; - for (SETLOOPER(scene->set, sce_iter, base)) { - if (v3d->lay & base->lay) { - UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f); - draw_object(scene, ar, v3d, base, dflag); - - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(scene, ar, v3d, base, dflag, TH_UNDEFINED); - } - } - } + if (!draw_floor) { + ED_region_pixelspace(ar); + *(&grid_unit) = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ + drawgrid(&scene->unit, ar, v3d, &grid_unit); - /* Transp and X-ray afterdraw stuff for sets is done later */ - } - - - if (draw_offscreen) { - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) - draw_dupli_objects(scene, ar, v3d, base); - - draw_object(scene, ar, v3d, base, 0); - } - } + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(rv3d->winmat); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(rv3d->viewmat); } else { - unsigned int lay_used = 0; + drawfloor(scene, v3d, &grid_unit, false); + } - /* then draw not selected and the duplis, but skip editmode object */ - for (base = scene->base.first; base; base = base->next) { - lay_used |= base->lay; + glDisable(GL_DEPTH_TEST); +} - if (v3d->lay & base->lay) { +static bool is_cursor_visible(Scene *scene) +{ + Object *ob = OBACT; - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects(scene, ar, v3d, base); - } - if ((base->flag & SELECT) == 0) { - if (base->object != scene->obedit) - draw_object(scene, ar, v3d, base, 0); - } + /* don't draw cursor in paint modes, but with a few exceptions */ + if (ob && ob->mode & OB_MODE_ALL_PAINT) { + /* exception: object is in weight paint and has deforming armature in pose mode */ + if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (BKE_object_pose_armature_get(ob) != NULL) { + return true; } } + /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */ + else if (ob->mode & OB_MODE_TEXTURE_PAINT) { + const Paint *p = BKE_paint_get_active(scene); - /* mask out localview */ - v3d->lay_used = lay_used & ((1 << 20) - 1); - - /* draw selected and editmode */ - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - if (base->object == scene->obedit || (base->flag & SELECT)) { - draw_object(scene, ar, v3d, base, 0); + if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) { + if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) { + return true; } } } - } - - /* perspective floor goes last to use scene depth and avoid writing to depth buffer */ - if (draw_grids_after) { - drawfloor(scene, v3d, grid_unit, false); - } - - /* must be before xray draw which clears the depth buffer */ - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - wmWindowManager *wm = (C != NULL) ? CTX_wm_manager(C) : NULL; - - /* must be before xray draw which clears the depth buffer */ - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - ED_gpencil_draw_view3d(wm, scene, v3d, ar, true); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } - - /* transp and X-ray afterdraw stuff */ - if (v3d->afterdraw_transp.first) view3d_draw_transp(scene, ar, v3d); - - /* always do that here to cleanup depth buffers if none needed */ - if (fx) { - do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first); - GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray); - } - - if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, &xrayclear); - if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, xrayclear); - - if (fx && do_composite_xray) { - GPU_fx_compositor_XRay_resolve(fx); - } - - if (!draw_offscreen) { - ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); - } - if (rv3d->rflag & RV3D_CLIPPING) - ED_view3d_clipping_disable(); - - /* important to do after clipping */ - if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame); - } - - if (!draw_offscreen) { - BIF_draw_manipulator(C); - } - - /* cleanup */ - if (v3d->zbuf) { - v3d->zbuf = false; - glDisable(GL_DEPTH_TEST); + /* no exception met? then don't draw cursor! */ + return false; } - if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - GPU_free_images_old(); - } + return true; } -static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) +static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d) { - RegionView3D *rv3d = ar->regiondata; + int co[2]; - ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat); + /* we don't want the clipping for cursor */ + if (ED_view3d_project_int_global(ar, ED_view3d_cursor3d_get(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + const float f5 = 0.25f * U.widget_unit; + const float f10 = 0.5f * U.widget_unit; + const float f20 = U.widget_unit; + + glLineWidth(1.0f); - /* set for opengl */ - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(rv3d->winmat); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(rv3d->viewmat); -} + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned color = add_attrib(format, "color", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT); -/** - * Store values from #RegionView3D, set when drawing. - * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example). - * - * Values set by #ED_view3d_update_viewmat should be handled here. - */ -struct RV3DMatrixStore { - float winmat[4][4]; - float viewmat[4][4]; - float viewinv[4][4]; - float persmat[4][4]; - float persinv[4][4]; - float viewcamtexcofac[4]; - float pixsize; -}; + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); -void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d) -{ - struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__); - copy_m4_m4(rv3dmat->winmat, rv3d->winmat); - copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat); - copy_m4_m4(rv3dmat->persmat, rv3d->persmat); - copy_m4_m4(rv3dmat->persinv, rv3d->persinv); - copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv); - copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac); - rv3dmat->pixsize = rv3d->pixsize; - return (void *)rv3dmat; -} + const int segments = 16; -void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt) -{ - struct RV3DMatrixStore *rv3dmat = rv3dmat_pt; - copy_m4_m4(rv3d->winmat, rv3dmat->winmat); - copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat); - copy_m4_m4(rv3d->persmat, rv3dmat->persmat); - copy_m4_m4(rv3d->persinv, rv3dmat->persinv); - copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv); - copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac); - rv3d->pixsize = rv3dmat->pixsize; -} + immBegin(GL_LINE_LOOP, segments); -void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d) -{ - /* shadow buffers, before we setup matrices */ - if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) - gpu_update_lamps_shadows_world(scene, v3d); -} + for (int i = 0; i < segments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)segments); + float x = co[0] + f10 * cosf(angle); + float y = co[1] + f10 * sinf(angle); -/* - * Function to clear the view - */ -static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) -{ - if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) { - RegionView3D *rv3d = ar->regiondata; - GPUMaterial *gpumat = GPU_material_world(scene, scene->world); + if (i % 2 == 0) + immAttrib3ub(color, 255, 0, 0); + else + immAttrib3ub(color, 255, 255, 255); - /* calculate full shader for background */ - GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); - - bool material_not_bound = !GPU_material_bound(gpumat); - - if (material_not_bound) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + immVertex2f(pos, x, y); } + immEnd(); - /* Draw world */ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glBegin(GL_TRIANGLE_STRIP); - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glEnd(); - - if (material_not_bound) { - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } + immUnbindProgram(); - GPU_material_unbind(gpumat); - - glDepthFunc(GL_LEQUAL); - glDisable(GL_DEPTH_TEST); - } - else { - if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glBegin(GL_QUADS); - UI_ThemeColor(TH_LOW_GRAD); - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - UI_ThemeColor(TH_HIGH_GRAD); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(-1.0, 1.0, 1.0); - glEnd(); - glDepthFunc(GL_LEQUAL); - glDisable(GL_DEPTH_TEST); + VertexFormat_clear(format); + pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - else { - UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + unsigned char crosshair_color[3]; + UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color); + immUniformColor3ubv(crosshair_color); + + immBegin(GL_LINES, 8); + immVertex2f(pos, co[0] - f20, co[1]); + immVertex2f(pos, co[0] - f5, co[1]); + immVertex2f(pos, co[0] + f5, co[1]); + immVertex2f(pos, co[0] + f20, co[1]); + immVertex2f(pos, co[0], co[1] - f20); + immVertex2f(pos, co[0], co[1] - f5); + immVertex2f(pos, co[0], co[1] + f5); + immVertex2f(pos, co[0], co[1] + f20); + immEnd(); + + immUnbindProgram(); } } -/* ED_view3d_draw_offscreen_init should be called before this to initialize - * stuff like shadow buffers - */ -void ED_view3d_draw_offscreen( - Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy, - float viewmat[4][4], float winmat[4][4], - bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, - GPUFX *fx, GPUFXSettings *fx_settings, - GPUOffScreen *ofs) -{ - struct bThemeState theme_state; - int bwinx, bwiny; - rcti brect; - bool do_compositing = false; - RegionView3D *rv3d = ar->regiondata; +static void draw_view_axis(RegionView3D *rv3d, rcti *rect) +{ + const float k = U.rvisize * U.pixelsize; /* axis size */ + const int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */ - glPushMatrix(); + const float startx = rect->xmin + k + 1.0f; /* axis center in screen coordinates, x=y */ + const float starty = rect->ymin + k + 1.0f; - /* set temporary new size */ - bwinx = ar->winx; - bwiny = ar->winy; - brect = ar->winrct; + float axis_pos[3][2]; + unsigned char axis_col[3][4]; - ar->winx = winx; - ar->winy = winy; - ar->winrct.xmin = 0; - ar->winrct.ymin = 0; - ar->winrct.xmax = winx; - ar->winrct.ymax = winy; + int axis_order[3] = {0, 1, 2}; + axis_sort_v3(rv3d->viewinv[2], axis_order); - UI_Theme_Store(&theme_state); - UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; - /* set flags */ - G.f |= G_RENDER_OGL; + /* get position of each axis tip on screen */ + float vec[3] = { 0.0f }; + vec[i] = 1.0f; + mul_qt_v3(rv3d->viewquat, vec); + axis_pos[i][0] = startx + vec[0] * k; + axis_pos[i][1] = starty + vec[1] * k; - if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - /* free images which can have changed on frame-change - * warning! can be slow so only free animated images - campbell */ - GPU_free_images_anim(); + /* get color of each axis */ + UI_GetThemeColorShade3ubv(TH_AXIS_X + i, bright, axis_col[i]); /* rgb */ + axis_col[i][3] = 255 * hypotf(vec[0], vec[1]); /* alpha */ } - /* setup view matrices before fx or unbinding the offscreen buffers will cause issues */ - if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera) - view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname); - else - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); - - /* framebuffer fx needed, we need to draw offscreen first */ - if (v3d->fx_settings.fx_flag && fx) { - GPUSSAOSettings *ssao = NULL; - - if (v3d->drawtype < OB_SOLID) { - ssao = v3d->fx_settings.ssao; - v3d->fx_settings.ssao = NULL; - } + /* draw axis lines */ + glLineWidth(2.0f); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned col = add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); - if (ssao) - v3d->fx_settings.ssao = ssao; - } + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GL_LINES, 6); - /* clear opengl buffers */ - if (do_sky) { - view3d_main_region_clear(scene, v3d, ar); - } - else { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - /* main drawing call */ - view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL); + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; - /* post process */ - if (do_compositing) { - if (!winmat) - is_persp = rv3d->is_persp; - GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs); + immAttrib4ubv(col, axis_col[i]); + immVertex2f(pos, startx, starty); + immVertex2fv(pos, axis_pos[i]); } - if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - /* draw grease-pencil stuff */ - ED_region_pixelspace(ar); - + immEnd(); + immUnbindProgram(); + glDisable(GL_LINE_SMOOTH); - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false); - } + /* draw axis names */ + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; - /* freeing the images again here could be done after the operator runs, leaving for now */ - GPU_free_images_anim(); + const char axis_text[2] = {'x' + i, '\0'}; + glColor4ubv(axis_col[i]); /* text shader still uses gl_Color */ + BLF_draw_default_ascii(axis_pos[i][0] + 2, axis_pos[i][1] + 2, 0.0f, axis_text, 1); } - /* restore size */ - ar->winx = bwinx; - ar->winy = bwiny; - ar->winrct = brect; - - glPopMatrix(); - - UI_Theme_Restore(&theme_state); - - G.f &= ~G_RENDER_OGL; + /* BLF_draw_default disabled blending for us */ } -/** - * Utility func for ED_view3d_draw_offscreen - * - * \param ofs: Optional off-screen buffer, can be NULL. - * (avoids re-creating when doing multiple GL renders). - */ -ImBuf *ED_view3d_draw_offscreen_imbuf( - Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, - unsigned int flag, bool draw_background, - int alpha_mode, int samples, bool full_samples, const char *viewname, - /* output vars */ - GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) +#ifdef WITH_INPUT_NDOF +/* draw center and axis of rotation for ongoing 3D mouse navigation */ +static void draw_rotation_guide(RegionView3D *rv3d) { - RegionView3D *rv3d = ar->regiondata; - ImBuf *ibuf; - const bool draw_sky = (alpha_mode == R_ADDSKY); - - /* view state */ - GPUFXSettings fx_settings = v3d->fx_settings; - bool is_ortho = false; - float winmat[4][4]; + float o[3]; /* center of rotation */ + float end[3]; /* endpoints for drawing */ - if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) { - /* sizes differ, can't reuse */ - ofs = NULL; - } + GLubyte color[4] = {0, 108, 255, 255}; /* bright blue so it matches device LEDs */ - const bool own_ofs = (ofs == NULL); + negate_v3_v3(o, rv3d->ofs); - if (own_ofs) { - /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); - if (ofs == NULL) { - return NULL; - } - } + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPointSize(5.0f); + glEnable(GL_POINT_SMOOTH); + glDepthMask(GL_FALSE); /* don't overwrite zbuf */ - ED_view3d_draw_offscreen_init(scene, v3d); + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT); + unsigned col = add_attrib(format, "color", COMP_U8, 4, NORMALIZE_INT_TO_FLOAT); - GPU_offscreen_bind(ofs, true); + immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); - /* read in pixels & stamp */ - ibuf = IMB_allocImBuf(sizex, sizey, 32, flag); + if (rv3d->rot_angle != 0.0f) { + /* -- draw rotation axis -- */ + float scaled_axis[3]; + const float scale = rv3d->dist; + mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale); - /* render 3d view */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { - CameraParams params; - Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - BKE_camera_params_init(¶ms); - /* fallback for non camera objects */ - params.clipsta = v3d->near; - params.clipend = v3d->far; - BKE_camera_params_from_object(¶ms, camera); - BKE_camera_multiview_params(&scene->r, ¶ms, camera, viewname); - BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp); - BKE_camera_params_compute_matrix(¶ms); + immBegin(GL_LINE_STRIP, 3); + color[3] = 0; /* more transparent toward the ends */ + immAttrib4ubv(col, color); + add_v3_v3v3(end, o, scaled_axis); + immVertex3fv(pos, end); - BKE_camera_to_gpu_dof(camera, &fx_settings); +#if 0 + color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */ + /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */ +#endif - is_ortho = params.is_ortho; - copy_m4_m4(winmat, params.winmat); - } - else { - rctf viewplane; - float clipsta, clipend; + color[3] = 127; /* more opaque toward the center */ + immAttrib4ubv(col, color); + immVertex3fv(pos, o); - is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); - if (is_ortho) { - orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); - } - else { - perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); - } - } + color[3] = 0; + immAttrib4ubv(col, color); + sub_v3_v3v3(end, o, scaled_axis); + immVertex3fv(pos, end); + immEnd(); + + /* -- draw ring around rotation center -- */ + { +#define ROT_AXIS_DETAIL 13 - if ((samples && full_samples) == 0) { - /* Single-pass render, common case */ - ED_view3d_draw_offscreen( - scene, v3d, ar, sizex, sizey, NULL, winmat, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); + const float s = 0.05f * scale; + const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL); - if (ibuf->rect_float) { - GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); - } - else if (ibuf->rect) { - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect); - } - } - else { - /* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling. - * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ - static float jit_ofs[32][2]; - float winmat_jitter[4][4]; - /* use imbuf as temp storage, before writing into it from accumulation buffer */ - unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float; - unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1"); - unsigned int i; - int j; - - BLI_jitter_init(jit_ofs, samples); - - /* first sample buffer, also initializes 'rv3d->persmat' */ - ED_view3d_draw_offscreen( - scene, v3d, ar, sizex, sizey, NULL, winmat, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); - - i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] = rect_temp[i]; - } + float q[4]; /* rotate ring so it's perpendicular to axis */ + const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f; + if (!upright) { + const float up[3] = {0.0f, 0.0f, 1.0f}; + float vis_angle, vis_axis[3]; - /* skip the first sample */ - for (j = 1; j < samples; j++) { - copy_m4_m4(winmat_jitter, winmat); - window_translate_m4( - winmat_jitter, rv3d->persmat, - (jit_ofs[j][0] * 2.0f) / sizex, - (jit_ofs[j][1] * 2.0f) / sizey); - - ED_view3d_draw_offscreen( - scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); - - i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] += rect_temp[i]; + cross_v3_v3v3(vis_axis, up, rv3d->rot_axis); + vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis)); + axis_angle_to_quat(q, vis_axis, vis_angle); } - } - if (ibuf->rect_float) { - float *rect_float = ibuf->rect_float; - i = sizex * sizey * 4; - while (i--) { - rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f); - } - } - else { - unsigned char *rect_ub = (unsigned char *)ibuf->rect; - i = sizex * sizey * 4; - while (i--) { - rect_ub[i] = accum_buffer[i] / samples; + immBegin(GL_LINE_LOOP, ROT_AXIS_DETAIL); + color[3] = 63; /* somewhat faint */ + immAttrib4ubv(col, color); + float angle = 0.0f; + for (int i = 0; i < ROT_AXIS_DETAIL; ++i, angle += step) { + float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f}; + + if (!upright) { + mul_qt_v3(q, p); + } + + add_v3_v3(p, o); + immVertex3fv(pos, p); } + immEnd(); + +#undef ROT_AXIS_DETAIL } - MEM_freeN(accum_buffer); + color[3] = 255; /* solid dot */ } + else + color[3] = 127; /* see-through dot */ - /* unbind */ - GPU_offscreen_unbind(ofs, true); - - if (own_ofs) { - GPU_offscreen_free(ofs); - } + /* -- draw rotation center -- */ + immBegin(GL_POINTS, 1); + immAttrib4ubv(col, color); + immVertex3fv(pos, o); + immEnd(); + immUnbindProgram(); - if (ibuf->rect_float && ibuf->rect) - IMB_rect_from_float(ibuf); +#if 0 + /* find screen coordinates for rotation center, then draw pretty icon */ + mul_m4_v3(rv3d->persinv, rot_center); + UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN); + /* ^^ just playing around, does not work */ +#endif - return ibuf; + glDisable(GL_BLEND); + glDisable(GL_POINT_SMOOTH); + glDepthMask(GL_TRUE); } +#endif /* WITH_INPUT_NDOF */ -/** - * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf) - * - * \param ofs: Optional off-screen buffer can be NULL. - * (avoids re-creating when doing multiple GL renders). - * - * \note used by the sequencer - */ -ImBuf *ED_view3d_draw_offscreen_imbuf_simple( - Scene *scene, Object *camera, int width, int height, - unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background, - int alpha_mode, int samples, bool full_samples, const char *viewname, - GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) -{ - View3D v3d = {NULL}; - ARegion ar = {NULL}; - RegionView3D rv3d = {{{0}}}; - - /* connect data */ - v3d.regionbase.first = v3d.regionbase.last = &ar; - ar.regiondata = &rv3d; - ar.regiontype = RGN_TYPE_WINDOW; - - v3d.camera = camera; - v3d.lay = scene->lay; - v3d.drawtype = drawtype; - v3d.flag2 = V3D_RENDER_OVERRIDE; - - if (use_gpencil) - v3d.flag2 |= V3D_SHOW_GPENCIL; - - if (use_solid_tex) - v3d.flag2 |= V3D_SOLID_TEX; - - if (draw_background) - v3d.flag3 |= V3D_SHOW_WORLD; +/* ******************** non-meshes ***************** */ - rv3d.persp = RV3D_CAMOB; +static void view3d_draw_non_mesh( +Scene *scene, Object *ob, Base *base, View3D *v3d, +RegionView3D *rv3d, const bool is_boundingbox, const unsigned char color[4]) +{ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); - copy_m4_m4(rv3d.viewinv, v3d.camera->obmat); - normalize_m4(rv3d.viewinv); - invert_m4_m4(rv3d.viewmat, rv3d.viewinv); + /* multiply view with object matrix. + * local viewmat and persmat, to calculate projections */ + ED_view3d_init_mats_rv3d_gl(ob, rv3d); + + switch (ob->type) { + case OB_MESH: + case OB_FONT: + case OB_CURVE: + case OB_SURF: + case OB_MBALL: + if (is_boundingbox) { + draw_bounding_volume(ob, ob->boundtype); + } + break; + case OB_EMPTY: + drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, color); + break; + case OB_LAMP: + drawlamp(v3d, rv3d, base, OB_SOLID, DRAW_CONSTCOLOR, color, ob == OBACT); + break; + case OB_CAMERA: + drawcamera(scene, v3d, rv3d, base, DRAW_CONSTCOLOR, color); + break; + case OB_SPEAKER: + drawspeaker(color); + break; + case OB_LATTICE: + /* TODO */ + break; + case OB_ARMATURE: + /* TODO */ + break; + default: + /* TODO Viewport: handle the other cases*/ + break; + } - { - CameraParams params; - Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname); - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, view_camera); - BKE_camera_multiview_params(&scene->r, ¶ms, view_camera, viewname); - BKE_camera_params_compute_viewplane(¶ms, width, height, scene->r.xasp, scene->r.yasp); - BKE_camera_params_compute_matrix(¶ms); - - copy_m4_m4(rv3d.winmat, params.winmat); - v3d.near = params.clipsta; - v3d.far = params.clipend; - v3d.lens = params.lens; + if (ob->rigidbody_object) { + draw_rigidbody_shape(ob); } - mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); - invert_m4_m4(rv3d.persinv, rv3d.viewinv); + ED_view3d_clear_mats_rv3d(rv3d); - return ED_view3d_draw_offscreen_imbuf( - scene, &v3d, &ar, width, height, flag, - draw_background, alpha_mode, samples, full_samples, viewname, - fx, ofs, err_out); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); } +/* ******************** info ***************** */ /** - * \note The info that this uses is updated in #ED_refresh_viewport_fps, - * which currently gets called during #SCREEN_OT_animation_step. - */ -void ED_scene_draw_fps(Scene *scene, const rcti *rect) -{ - ScreenFrameRateInfo *fpsi = scene->fps_info; - float fps; - char printable[16]; - int i, tot; - - if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) - return; - - printable[0] = '\0'; - -#if 0 - /* this is too simple, better do an average */ - fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)) -#else - fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)); - - for (i = 0, tot = 0, fps = 0.0f; i < REDRAW_FRAME_AVERAGE; i++) { - if (fpsi->redrawtimes_fps[i]) { - fps += fpsi->redrawtimes_fps[i]; - tot++; - } - } - if (tot) { - fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE; - - //fpsi->redrawtime_index++; - //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE) - // fpsi->redrawtime = 0; - - fps = fps / tot; - } -#endif +* Render and camera border +*/ +static void view3d_draw_border(const bContext *C, ARegion *ar) +{ + Scene *scene = CTX_data_scene(C); + RegionView3D *rv3d = ar->regiondata; + View3D *v3d = CTX_wm_view3d(C); - /* is this more than half a frame behind? */ - if (fps + 0.5f < (float)(FPS)) { - UI_ThemeColor(TH_REDALERT); - BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps); + if (rv3d->persp == RV3D_CAMOB) { + drawviewborder(scene, ar, v3d); } - else { - UI_ThemeColor(TH_TEXT_HI); - BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f)); + else if (v3d->flag2 & V3D_RENDER_BORDER) { + drawrenderborder(ar, v3d); } - -#ifdef WITH_INTERNATIONAL - BLF_draw_default(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); -#else - BLF_draw_default_ascii(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); -#endif } -static bool view3d_main_region_do_render_draw(Scene *scene) +/** +* Grease Pencil +*/ +static void view3d_draw_grease_pencil(const bContext *C) { - RenderEngineType *type = RE_engines_find(scene->r.engine); - - return (type && type->view_update && type->view_draw); + /* TODO viewport */ } -bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *rect) +/* ******************** view loop ***************** */ + +/** + * Set the correct matrices + */ +static void view3d_draw_setup_view(const bContext *C, ARegion *ar) { + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; - rctf viewborder; - bool use_border; - - /* test if there is a 3d view rendering */ - if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene)) - return false; - /* test if there is a border render */ - if (rv3d->persp == RV3D_CAMOB) - use_border = (scene->r.mode & R_BORDER) != 0; + /* setup the view matrix */ + if (view3d_stereo3d_active(C, scene, v3d, rv3d)) + view3d_stereo3d_setup(scene, v3d, ar); else - use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0; - - if (!use_border) - return false; - - /* compute border */ - if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); - - rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); - rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); - rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder); - rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder); - } - else { - rect->xmin = v3d->render_border.xmin * ar->winx; - rect->xmax = v3d->render_border.xmax * ar->winx; - rect->ymin = v3d->render_border.ymin * ar->winy; - rect->ymax = v3d->render_border.ymax * ar->winy; - } - - BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin); - BLI_rcti_isect(&ar->winrct, rect, rect); - - return true; + view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); } -static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene, - ARegion *ar, View3D *v3d, - bool clip_border, const rcti *border_rect) +static void draw_all_objects(const bContext *C, ARegion *ar, const bool only_depth, const bool use_depth) { - RegionView3D *rv3d = ar->regiondata; - RenderEngineType *type; - GLint scissor[4]; - - /* create render engine */ - if (!rv3d->render_engine) { - RenderEngine *engine; - - type = RE_engines_find(scene->r.engine); - - if (!(type->view_update && type->view_draw)) - return false; - - engine = RE_engine_create_ex(type, true); - - engine->tile_x = scene->r.tilex; - engine->tile_y = scene->r.tiley; + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); - type->view_update(engine, C); + if (only_depth) + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - rv3d->render_engine = engine; + if (only_depth || use_depth) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + v3d->zbuf = true; } - /* setup view matrices */ - view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); - - /* background draw */ - ED_region_pixelspace(ar); + for (Base *base = scene->base.first; base; base = base->next) { + if (v3d->lay & base->lay) { + /* dupli drawing */ + if (base->object->transflag & OB_DUPLI) + draw_dupli_objects(scene, ar, v3d, base); - if (clip_border) { - /* for border draw, we only need to clear a subset of the 3d view */ - if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) { - glGetIntegerv(GL_SCISSOR_BOX, scissor); - glScissor(border_rect->xmin, border_rect->ymin, - BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect)); - } - else { - return false; + draw_object(scene, ar, v3d, base, 0); } } - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (v3d->flag & V3D_DISPBGPICS) - view3d_draw_bgpic_test(scene, ar, v3d, false, true); - else - fdrawcheckerboard(0, 0, ar->winx, ar->winy); - - /* render result draw */ - type = rv3d->render_engine->type; - type->view_draw(rv3d->render_engine, C); + if (only_depth) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - if (v3d->flag & V3D_DISPBGPICS) - view3d_draw_bgpic_test(scene, ar, v3d, true, true); - - if (clip_border) { - /* restore scissor as it was before */ - glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); + if (only_depth || use_depth) { + glDisable(GL_DEPTH_TEST); + v3d->zbuf = false; } - - return true; } -static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border) +/** + * Draw only the scene depth buffer + */ +static void draw_depth_buffer(const bContext *C, ARegion *ar) { - float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f}; - - if (!rv3d->render_engine || !rv3d->render_engine->text[0]) - return; - - if (render_border) { - /* draw darkened background color. no alpha because border render does - * partial redraw and will not redraw the region behind this info bar */ - float alpha = 1.0f - fill_color[3]; - Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); - - if (camera) { - if (camera->flag & CAM_SHOWPASSEPARTOUT) { - alpha *= (1.0f - camera->passepartalpha); - } - } - - UI_GetThemeColor3fv(TH_HIGH_GRAD, fill_color); - mul_v3_fl(fill_color, alpha); - fill_color[3] = 1.0f; - } - - ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true); + draw_all_objects(C, ar, true, true); } -static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d) +/** + * Required if the shaders need it or external engines + * (e.g., Cycles requires depth buffer handled separately). + */ +static void view3d_draw_prerender_buffers(const bContext *C, ARegion *ar, DrawData *draw_data) { - wmWindow *win = CTX_wm_window(C); - - if ((scene->r.scemode & R_MULTIVIEW) == 0) - return false; - - if (WM_stereo3d_enabled(win, true) == false) - return false; - - if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) - return false; - - if (scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) { - if (v3d->stereo3d_camera == STEREO_MONO_ID) - return false; + View3D *v3d = CTX_wm_view3d(C); - return BKE_scene_multiview_is_stereo3d(&scene->r); + /* TODO viewport */ + if (draw_data->is_render && ((!draw_data->clip_border) || (v3d->drawtype <= OB_WIRE))) { + draw_depth_buffer(C, ar); } - - return true; } -/* setup the view and win matrices for the multiview cameras - * - * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called - * we have no winmatrix (i.e., projection matrix) defined at that time. - * Since the camera and the camera shift are needed for the winmat calculation - * we do a small hack to replace it temporarily so we don't need to change the - * view3d)main_region_setup_view() code to account for that. +/** + * Draw all the plates that will fill the RGBD buffer */ -static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) +static void view3d_draw_solid_plates(const bContext *C, ARegion *ar, DrawData *draw_data) { - bool is_left; - const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - const char *viewname; - - /* show only left or right camera */ - if (v3d->stereo3d_camera != STEREO_3D_ID) - v3d->multiview_eye = v3d->stereo3d_camera; - - is_left = v3d->multiview_eye == STEREO_LEFT_ID; - viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID]; - - /* update the viewport matrices with the new camera */ - if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { - Camera *data; - float viewmat[4][4]; - float shiftx; - - data = (Camera *)v3d->camera->data; - shiftx = data->shiftx; - - BLI_lock_thread(LOCK_VIEW3D); - data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname); - - BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); - - data->shiftx = shiftx; - BLI_unlock_thread(LOCK_VIEW3D); + /* realtime plates */ + if ((!draw_data->is_render) || draw_data->clip_border) { + view3d_draw_background(C); + view3d_draw_render_solid_surfaces(C, ar, true); + view3d_draw_render_transparent_surfaces(C); + view3d_draw_post_draw(C); } - else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ - float viewmat[4][4]; - Object *view_ob = v3d->camera; - Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - - BLI_lock_thread(LOCK_VIEW3D); - v3d->camera = camera; - BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); + /* offline plates*/ + if (draw_data->is_render) { + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); - v3d->camera = view_ob; - BLI_unlock_thread(LOCK_VIEW3D); - } -} - -static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, - float winmat[4][4], const char *viewname) -{ - /* update the viewport matrices with the new camera */ - if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { - float viewmat[4][4]; - const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); - - BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); + view3d_draw_render_draw(C, scene, ar, v3d, draw_data->clip_border, &draw_data->border_rect); } - else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ - float viewmat[4][4]; - Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); - } +#if VIEW3D_DRAW_DEBUG + view3d_draw_debug_post_solid(C, ar, draw_data); +#endif } -#ifdef WITH_GAMEENGINE -static void update_lods(Scene *scene, float camera_pos[3]) +/** + * Wires, outline, ... + */ +static void view3d_draw_geometry_overlay(const bContext *C) { - Scene *sce_iter; - Base *base; - Object *ob; - - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - BKE_object_lod_update(ob, camera_pos); - } + view3d_draw_wire_plates(C); + view3d_draw_outline_plates(C); } -#endif -static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d, - ARegion *ar, const char **grid_unit) +/* drawing cameras, lamps, ... */ +static void view3d_draw_non_meshes(const bContext *C, ARegion *ar) { - wmWindow *win = CTX_wm_window(C); + /* TODO viewport + * for now we draw them all, in the near future + * we filter them based on the plates/layers + */ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; - unsigned int lay_used = v3d->lay_used; - - /* post processing */ - bool do_compositing = false; - - /* shadow buffers, before we setup matrices */ - if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) - gpu_update_lamps_shadows_world(scene, v3d); - - /* reset default OpenGL lights if needed (i.e. after preferences have been altered) */ - if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) { - rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE; - GPU_default_lights(); - } - /* setup the view matrix */ - if (view3d_stereo3d_active(C, scene, v3d, rv3d)) - view3d_stereo3d_setup(scene, v3d, ar); - else - view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); + bool is_boundingbox = ((v3d->drawtype == OB_BOUNDBOX) || + ((v3d->drawtype == OB_RENDER) && (v3d->prev_drawtype == OB_BOUNDBOX))); - rv3d->rflag &= ~RV3D_IS_GAME_ENGINE; -#ifdef WITH_GAMEENGINE - if (STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)) { - rv3d->rflag |= RV3D_IS_GAME_ENGINE; + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + /* TODO Viewport + * we are already temporarily writing to zbuffer in draw_object() + * for now let's avoid writing again to zbuffer to prevent glitches + */ - /* Make sure LoDs are up to date */ - update_lods(scene, rv3d->viewinv[3]); - } -#endif + for (Base *base = scene->base.first; base; base = base->next) { + if (v3d->lay & base->lay) { + Object *ob = base->object; - /* framebuffer fx needed, we need to draw offscreen first */ - if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) { - GPUFXSettings fx_settings; - BKE_screen_gpu_fx_validate(&v3d->fx_settings); - fx_settings = v3d->fx_settings; - if (!rv3d->compositor) - rv3d->compositor = GPU_fx_compositor_create(); - - if (rv3d->persp == RV3D_CAMOB && v3d->camera) - BKE_camera_to_gpu_dof(v3d->camera, &fx_settings); - else { - fx_settings.dof = NULL; + unsigned char ob_wire_col[4]; + draw_object_wire_color(scene, base, ob_wire_col); + view3d_draw_non_mesh(scene, ob, base, v3d, rv3d, is_boundingbox, ob_wire_col); } - - do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings); - } - - /* clear the background */ - view3d_main_region_clear(scene, v3d, ar); - - /* enables anti-aliasing for 3D view drawing */ - if (win->multisamples != USER_MULTISAMPLE_NONE) { - glEnable(GL_MULTISAMPLE); } - /* main drawing call */ - view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); - - /* post process */ - if (do_compositing) { - GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL); - } - - /* Disable back anti-aliasing */ - if (win->multisamples != USER_MULTISAMPLE_NONE) { - glDisable(GL_MULTISAMPLE); - } + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); +} - if (v3d->lay_used != lay_used) { /* happens when loading old files or loading with UI load */ - /* find header and force tag redraw */ - ScrArea *sa = CTX_wm_area(C); - ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); - ED_region_tag_redraw(ar_header); /* can be NULL */ - } +/** +* Parent lines, grid, ... +*/ +static void view3d_draw_other_elements(const bContext *C, ARegion *ar) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ar->regiondata; - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - BDR_drawSketch(C); - } + view3d_draw_grid(C, ar); #ifdef WITH_INPUT_NDOF if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((rv3d->viewlock & RV3D_LOCKED) == 0) && (rv3d->persp != RV3D_CAMOB)) @@ -3814,248 +2012,178 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie #endif } -static bool is_cursor_visible(Scene *scene) +/** + * Paint brushes, armatures, ... + */ +static void view3d_draw_tool_ui(const bContext *C) { - Object *ob = OBACT; - - /* don't draw cursor in paint modes, but with a few exceptions */ - if (ob && ob->mode & OB_MODE_ALL_PAINT) { - /* exception: object is in weight paint and has deforming armature in pose mode */ - if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (BKE_object_pose_armature_get(ob) != NULL) { - return true; - } - } - /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */ - else if (ob->mode & OB_MODE_TEXTURE_PAINT) { - const Paint *p = BKE_paint_get_active(scene); - - if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) { - if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) { - return true; - } - } - } + /* TODO viewport */ +} - /* no exception met? then don't draw cursor! */ - return false; - } +/** + * Blueprint images + */ +static void view3d_draw_reference_images(const bContext *C) +{ + /* TODO viewport */ +} - return true; +/** +* 3D manipulators +*/ +static void view3d_draw_manipulator(const bContext *C) +{ + View3D *v3d = CTX_wm_view3d(C); + v3d->zbuf = false; + BIF_draw_manipulator(C); } -static void view3d_main_region_draw_info(const bContext *C, Scene *scene, - ARegion *ar, View3D *v3d, - const char *grid_unit, bool render_border) +/** +* Information drawn on top of the solid plates and composed data +*/ +static void view3d_draw_region_info(const bContext *C, ARegion *ar) { - wmWindowManager *wm = CTX_wm_manager(C); - RegionView3D *rv3d = ar->regiondata; - rcti rect; - + /* correct projection matrix */ + ED_region_pixelspace(ar); + /* local coordinate visible rect inside region, to accomodate overlapping ui */ + rcti rect; ED_region_visible_rect(ar, &rect); - if (rv3d->persp == RV3D_CAMOB) { - drawviewborder(scene, ar, v3d); - } - else if (v3d->flag2 & V3D_RENDER_BORDER) { - glLineWidth(1.0f); - setlinestyle(3); - cpack(0x4040FF); + view3d_draw_border(C, ar); + view3d_draw_grease_pencil(C); - sdrawbox(v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy, - v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy); + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ar->regiondata; - setlinestyle(0); + /* 3D cursor */ + if (is_cursor_visible(scene)) { + drawcursor(scene, ar, v3d); } - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(wm, scene, v3d, ar, false); + if (U.uiflag & USER_SHOW_ROTVIEWICON) { + draw_view_axis(rv3d, &rect); } - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - Object *ob; - - /* 3d cursor */ - if (is_cursor_visible(scene)) { - drawcursor(scene, ar, v3d); - } + /* TODO viewport */ +} - if (U.uiflag & USER_SHOW_ROTVIEWICON) - draw_view_axis(rv3d, &rect); - else - draw_view_icon(rv3d, &rect); +/** + * This could run once per view, or even in parallel + * for each of them. What is a "view"? + * - a viewport with the camera elsewhere + * - left/right stereo + * - panorama / fisheye individual cubemap faces + */ +static void view3d_draw_view(const bContext *C, ARegion *ar, DrawData *draw_data) +{ + /* TODO - Technically this should be drawn to a few FBO, so we can handle + * compositing better, but for now this will get the ball rolling (dfelinto) */ + + view3d_draw_setup_view(C, ar); + view3d_draw_prerender_buffers(C, ar, draw_data); + view3d_draw_solid_plates(C, ar, draw_data); + view3d_draw_geometry_overlay(C); + view3d_draw_non_meshes(C, ar); + view3d_draw_other_elements(C, ar); + view3d_draw_tool_ui(C); + view3d_draw_reference_images(C); + view3d_draw_manipulator(C); + view3d_draw_region_info(C, ar); + +#if VIEW3D_DRAW_DEBUG + view3d_draw_debug(C, ar, draw_data); +#endif +} - ob = OBACT; - if (U.uiflag & USER_DRAWVIEWINFO) - draw_selected_name(scene, ob, &rect); - } +void view3d_main_region_draw(const bContext *C, ARegion *ar) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ar->regiondata; - if (rv3d->render_engine) { - view3d_main_region_draw_engine_info(v3d, rv3d, ar, render_border); + if (IS_VIEWPORT_LEGACY(v3d)) { + view3d_main_region_draw_legacy(C, ar); return; } - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { - ED_scene_draw_fps(scene, &rect); - } - else if (U.uiflag & USER_SHOW_VIEWPORTNAME) { - draw_viewport_name(ar, v3d, &rect); - } + if (!rv3d->viewport) + rv3d->viewport = GPU_viewport_create(); - if (grid_unit) { /* draw below the viewport name */ - char numstr[32] = ""; + /* TODO viewport - there is so much to be done, in fact a lot will need to happen in the space_view3d.c + * before we even call the drawing routine, but let's move on for now (dfelinto) + * but this is a provisory way to start seeing things in the viewport */ + DrawData draw_data; + view3d_draw_data_init(C, ar, rv3d, &draw_data); + view3d_draw_view(C, ar, &draw_data); - UI_ThemeColor(TH_TEXT_HI); - if (v3d->grid != 1.0f) { - BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); - } + v3d->flag |= V3D_INVALID_BACKBUF; +} - BLF_draw_default_ascii(rect.xmin + U.widget_unit, - rect.ymax - (USER_SHOW_VIEWPORTNAME ? 2 * U.widget_unit : U.widget_unit), 0.0f, - numstr[0] ? numstr : grid_unit, sizeof(numstr)); - } +/* ******************** legacy interface ***************** */ +/** + * This will be removed once the viewport gets replaced + * meanwhile it should keep the old viewport working. + */ + +void VP_legacy_drawcursor(Scene *scene, ARegion *ar, View3D *v3d) +{ + if (is_cursor_visible(scene)) { + drawcursor(scene, ar, v3d); } } -void view3d_main_region_draw(const bContext *C, ARegion *ar) +void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - const char *grid_unit = NULL; - rcti border_rect; - bool render_border, clip_border; - - /* if we only redraw render border area, skip opengl draw and also - * don't do scissor because it's already set */ - render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect); - clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); + draw_view_axis(rv3d, rect); +} - /* draw viewport using opengl */ - if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) { - view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit); - -#ifdef DEBUG_DRAW - bl_debug_draw(); -#endif - if (G.debug & G_DEBUG_SIMDATA) - draw_sim_debug_data(scene, v3d, ar); - - ED_region_pixelspace(ar); - } +void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit) +{ + drawgrid(unit, ar, v3d, grid_unit); +} - /* draw viewport using external renderer */ - if (v3d->drawtype == OB_RENDER) - view3d_main_region_draw_engine(C, scene, ar, v3d, clip_border, &border_rect); - - view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); +void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth) +{ + drawfloor(scene, v3d, grid_unit, write_depth); +} - v3d->flag |= V3D_INVALID_BACKBUF; +void VP_legacy_view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) +{ + view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); +} - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp)); - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray)); - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp)); +bool VP_legacy_view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d) +{ + return view3d_stereo3d_active(C, scene, v3d, rv3d); } -#ifdef DEBUG_DRAW -/* debug drawing */ -#define _DEBUG_DRAW_QUAD_TOT 1024 -#define _DEBUG_DRAW_EDGE_TOT 1024 -static float _bl_debug_draw_quads[_DEBUG_DRAW_QUAD_TOT][4][3]; -static int _bl_debug_draw_quads_tot = 0; -static float _bl_debug_draw_edges[_DEBUG_DRAW_QUAD_TOT][2][3]; -static int _bl_debug_draw_edges_tot = 0; -static unsigned int _bl_debug_draw_quads_color[_DEBUG_DRAW_QUAD_TOT]; -static unsigned int _bl_debug_draw_edges_color[_DEBUG_DRAW_EDGE_TOT]; -static unsigned int _bl_debug_draw_color; +void VP_legacy_view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) +{ + view3d_stereo3d_setup(scene, v3d, ar); +} -void bl_debug_draw_quad_clear(void) +bool VP_legacy_use_depth(Scene *scene, View3D *v3d) { - _bl_debug_draw_quads_tot = 0; - _bl_debug_draw_edges_tot = 0; - _bl_debug_draw_color = 0x00FF0000; + return use_depth_doit(scene, v3d); } -void bl_debug_color_set(const unsigned int color) + +void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) { - _bl_debug_draw_color = color; + drawviewborder(scene, ar, v3d); } -void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]) + +void VP_drawrenderborder(ARegion *ar, View3D *v3d) { - if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_QUAD_TOT) { - printf("%s: max quad count hit %d!", __func__, _bl_debug_draw_quads_tot); - } - else { - float *pt = &_bl_debug_draw_quads[_bl_debug_draw_quads_tot][0][0]; - copy_v3_v3(pt, v0); pt += 3; - copy_v3_v3(pt, v1); pt += 3; - copy_v3_v3(pt, v2); pt += 3; - copy_v3_v3(pt, v3); pt += 3; - _bl_debug_draw_quads_color[_bl_debug_draw_quads_tot] = _bl_debug_draw_color; - _bl_debug_draw_quads_tot++; - } + drawrenderborder(ar, v3d); } -void bl_debug_draw_edge_add(const float v0[3], const float v1[3]) + +void VP_view3d_draw_background_none(void) { - if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_EDGE_TOT) { - printf("%s: max edge count hit %d!", __func__, _bl_debug_draw_edges_tot); - } - else { - float *pt = &_bl_debug_draw_edges[_bl_debug_draw_edges_tot][0][0]; - copy_v3_v3(pt, v0); pt += 3; - copy_v3_v3(pt, v1); pt += 3; - _bl_debug_draw_edges_color[_bl_debug_draw_edges_tot] = _bl_debug_draw_color; - _bl_debug_draw_edges_tot++; - } + view3d_draw_background_none(); } -static void bl_debug_draw(void) -{ - unsigned int color; - if (_bl_debug_draw_quads_tot) { - int i; - color = _bl_debug_draw_quads_color[0]; - cpack(color); - for (i = 0; i < _bl_debug_draw_quads_tot; i ++) { - if (_bl_debug_draw_quads_color[i] != color) { - color = _bl_debug_draw_quads_color[i]; - cpack(color); - } - glBegin(GL_LINE_LOOP); - glVertex3fv(_bl_debug_draw_quads[i][0]); - glVertex3fv(_bl_debug_draw_quads[i][1]); - glVertex3fv(_bl_debug_draw_quads[i][2]); - glVertex3fv(_bl_debug_draw_quads[i][3]); - glEnd(); - } - } - if (_bl_debug_draw_edges_tot) { - int i; - color = _bl_debug_draw_edges_color[0]; - cpack(color); - glBegin(GL_LINES); - for (i = 0; i < _bl_debug_draw_edges_tot; i ++) { - if (_bl_debug_draw_edges_color[i] != color) { - color = _bl_debug_draw_edges_color[i]; - cpack(color); - } - glVertex3fv(_bl_debug_draw_edges[i][0]); - glVertex3fv(_bl_debug_draw_edges[i][1]); - } - glEnd(); - color = _bl_debug_draw_edges_color[0]; - cpack(color); - glPointSize(4.0); - glBegin(GL_POINTS); - for (i = 0; i < _bl_debug_draw_edges_tot; i ++) { - if (_bl_debug_draw_edges_color[i] != color) { - color = _bl_debug_draw_edges_color[i]; - cpack(color); - } - glVertex3fv(_bl_debug_draw_edges[i][0]); - glVertex3fv(_bl_debug_draw_edges[i][1]); - } - glEnd(); - } + +void VP_view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d) +{ + view3d_draw_background_world(scene, v3d, rv3d); } -#endif diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c new file mode 100644 index 00000000000..639be36d739 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -0,0 +1,2731 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_draw.c + * \ingroup spview3d + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> + +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" +#include "DNA_group_types.h" +#include "DNA_mesh_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_scene_types.h" +#include "DNA_world_types.h" +#include "DNA_brush_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_jitter.h" +#include "BLI_utildefines.h" +#include "BLI_endian_switch.h" +#include "BLI_threads.h" + +#include "BKE_anim.h" +#include "BKE_camera.h" +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_image.h" +#include "BKE_key.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_global.h" +#include "BKE_paint.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_unit.h" +#include "BKE_movieclip.h" + +#include "RE_engine.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_colormanagement.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" + +#include "BLF_api.h" +#include "BLT_translation.h" + +#include "ED_armature.h" +#include "ED_keyframing.h" +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_screen_types.h" +#include "ED_transform.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_resources.h" + +#include "GPU_draw.h" +#include "GPU_framebuffer.h" +#include "GPU_material.h" +#include "GPU_compositing.h" +#include "GPU_extensions.h" +#include "GPU_immediate.h" + +#include "view3d_intern.h" /* own include */ + +/* prototypes */ +static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, + float winmat[4][4], const char *viewname); + +void circ(float x, float y, float rad) +{ + glBegin(GL_LINE_LOOP); + const int segments = 32; + for (int i = 0; i < segments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)segments); + glVertex2f(x + rad * cosf(angle), + y + rad * sinf(angle)); + } + glEnd(); +} + + +/* ********* custom clipping *********** */ + +static void view3d_draw_clipping(RegionView3D *rv3d) +{ + BoundBox *bb = rv3d->clipbb; + + if (bb) { + const unsigned int clipping_index[6][4] = { + {0, 1, 2, 3}, + {0, 4, 5, 1}, + {4, 7, 6, 5}, + {7, 3, 2, 6}, + {1, 5, 6, 2}, + {7, 4, 0, 3} + }; + + /* fill in zero alpha for rendering & re-projection [#31530] */ + unsigned char col[4]; + UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col); + glColor4ubv(col); + + glEnable(GL_BLEND); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, bb->vec); + glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index); + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_BLEND); + } +} + +void ED_view3d_clipping_set(RegionView3D *rv3d) +{ + double plane[4]; + const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6; + + for (unsigned a = 0; a < tot; a++) { + copy_v4db_v4fl(plane, rv3d->clip[a]); + glClipPlane(GL_CLIP_PLANE0 + a, plane); + glEnable(GL_CLIP_PLANE0 + a); + } +} + +/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */ +void ED_view3d_clipping_disable(void) +{ + for (unsigned a = 0; a < 6; a++) { + glDisable(GL_CLIP_PLANE0 + a); + } +} +void ED_view3d_clipping_enable(void) +{ + for (unsigned a = 0; a < 6; a++) { + glEnable(GL_CLIP_PLANE0 + a); + } +} + +static bool view3d_clipping_test(const float co[3], const float clip[6][4]) +{ + if (plane_point_side_v3(clip[0], co) > 0.0f) + if (plane_point_side_v3(clip[1], co) > 0.0f) + if (plane_point_side_v3(clip[2], co) > 0.0f) + if (plane_point_side_v3(clip[3], co) > 0.0f) + return false; + + return true; +} + +/* for 'local' ED_view3d_clipping_local must run first + * then all comparisons can be done in localspace */ +bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local) +{ + return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip); +} + +/* ********* end custom clipping *********** */ + +static void draw_view_icon(RegionView3D *rv3d, rcti *rect) +{ + BIFIconID icon; + + if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) + icon = ICON_AXIS_TOP; + else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) + icon = ICON_AXIS_FRONT; + else if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) + icon = ICON_AXIS_SIDE; + else return; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon); + + glDisable(GL_BLEND); +} + +static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d) +{ + const char *name = NULL; + + switch (rv3d->view) { + case RV3D_VIEW_FRONT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho"); + else name = IFACE_("Front Persp"); + break; + case RV3D_VIEW_BACK: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho"); + else name = IFACE_("Back Persp"); + break; + case RV3D_VIEW_TOP: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Ortho"); + else name = IFACE_("Top Persp"); + break; + case RV3D_VIEW_BOTTOM: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Ortho"); + else name = IFACE_("Bottom Persp"); + break; + case RV3D_VIEW_RIGHT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Ortho"); + else name = IFACE_("Right Persp"); + break; + case RV3D_VIEW_LEFT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Ortho"); + else name = IFACE_("Left Persp"); + break; + + default: + if (rv3d->persp == RV3D_CAMOB) { + if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) { + Camera *cam; + cam = v3d->camera->data; + if (cam->type == CAM_PERSP) { + name = IFACE_("Camera Persp"); + } + else if (cam->type == CAM_ORTHO) { + name = IFACE_("Camera Ortho"); + } + else { + BLI_assert(cam->type == CAM_PANO); + name = IFACE_("Camera Pano"); + } + } + else { + name = IFACE_("Object as Camera"); + } + } + else { + name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Ortho") : IFACE_("User Persp"); + } + } + + return name; +} + +static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect) +{ + RegionView3D *rv3d = ar->regiondata; + const char *name = view3d_get_name(v3d, rv3d); + /* increase size for unicode languages (Chinese in utf-8...) */ +#ifdef WITH_INTERNATIONAL + char tmpstr[96]; +#else + char tmpstr[32]; +#endif + + if (v3d->localvd) { + BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name); + name = tmpstr; + } + + UI_ThemeColor(TH_TEXT_HI); +#ifdef WITH_INTERNATIONAL + BLF_draw_default(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); +#else + BLF_draw_default_ascii(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); +#endif +} + +/* draw info beside axes in bottom left-corner: + * framenum, object name, bone name (if available), marker name (if available) + */ + +static void draw_selected_name(Scene *scene, Object *ob, rcti *rect) +{ + const int cfra = CFRA; + const char *msg_pin = " (Pinned)"; + const char *msg_sep = " : "; + + char info[300]; + char *s = info; + short offset = 1.5f * UI_UNIT_X + rect->xmin; + + s += sprintf(s, "(%d)", cfra); + + /* + * info can contain: + * - a frame (7 + 2) + * - 3 object names (MAX_NAME) + * - 2 BREAD_CRUMB_SEPARATORs (6) + * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room! + * - a marker name (MAX_NAME + 3) + */ + + /* get name of marker on current frame (if available) */ + const char *markern = BKE_scene_find_marker_name(scene, cfra); + + /* check if there is an object */ + if (ob) { + *s++ = ' '; + s += BLI_strcpy_rlen(s, ob->id.name + 2); + + /* name(s) to display depends on type of object */ + if (ob->type == OB_ARMATURE) { + bArmature *arm = ob->data; + + /* show name of active bone too (if possible) */ + if (arm->edbo) { + if (arm->act_edbone) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_edbone->name); + } + } + else if (ob->mode & OB_MODE_POSE) { + if (arm->act_bone) { + + if (arm->act_bone->layer & arm->layer) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_bone->name); + } + } + } + } + else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { + /* try to display active bone and active shapekey too (if they exist) */ + + if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) { + Object *armobj = BKE_object_pose_armature_get(ob); + if (armobj && armobj->mode & OB_MODE_POSE) { + bArmature *arm = armobj->data; + if (arm->act_bone) { + if (arm->act_bone->layer & arm->layer) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_bone->name); + } + } + } + } + + Key *key = BKE_key_from_object(ob); + if (key) { + KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1); + if (kb) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, kb->name); + if (ob->shapeflag & OB_SHAPE_LOCK) { + s += BLI_strcpy_rlen(s, IFACE_(msg_pin)); + } + } + } + } + + /* color depends on whether there is a keyframe */ + if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) + UI_ThemeColor(TH_TIME_KEYFRAME); + else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) + UI_ThemeColor(TH_TIME_GP_KEYFRAME); + else + UI_ThemeColor(TH_TEXT_HI); + } + else { + /* no object */ + if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) + UI_ThemeColor(TH_TIME_GP_KEYFRAME); + else + UI_ThemeColor(TH_TEXT_HI); + } + + if (markern) { + s += sprintf(s, " <%s>", markern); + } + + if (U.uiflag & USER_SHOW_ROTVIEWICON) + offset = U.widget_unit + (U.rvisize * 2) + rect->xmin; + + BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info)); +} + +/* *********************** backdraw for selection *************** */ + +static void backdrawview3d(Scene *scene, wmWindow *win, ARegion *ar, View3D *v3d) +{ + RegionView3D *rv3d = ar->regiondata; + struct Base *base = scene->basact; + int multisample_enabled; + + BLI_assert(ar->regiontype == RGN_TYPE_WINDOW); + + if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) || + BKE_paint_select_face_test(base->object))) + { + /* do nothing */ + } + /* texture paint mode sampling */ + else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) && + (v3d->drawtype > OB_WIRE)) + { + /* do nothing */ + } + else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) && + V3D_IS_ZBUF(v3d)) + { + /* do nothing */ + } + else if (scene->obedit && + V3D_IS_ZBUF(v3d)) + { + /* do nothing */ + } + else { + v3d->flag &= ~V3D_INVALID_BACKBUF; + return; + } + + if (!(v3d->flag & V3D_INVALID_BACKBUF)) + return; + +#if 0 + if (test) { + if (qtest()) { + addafterqueue(ar->win, BACKBUFDRAW, 1); + return; + } + } +#endif + + if (v3d->drawtype > OB_WIRE) v3d->zbuf = true; + + /* dithering and AA break color coding, so disable */ + glDisable(GL_DITHER); + + multisample_enabled = glIsEnabled(GL_MULTISAMPLE); + if (multisample_enabled) + glDisable(GL_MULTISAMPLE); + + if (win->multisamples != USER_MULTISAMPLE_NONE) { + /* for multisample we use an offscreen FBO. multisample drawing can fail + * with color coded selection drawing, and reading back depths from such + * a buffer can also cause a few seconds freeze on OS X / NVidia. */ + int w = BLI_rcti_size_x(&ar->winrct); + int h = BLI_rcti_size_y(&ar->winrct); + char error[256]; + + if (rv3d->gpuoffscreen) { + if (GPU_offscreen_width(rv3d->gpuoffscreen) != w || + GPU_offscreen_height(rv3d->gpuoffscreen) != h) + { + GPU_offscreen_free(rv3d->gpuoffscreen); + rv3d->gpuoffscreen = NULL; + } + } + + if (!rv3d->gpuoffscreen) { + rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error); + + if (!rv3d->gpuoffscreen) + fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); + } + } + + if (rv3d->gpuoffscreen) + GPU_offscreen_bind(rv3d->gpuoffscreen, true); + else + glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); + + glClearColor(0.0, 0.0, 0.0, 0.0); + if (v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + else { + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_DEPTH_TEST); + } + + if (rv3d->rflag & RV3D_CLIPPING) + ED_view3d_clipping_set(rv3d); + + G.f |= G_BACKBUFSEL; + + if (base && (base->lay & v3d->lay)) + draw_object_backbufsel(scene, v3d, rv3d, base->object); + + if (rv3d->gpuoffscreen) + GPU_offscreen_unbind(rv3d->gpuoffscreen, true); + else + ar->swap = 0; /* mark invalid backbuf for wm draw */ + + v3d->flag &= ~V3D_INVALID_BACKBUF; + + G.f &= ~G_BACKBUFSEL; + v3d->zbuf = false; + glDisable(GL_DEPTH_TEST); + glEnable(GL_DITHER); + if (multisample_enabled) + glEnable(GL_MULTISAMPLE); + + if (rv3d->rflag & RV3D_CLIPPING) + ED_view3d_clipping_disable(); +} + +void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) +{ + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->gpuoffscreen) { + GPU_offscreen_bind(rv3d->gpuoffscreen, true); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glReadPixels(x, y, w, h, format, type, data); + GPU_offscreen_unbind(rv3d->gpuoffscreen, true); + } + else { + glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); + } +} + +/* XXX depth reading exception, for code not using gpu offscreen */ +static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) +{ + glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); +} + +void ED_view3d_backbuf_validate(ViewContext *vc) +{ + if (vc->v3d->flag & V3D_INVALID_BACKBUF) + backdrawview3d(vc->scene, vc->win, vc->ar, vc->v3d); +} + +/** + * allow for small values [0.5 - 2.5], + * and large values, FLT_MAX by clamping by the area size + */ +int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist) +{ + return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx)); +} + +/* samples a single pixel (copied from vpaint) */ +unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) +{ + if (x >= vc->ar->winx || y >= vc->ar->winy) { + return 0; + } + + ED_view3d_backbuf_validate(vc); + + unsigned int col; + view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); + glReadBuffer(GL_BACK); + + if (ENDIAN_ORDER == B_ENDIAN) { + BLI_endian_switch_uint32(&col); + } + + return GPU_select_to_index(col); +} + +/* reads full rect, converts indices */ +ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax) +{ + /* clip */ + const rcti clip = { + max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1), + max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)}; + const int size_clip[2] = { + BLI_rcti_size_x(&clip) + 1, + BLI_rcti_size_y(&clip) + 1}; + + if (UNLIKELY((clip.xmin > clip.xmax) || + (clip.ymin > clip.ymax))) + { + return NULL; + } + + ImBuf *ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect); + + ED_view3d_backbuf_validate(vc); + + view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect); + + glReadBuffer(GL_BACK); + + if (ENDIAN_ORDER == B_ENDIAN) { + IMB_convert_rgba_to_abgr(ibuf_clip); + } + + GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); + + if ((clip.xmin == xmin) && + (clip.xmax == xmax) && + (clip.ymin == ymin) && + (clip.ymax == ymax)) + { + return ibuf_clip; + } + else { + /* put clipped result into a non-clipped buffer */ + const int size[2] = { + (xmax - xmin + 1), + (ymax - ymin + 1)}; + + ImBuf *ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect); + + IMB_rectcpy( + ibuf_full, ibuf_clip, + clip.xmin - xmin, clip.ymin - ymin, + 0, 0, + size_clip[0], size_clip[1]); + IMB_freeImBuf(ibuf_clip); + return ibuf_full; + } +} + +/* smart function to sample a rect spiralling outside, nice for backbuf selection */ +unsigned int ED_view3d_backbuf_sample_rect( + ViewContext *vc, const int mval[2], int size, + unsigned int min, unsigned int max, float *r_dist) +{ + int dirvec[4][2]; + + const int amount = (size - 1) / 2; + + const int minx = mval[0] - (amount + 1); + const int miny = mval[1] - (amount + 1); + ImBuf *buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1); + if (!buf) return 0; + + unsigned index = 0; + int rc = 0; + + dirvec[0][0] = 1; dirvec[0][1] = 0; + dirvec[1][0] = 0; dirvec[1][1] = -size; + dirvec[2][0] = -1; dirvec[2][1] = 0; + dirvec[3][0] = 0; dirvec[3][1] = size; + + const unsigned *bufmin = buf->rect; + const unsigned *tbuf = buf->rect; + const unsigned *bufmax = buf->rect + size * size; + tbuf += amount * size + amount; + + for (int nr = 1; nr <= size; nr++) { + for (int a = 0; a < 2; a++) { + for (int b = 0; b < nr; b++) { + if (*tbuf && *tbuf >= min && *tbuf < max) { + /* we got a hit */ + + /* get x,y pixel coords from the offset + * (manhatten distance in keeping with other screen-based selection) */ + *r_dist = (float)( + abs(((int)(tbuf - buf->rect) % size) - (size / 2)) + + abs(((int)(tbuf - buf->rect) / size) - (size / 2))); + + /* indices start at 1 here */ + index = (*tbuf - min) + 1; + goto exit; + } + + tbuf += (dirvec[rc][0] + dirvec[rc][1]); + + if (tbuf < bufmin || tbuf >= bufmax) { + goto exit; + } + } + rc++; + rc &= 3; + } + } + +exit: + IMB_freeImBuf(buf); + return index; +} + + +/* ************************************************************* */ + +static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) +{ + if (BKE_image_is_stereo(ima)) { + iuser->flag |= IMA_SHOW_STEREO; + + if ((scene->r.scemode & R_MULTIVIEW) == 0) { + iuser->multiview_eye = STEREO_LEFT_ID; + } + else if (v3d->stereo3d_camera != STEREO_3D_ID) { + /* show only left or right camera */ + iuser->multiview_eye = v3d->stereo3d_camera; + } + + BKE_image_multiview_index(ima, iuser); + } + else { + iuser->flag &= ~IMA_SHOW_STEREO; + } +} + +static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, + const bool do_foreground, const bool do_camera_frame) +{ + RegionView3D *rv3d = ar->regiondata; + int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0; + + for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + bgpic->iuser.scene = scene; /* Needed for render results. */ + + if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag) + continue; + + if ((bgpic->view == 0) || /* zero for any */ + (bgpic->view & (1 << rv3d->view)) || /* check agaist flags */ + (rv3d->persp == RV3D_CAMOB && bgpic->view == (1 << RV3D_VIEW_CAMERA))) + { + float image_aspect[2]; + float x1, y1, x2, y2, centx, centy; + + void *lock; + + Image *ima = NULL; + + /* disable individual images */ + if ((bgpic->flag & V3D_BGPIC_DISABLED)) + continue; + + ImBuf *ibuf = NULL; + ImBuf *freeibuf = NULL; + ImBuf *releaseibuf = NULL; + if (bgpic->source == V3D_BGPIC_IMAGE) { + ima = bgpic->ima; + if (ima == NULL) + continue; + BKE_image_user_frame_calc(&bgpic->iuser, CFRA, 0); + if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) { + ibuf = NULL; /* frame is out of range, dont show */ + } + else { + view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser); + ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock); + releaseibuf = ibuf; + } + + image_aspect[0] = ima->aspx; + image_aspect[1] = ima->aspy; + } + else if (bgpic->source == V3D_BGPIC_MOVIE) { + /* TODO: skip drawing when out of frame range (as image sequences do above) */ + MovieClip *clip = NULL; + + if (bgpic->flag & V3D_BGPIC_CAMERACLIP) { + if (scene->camera) + clip = BKE_object_movieclip_get(scene, scene->camera, true); + } + else { + clip = bgpic->clip; + } + + if (clip == NULL) + continue; + + BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA); + ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser); + + image_aspect[0] = clip->aspx; + image_aspect[1] = clip->aspy; + + /* working with ibuf from image and clip has got different workflow now. + * ibuf acquired from clip is referenced by cache system and should + * be dereferenced after usage. */ + freeibuf = ibuf; + } + else { + /* perhaps when loading future files... */ + BLI_assert(0); + copy_v2_fl(image_aspect, 1.0f); + } + + if (ibuf == NULL) + continue; + + if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */ + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + + continue; + } + + if (ibuf->rect == NULL) + IMB_rect_from_float(ibuf); + + if (rv3d->persp == RV3D_CAMOB) { + + if (do_camera_frame) { + rctf vb; + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); + x1 = vb.xmin; + y1 = vb.ymin; + x2 = vb.xmax; + y2 = vb.ymax; + } + else { + x1 = ar->winrct.xmin; + y1 = ar->winrct.ymin; + x2 = ar->winrct.xmax; + y2 = ar->winrct.ymax; + } + + /* apply offset last - camera offset is different to offset in blender units */ + /* so this has some sane way of working - this matches camera's shift _exactly_ */ + { + const float max_dim = max_ff(x2 - x1, y2 - y1); + const float xof_scale = bgpic->xof * max_dim; + const float yof_scale = bgpic->yof * max_dim; + + x1 += xof_scale; + y1 += yof_scale; + x2 += xof_scale; + y2 += yof_scale; + } + + centx = (x1 + x2) * 0.5f; + centy = (y1 + y2) * 0.5f; + + /* aspect correction */ + if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) { + /* apply aspect from clip */ + const float w_src = ibuf->x * image_aspect[0]; + const float h_src = ibuf->y * image_aspect[1]; + + /* destination aspect is already applied from the camera frame */ + const float w_dst = x1 - x2; + const float h_dst = y1 - y2; + + const float asp_src = w_src / h_src; + const float asp_dst = w_dst / h_dst; + + if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { + if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) { + /* fit X */ + const float div = asp_src / asp_dst; + x1 = ((x1 - centx) * div) + centx; + x2 = ((x2 - centx) * div) + centx; + } + else { + /* fit Y */ + const float div = asp_dst / asp_src; + y1 = ((y1 - centy) * div) + centy; + y2 = ((y2 - centy) * div) + centy; + } + } + } + } + else { + float tvec[3]; + float sco[2]; + const float mval_f[2] = {1.0f, 0.0f}; + const float co_zero[3] = {0}; + + /* calc window coord */ + float zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL); + ED_view3d_win_to_delta(ar, mval_f, tvec, zfac); + float fac = 1.0f / max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */ + float asp = (float)ibuf->y / (float)ibuf->x; + + zero_v3(tvec); + ED_view3d_project_float_v2_m4(ar, tvec, sco, rv3d->persmat); + + x1 = sco[0] + fac * (bgpic->xof - bgpic->size); + y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size); + x2 = sco[0] + fac * (bgpic->xof + bgpic->size); + y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size); + + centx = (x1 + x2) / 2.0f; + centy = (y1 + y2) / 2.0f; + } + + /* complete clip? */ + rctf clip_rect; + BLI_rctf_init(&clip_rect, x1, x2, y1, y2); + if (bgpic->rotation) { + BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation); + } + + if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) { + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + + continue; + } + + float zoomx = (x2 - x1) / ibuf->x; + float zoomy = (y2 - y1) / ibuf->y; + + /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */ + if (zoomx < 1.0f || zoomy < 1.0f) { + float tzoom = min_ff(zoomx, zoomy); + int mip = 0; + + if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) { + IMB_remakemipmap(ibuf, 0); + ibuf->userflags &= ~IB_MIPMAP_INVALID; + } + else if (ibuf->mipmap[0] == NULL) + IMB_makemipmap(ibuf, 0); + + while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) { + tzoom *= 2.0f; + zoomx *= 2.0f; + zoomy *= 2.0f; + mip++; + } + if (mip > 0) + ibuf = ibuf->mipmap[mip - 1]; + } + + if (v3d->zbuf) glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + ED_region_pixelspace(ar); + + glTranslatef(centx, centy, 0.0); + glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f); + + if (bgpic->flag & V3D_BGPIC_FLIP_X) { + zoomx *= -1.0f; + x1 = x2; + } + if (bgpic->flag & V3D_BGPIC_FLIP_Y) { + zoomy *= -1.0f; + y1 = y2; + } + glPixelZoom(zoomx, zoomy); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend); + + /* could not use glaDrawPixelsAuto because it could fallback to + * glaDrawPixelsSafe in some cases, which will end up in missing + * alpha transparency for the background image (sergey) + */ + glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); + + glPixelZoom(1.0, 1.0); + glPixelTransferf(GL_ALPHA_SCALE, 1.0f); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glDisable(GL_BLEND); + + glDepthMask(GL_TRUE); + if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + } + } +} + +static void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, + const bool do_foreground, const bool do_camera_frame) +{ + RegionView3D *rv3d = ar->regiondata; + + if ((v3d->flag & V3D_DISPBGPICS) == 0) + return; + + /* disabled - mango request, since footage /w only render is quite useful + * and this option is easy to disable all background images at once */ +#if 0 + if (v3d->flag2 & V3D_RENDER_OVERRIDE) + return; +#endif + + if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { + if (rv3d->persp == RV3D_CAMOB) { + view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); + } + } + else { + view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); + } +} + +/* ****************** View3d afterdraw *************** */ + +typedef struct View3DAfter { + struct View3DAfter *next, *prev; + struct Base *base; + short dflag; +} View3DAfter; + +/* temp storage of Objects that need to be drawn as last */ +void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag) +{ + View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after"); + BLI_assert((base->flag & OB_FROMDUPLI) == 0); + BLI_addtail(lb, v3da); + v3da->base = base; + v3da->dflag = dflag; +} + +/* disables write in zbuffer and draws it over */ +static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d) +{ + View3DAfter *v3da; + + glDepthMask(GL_FALSE); + v3d->transp = true; + + while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { + draw_object(scene, ar, v3d, v3da->base, v3da->dflag); + MEM_freeN(v3da); + } + v3d->transp = false; + + glDepthMask(GL_TRUE); + +} + +/* clears zbuffer and draws it over */ +static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear) +{ + if (*clear && v3d->zbuf) { + glClear(GL_DEPTH_BUFFER_BIT); + *clear = false; + } + + v3d->xray = true; + View3DAfter *v3da; + while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { + draw_object(scene, ar, v3d, v3da->base, v3da->dflag); + MEM_freeN(v3da); + } + v3d->xray = false; +} + + +/* clears zbuffer and draws it over */ +static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const bool clear) +{ + if (clear && v3d->zbuf) + glClear(GL_DEPTH_BUFFER_BIT); + + v3d->xray = true; + v3d->transp = true; + + glDepthMask(GL_FALSE); + + View3DAfter *v3da; + while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { + draw_object(scene, ar, v3d, v3da->base, v3da->dflag); + MEM_freeN(v3da); + } + + v3d->transp = false; + v3d->xray = false; + + glDepthMask(GL_TRUE); +} + +/* *********************** */ + +/* + * In most cases call draw_dupli_objects, + * draw_dupli_objects_color was added because when drawing set dupli's + * we need to force the color + */ + +#if 0 +int dupli_ob_sort(void *arg1, void *arg2) +{ + void *p1 = ((DupliObject *)arg1)->ob; + void *p2 = ((DupliObject *)arg2)->ob; + int val = 0; + if (p1 < p2) val = -1; + else if (p1 > p2) val = 1; + return val; +} +#endif + + +static DupliObject *dupli_step(DupliObject *dob) +{ + while (dob && dob->no_draw) + dob = dob->next; + return dob; +} + +static void draw_dupli_objects_color( + Scene *scene, ARegion *ar, View3D *v3d, Base *base, + const short dflag, const int color) +{ + RegionView3D *rv3d = ar->regiondata; + ListBase *lb; + LodLevel *savedlod; + Base tbase = {NULL}; + BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */ + GLuint displist = 0; + unsigned char color_rgb[3]; + const short dflag_dupli = dflag | DRAW_CONSTCOLOR; + short transflag; + bool use_displist = false; /* -1 is initialize */ + char dt; + short dtx; + DupliApplyData *apply_data; + + if (base->object->restrictflag & OB_RESTRICT_VIEW) return; + if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return; + + if (dflag & DRAW_CONSTCOLOR) { + BLI_assert(color == TH_UNDEFINED); + } + else { + UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb); + } + + tbase.flag = OB_FROMDUPLI | base->flag; + lb = object_duplilist(G.main->eval_ctx, scene, base->object); + // BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */ + + apply_data = duplilist_apply(base->object, scene, lb); + + DupliObject *dob_prev = NULL, *dob_next = NULL; + DupliObject *dob = dupli_step(lb->first); + if (dob) dob_next = dupli_step(dob->next); + + for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) { + bool testbb = false; + + tbase.object = dob->ob; + + /* Make sure lod is updated from dupli's position */ + savedlod = dob->ob->currentlod; + +#ifdef WITH_GAMEENGINE + if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { + BKE_object_lod_update(dob->ob, rv3d->viewinv[3]); + } +#endif + + /* extra service: draw the duplicator in drawtype of parent, minimum taken + * to allow e.g. boundbox box objects in groups for LOD */ + dt = tbase.object->dt; + tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); + + /* inherit draw extra, but not if a boundbox under the assumption that this + * is intended to speed up drawing, and drawing extra (especially wire) can + * slow it down too much */ + dtx = tbase.object->dtx; + if (tbase.object->dt != OB_BOUNDBOX) + tbase.object->dtx = base->object->dtx; + + /* negative scale flag has to propagate */ + transflag = tbase.object->transflag; + + if (is_negative_m4(dob->mat)) + tbase.object->transflag |= OB_NEG_SCALE; + else + tbase.object->transflag &= ~OB_NEG_SCALE; + + /* should move outside the loop but possible color is set in draw_object still */ + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(color_rgb); + } + + /* generate displist, test for new object */ + if (dob_prev && dob_prev->ob != dob->ob) { + if (use_displist == true) + glDeleteLists(displist, 1); + + use_displist = false; + } + + if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) { + bb = *bb_tmp; /* must make a copy */ + testbb = true; + } + + if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) { + /* generate displist */ + if (use_displist == false) { + + /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP) + * however this is very slow, it was probably needed for the NLA + * offset feature (used in group-duplicate.blend but no longer works in 2.5) + * so for now it should be ok to - campbell */ + + if ( /* if this is the last no need to make a displist */ + (dob_next == NULL || dob_next->ob != dob->ob) || + /* lamp drawing messes with matrices, could be handled smarter... but this works */ + (dob->ob->type == OB_LAMP) || + (dob->type == OB_DUPLIGROUP && dob->animated) || + !bb_tmp || + draw_glsl_material(scene, dob->ob, v3d, dt) || + check_object_draw_texture(scene, v3d, dt) || + (v3d->flag2 & V3D_SOLID_MATCAP) != 0) + { + // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2); + use_displist = false; + } + else { + // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2); + + /* disable boundbox check for list creation */ + BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1); + /* need this for next part of code */ + unit_m4(dob->ob->obmat); /* obmat gets restored */ + + displist = glGenLists(1); + glNewList(displist, GL_COMPILE); + draw_object(scene, ar, v3d, &tbase, dflag_dupli); + glEndList(); + + use_displist = true; + BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0); + } + } + + if (use_displist) { + glPushMatrix(); + glMultMatrixf(dob->mat); + glCallList(displist); + glPopMatrix(); + } + else { + copy_m4_m4(dob->ob->obmat, dob->mat); + GPU_begin_dupli_object(dob); + draw_object(scene, ar, v3d, &tbase, dflag_dupli); + GPU_end_dupli_object(); + } + } + + tbase.object->dt = dt; + tbase.object->dtx = dtx; + tbase.object->transflag = transflag; + tbase.object->currentlod = savedlod; + } + + if (apply_data) { + duplilist_restore(lb, apply_data); + duplilist_free_apply_data(apply_data); + } + + free_object_duplilist(lb); + + if (use_displist) + glDeleteLists(displist, 1); +} + +void draw_dupli_objects(Scene *scene, ARegion *ar, View3D *v3d, Base *base) +{ + /* define the color here so draw_dupli_objects_color can be called + * from the set loop */ + + int color = (base->flag & SELECT) ? TH_SELECT : TH_WIRE; + /* debug */ + if (base->object->dup_group && base->object->dup_group->id.us < 1) + color = TH_REDALERT; + + draw_dupli_objects_color(scene, ar, v3d, base, 0, color); +} + +/* XXX warning, not using gpu offscreen here */ +void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect) +{ + /* clamp rect by region */ + rcti r = { + .xmin = 0, + .xmax = ar->winx - 1, + .ymin = 0, + .ymax = ar->winy - 1 + }; + + /* Constrain rect to depth bounds */ + BLI_rcti_isect(&r, rect, rect); + + /* assign values to compare with the ViewDepths */ + int x = rect->xmin; + int y = rect->ymin; + + int w = BLI_rcti_size_x(rect); + int h = BLI_rcti_size_y(rect); + + if (w <= 0 || h <= 0) { + if (d->depths) + MEM_freeN(d->depths); + d->depths = NULL; + + d->damaged = false; + } + else if (d->w != w || + d->h != h || + d->x != x || + d->y != y || + d->depths == NULL + ) + { + d->x = x; + d->y = y; + d->w = w; + d->h = h; + + if (d->depths) + MEM_freeN(d->depths); + + d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset"); + + d->damaged = true; + } + + if (d->damaged) { + /* XXX using special function here, it doesn't use the gpu offscreen system */ + view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); + glGetDoublev(GL_DEPTH_RANGE, d->depth_range); + d->damaged = false; + } +} + +/* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */ +void ED_view3d_depth_update(ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + + /* Create storage for, and, if necessary, copy depth buffer */ + if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths"); + if (rv3d->depths) { + ViewDepths *d = rv3d->depths; + if (d->w != ar->winx || + d->h != ar->winy || + !d->depths) + { + d->w = ar->winx; + d->h = ar->winy; + if (d->depths) + MEM_freeN(d->depths); + d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths"); + d->damaged = true; + } + + if (d->damaged) { + view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); + glGetDoublev(GL_DEPTH_RANGE, d->depth_range); + + d->damaged = false; + } + } +} + +/* utility function to find the closest Z value, use for autodepth */ +float view3d_depth_near(ViewDepths *d) +{ + /* convert to float for comparisons */ + const float near = (float)d->depth_range[0]; + const float far_real = (float)d->depth_range[1]; + float far = far_real; + + const float *depths = d->depths; + float depth = FLT_MAX; + int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */ + + /* far is both the starting 'far' value + * and the closest value found. */ + while (i--) { + depth = *depths++; + if ((depth < far) && (depth > near)) { + far = depth; + } + } + + return far == far_real ? FLT_MAX : far; +} + +void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d) +{ + short zbuf = v3d->zbuf; + RegionView3D *rv3d = ar->regiondata; + + view3d_winmatrix_set(ar, v3d, NULL); + view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ + + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + invert_m4_m4(rv3d->persinv, rv3d->persmat); + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + + glClear(GL_DEPTH_BUFFER_BIT); + + glLoadMatrixf(rv3d->viewmat); + + v3d->zbuf = true; + glEnable(GL_DEPTH_TEST); + + if (v3d->flag2 & V3D_SHOW_GPENCIL) { + ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true); + } + + v3d->zbuf = zbuf; +} + +void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride) +{ + RegionView3D *rv3d = ar->regiondata; + Base *base; + short zbuf = v3d->zbuf; + short flag = v3d->flag; + float glalphaclip = U.glalphaclip; + int obcenter_dia = U.obcenter_dia; + /* no need for color when drawing depth buffer */ + const short dflag_depth = DRAW_CONSTCOLOR; + /* temp set drawtype to solid */ + + /* Setting these temporarily is not nice */ + v3d->flag &= ~V3D_SELECT_OUTLINE; + U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */ + U.obcenter_dia = 0; + + view3d_winmatrix_set(ar, v3d, NULL); + view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ + + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + invert_m4_m4(rv3d->persinv, rv3d->persmat); + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + + glClear(GL_DEPTH_BUFFER_BIT); + + glLoadMatrixf(rv3d->viewmat); + + if (rv3d->rflag & RV3D_CLIPPING) { + ED_view3d_clipping_set(rv3d); + } + /* get surface depth without bias */ + rv3d->rflag |= RV3D_ZOFFSET_DISABLED; + + v3d->zbuf = true; + glEnable(GL_DEPTH_TEST); + + /* draw set first */ + if (scene->set) { + Scene *sce_iter; + for (SETLOOPER(scene->set, sce_iter, base)) { + if (v3d->lay & base->lay) { + draw_object(scene, ar, v3d, base, 0); + if (base->object->transflag & OB_DUPLI) { + draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED); + } + } + } + } + + for (base = scene->base.first; base; base = base->next) { + if (v3d->lay & base->lay) { + /* dupli drawing */ + if (base->object->transflag & OB_DUPLI) { + draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED); + } + draw_object(scene, ar, v3d, base, dflag_depth); + } + } + + /* this isn't that nice, draw xray objects as if they are normal */ + if (v3d->afterdraw_transp.first || + v3d->afterdraw_xray.first || + v3d->afterdraw_xraytransp.first) + { + View3DAfter *v3da; + int mask_orig; + + v3d->xray = true; + + /* transp materials can change the depth mask, see #21388 */ + glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); + + + if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) { + glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */ + for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) { + draw_object(scene, ar, v3d, v3da->base, dflag_depth); + } + glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */ + } + + /* draw 3 passes, transp/xray/xraytransp */ + v3d->xray = false; + v3d->transp = true; + while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { + draw_object(scene, ar, v3d, v3da->base, dflag_depth); + MEM_freeN(v3da); + } + + v3d->xray = true; + v3d->transp = false; + while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { + draw_object(scene, ar, v3d, v3da->base, dflag_depth); + MEM_freeN(v3da); + } + + v3d->xray = true; + v3d->transp = true; + while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { + draw_object(scene, ar, v3d, v3da->base, dflag_depth); + MEM_freeN(v3da); + } + + + v3d->xray = false; + v3d->transp = false; + + glDepthMask(mask_orig); + } + + if (rv3d->rflag & RV3D_CLIPPING) { + ED_view3d_clipping_disable(); + } + rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; + + v3d->zbuf = zbuf; + if (!v3d->zbuf) glDisable(GL_DEPTH_TEST); + + U.glalphaclip = glalphaclip; + v3d->flag = flag; + U.obcenter_dia = obcenter_dia; +} + +typedef struct View3DShadow { + struct View3DShadow *next, *prev; + GPULamp *lamp; +} View3DShadow; + +static void gpu_render_lamp_update(Scene *scene, View3D *v3d, + Object *ob, Object *par, + float obmat[4][4], unsigned int lay, + ListBase *shadows, SceneRenderLayer *srl) +{ + GPULamp *lamp = GPU_lamp_from_blender(scene, ob, par); + + if (lamp) { + Lamp *la = (Lamp *)ob->data; + + GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat); + GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy); + + unsigned int layers = lay & v3d->lay; + if (srl) + layers &= srl->lay; + + if (layers && + GPU_lamp_has_shadow_buffer(lamp) && + /* keep last, may do string lookup */ + GPU_lamp_override_visible(lamp, srl, NULL)) + { + View3DShadow *shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow"); + shadow->lamp = lamp; + BLI_addtail(shadows, shadow); + } + } +} + +static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d) +{ + ListBase shadows; + Scene *sce_iter; + Base *base; + World *world = scene->world; + SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL; + + BLI_listbase_clear(&shadows); + + /* update lamp transform and gather shadow lamps */ + for (SETLOOPER(scene, sce_iter, base)) { + Object *ob = base->object; + + if (ob->type == OB_LAMP) + gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, ob->lay, &shadows, srl); + + if (ob->transflag & OB_DUPLI) { + DupliObject *dob; + ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob); + + for (dob = lb->first; dob; dob = dob->next) + if (dob->ob->type == OB_LAMP) + gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, ob->lay, &shadows, srl); + + free_object_duplilist(lb); + } + } + + /* render shadows after updating all lamps, nested object_duplilist + * don't work correct since it's replacing object matrices */ + for (View3DShadow *shadow = shadows.first; shadow; shadow = shadow->next) { + /* this needs to be done better .. */ + float viewmat[4][4], winmat[4][4]; + ARegion ar = {NULL}; + RegionView3D rv3d = {{{0}}}; + + int drawtype = v3d->drawtype; + int lay = v3d->lay; + int flag2 = v3d->flag2; + + v3d->drawtype = OB_SOLID; + v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp); + v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP); + v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW; + + int winsize; + GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat); + + ar.regiondata = &rv3d; + ar.regiontype = RGN_TYPE_WINDOW; + rv3d.persp = RV3D_CAMOB; + copy_m4_m4(rv3d.winmat, winmat); + copy_m4_m4(rv3d.viewmat, viewmat); + invert_m4_m4(rv3d.viewinv, rv3d.viewmat); + mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); + invert_m4_m4(rv3d.persinv, rv3d.viewinv); + + /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */ + ED_view3d_draw_offscreen( + scene, v3d, &ar, winsize, winsize, viewmat, winmat, + false, false, true, + NULL, NULL, NULL, NULL); + GPU_lamp_shadow_buffer_unbind(shadow->lamp); + + v3d->drawtype = drawtype; + v3d->lay = lay; + v3d->flag2 = flag2; + } + + BLI_freelistN(&shadows); + + /* update world values */ + if (world) { + GPU_mist_update_enable(world->mode & WO_MIST); + GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr); + GPU_horizon_update_color(&world->horr); + GPU_ambient_update_color(&world->ambr); + GPU_zenith_update_color(&world->zenr); + } +} + +/* *********************** customdata **************** */ + +CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d) +{ + CustomDataMask mask = 0; + const int drawtype = view3d_effective_drawtype(v3d); + + if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) || + ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) + { + mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; + + if (BKE_scene_use_new_shading_nodes(scene)) { + if (drawtype == OB_MATERIAL) + mask |= CD_MASK_ORCO; + } + else { + if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) || + (drawtype == OB_MATERIAL)) + { + mask |= CD_MASK_ORCO; + } + } + } + + return mask; +} + +/* goes over all modes and view3d settings */ +CustomDataMask ED_view3d_screen_datamask(const bScreen *screen) +{ + const Scene *scene = screen->scene; + CustomDataMask mask = CD_MASK_BAREMESH; + + /* check if we need tfaces & mcols due to view mode */ + for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + if (sa->spacetype == SPACE_VIEW3D) { + mask |= ED_view3d_datamask(scene, sa->spacedata.first); + } + } + + return mask; +} + +/** + * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects + * + * \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set. + * \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here. + */ +static void view3d_draw_objects( + const bContext *C, + Scene *scene, View3D *v3d, ARegion *ar, + const char **grid_unit, + const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) +{ + RegionView3D *rv3d = ar->regiondata; + Base *base; + const bool do_camera_frame = !draw_offscreen; + const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; + const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); + /* only draw grids after in solid modes, else it hovers over mesh wires */ + const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx; + bool do_composite_xray = false; + bool xrayclear = true; + + if (!draw_offscreen) { + ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); + } + + if (rv3d->rflag & RV3D_CLIPPING) + view3d_draw_clipping(rv3d); + + /* set zbuffer after we draw clipping region */ + v3d->zbuf = VP_legacy_use_depth(scene, v3d); + + if (v3d->zbuf) { + glEnable(GL_DEPTH_TEST); + } + + /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override + * objects if done last */ + if (draw_grids) { + /* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */ + rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit); + + if (!draw_floor) { + ED_region_pixelspace(ar); + *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ + VP_legacy_drawgrid(&scene->unit, ar, v3d, grid_unit); + /* XXX make function? replaces persp(1) */ + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(rv3d->winmat); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(rv3d->viewmat); + } + else if (!draw_grids_after) { + VP_legacy_drawfloor(scene, v3d, grid_unit, true); + } + } + + /* important to do before clipping */ + if (do_bgpic) { + view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame); + } + + if (rv3d->rflag & RV3D_CLIPPING) { + ED_view3d_clipping_set(rv3d); + } + + /* draw set first */ + if (scene->set) { + const short dflag = DRAW_CONSTCOLOR | DRAW_SCENESET; + Scene *sce_iter; + for (SETLOOPER(scene->set, sce_iter, base)) { + if (v3d->lay & base->lay) { + UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f); + draw_object(scene, ar, v3d, base, dflag); + + if (base->object->transflag & OB_DUPLI) { + draw_dupli_objects_color(scene, ar, v3d, base, dflag, TH_UNDEFINED); + } + } + } + + /* Transp and X-ray afterdraw stuff for sets is done later */ + } + + if (draw_offscreen) { + for (base = scene->base.first; base; base = base->next) { + if (v3d->lay & base->lay) { + /* dupli drawing */ + if (base->object->transflag & OB_DUPLI) + draw_dupli_objects(scene, ar, v3d, base); + + draw_object(scene, ar, v3d, base, 0); + } + } + } + else { + unsigned int lay_used = 0; + + /* then draw not selected and the duplis, but skip editmode object */ + for (base = scene->base.first; base; base = base->next) { + lay_used |= base->lay; + + if (v3d->lay & base->lay) { + + /* dupli drawing */ + if (base->object->transflag & OB_DUPLI) { + draw_dupli_objects(scene, ar, v3d, base); + } + if ((base->flag & SELECT) == 0) { + if (base->object != scene->obedit) + draw_object(scene, ar, v3d, base, 0); + } + } + } + + /* mask out localview */ + v3d->lay_used = lay_used & ((1 << 20) - 1); + + /* draw selected and editmode */ + for (base = scene->base.first; base; base = base->next) { + if (v3d->lay & base->lay) { + if (base->object == scene->obedit || (base->flag & SELECT)) { + draw_object(scene, ar, v3d, base, 0); + } + } + } + } + + /* perspective floor goes last to use scene depth and avoid writing to depth buffer */ + if (draw_grids_after) { + VP_legacy_drawfloor(scene, v3d, grid_unit, false); + } + + /* must be before xray draw which clears the depth buffer */ + if (v3d->flag2 & V3D_SHOW_GPENCIL) { + wmWindowManager *wm = (C != NULL) ? CTX_wm_manager(C) : NULL; + + /* must be before xray draw which clears the depth buffer */ + if (v3d->zbuf) glDisable(GL_DEPTH_TEST); + ED_gpencil_draw_view3d(wm, scene, v3d, ar, true); + if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + } + + /* transp and X-ray afterdraw stuff */ + if (v3d->afterdraw_transp.first) view3d_draw_transp(scene, ar, v3d); + + /* always do that here to cleanup depth buffers if none needed */ + if (fx) { + do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first); + GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray); + } + + if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, &xrayclear); + if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, xrayclear); + + if (fx && do_composite_xray) { + GPU_fx_compositor_XRay_resolve(fx); + } + + if (!draw_offscreen) { + ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); + } + + if (rv3d->rflag & RV3D_CLIPPING) + ED_view3d_clipping_disable(); + + /* important to do after clipping */ + if (do_bgpic) { + view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame); + } + + if (!draw_offscreen) { + BIF_draw_manipulator(C); + } + + /* cleanup */ + if (v3d->zbuf) { + v3d->zbuf = false; + glDisable(GL_DEPTH_TEST); + } + + if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { + GPU_free_images_old(); + } +} + +/** + * Store values from #RegionView3D, set when drawing. + * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example). + * + * Values set by #ED_view3d_update_viewmat should be handled here. + */ +struct RV3DMatrixStore { + float winmat[4][4]; + float viewmat[4][4]; + float viewinv[4][4]; + float persmat[4][4]; + float persinv[4][4]; + float viewcamtexcofac[4]; + float pixsize; +}; + +void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d) +{ + struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__); + copy_m4_m4(rv3dmat->winmat, rv3d->winmat); + copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat); + copy_m4_m4(rv3dmat->persmat, rv3d->persmat); + copy_m4_m4(rv3dmat->persinv, rv3d->persinv); + copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv); + copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac); + rv3dmat->pixsize = rv3d->pixsize; + return (void *)rv3dmat; +} + +void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt) +{ + struct RV3DMatrixStore *rv3dmat = rv3dmat_pt; + copy_m4_m4(rv3d->winmat, rv3dmat->winmat); + copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat); + copy_m4_m4(rv3d->persmat, rv3dmat->persmat); + copy_m4_m4(rv3d->persinv, rv3dmat->persinv); + copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv); + copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac); + rv3d->pixsize = rv3dmat->pixsize; +} + +void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d) +{ + /* shadow buffers, before we setup matrices */ + if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) + gpu_update_lamps_shadows_world(scene, v3d); +} + +/* + * Function to clear the view + */ +static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) +{ + if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) { + VP_view3d_draw_background_world(scene, v3d, ar->regiondata); + } + else { + VP_view3d_draw_background_none(); + } +} + +/* ED_view3d_draw_offscreen_init should be called before this to initialize + * stuff like shadow buffers + */ +void ED_view3d_draw_offscreen( + Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy, + float viewmat[4][4], float winmat[4][4], + bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, + GPUFX *fx, GPUFXSettings *fx_settings, + GPUOffScreen *ofs) +{ + bool do_compositing = false; + RegionView3D *rv3d = ar->regiondata; + + glPushMatrix(); + + /* set temporary new size */ + int bwinx = ar->winx; + int bwiny = ar->winy; + rcti brect = ar->winrct; + + ar->winx = winx; + ar->winy = winy; + ar->winrct.xmin = 0; + ar->winrct.ymin = 0; + ar->winrct.xmax = winx; + ar->winrct.ymax = winy; + + struct bThemeState theme_state; + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + + /* set flags */ + G.f |= G_RENDER_OGL; + + if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { + /* free images which can have changed on frame-change + * warning! can be slow so only free animated images - campbell */ + GPU_free_images_anim(); + } + + /* setup view matrices before fx or unbinding the offscreen buffers will cause issues */ + if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera) + view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname); + else + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); + + /* framebuffer fx needed, we need to draw offscreen first */ + if (v3d->fx_settings.fx_flag && fx) { + GPUSSAOSettings *ssao = NULL; + + if (v3d->drawtype < OB_SOLID) { + ssao = v3d->fx_settings.ssao; + v3d->fx_settings.ssao = NULL; + } + + do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings); + + if (ssao) + v3d->fx_settings.ssao = ssao; + } + + /* clear opengl buffers */ + if (do_sky) { + view3d_main_region_clear(scene, v3d, ar); + } + else { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + /* main drawing call */ + view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL); + + /* post process */ + if (do_compositing) { + if (!winmat) + is_persp = rv3d->is_persp; + GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs); + } + + if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { + /* draw grease-pencil stuff */ + ED_region_pixelspace(ar); + + + if (v3d->flag2 & V3D_SHOW_GPENCIL) { + /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ + ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false); + } + + /* freeing the images again here could be done after the operator runs, leaving for now */ + GPU_free_images_anim(); + } + + /* restore size */ + ar->winx = bwinx; + ar->winy = bwiny; + ar->winrct = brect; + + glPopMatrix(); + + UI_Theme_Restore(&theme_state); + + G.f &= ~G_RENDER_OGL; +} + +/** + * Utility func for ED_view3d_draw_offscreen + * + * \param ofs: Optional off-screen buffer, can be NULL. + * (avoids re-creating when doing multiple GL renders). + */ +ImBuf *ED_view3d_draw_offscreen_imbuf( + Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, + unsigned int flag, bool draw_background, + int alpha_mode, int samples, bool full_samples, const char *viewname, + /* output vars */ + GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) +{ + RegionView3D *rv3d = ar->regiondata; + const bool draw_sky = (alpha_mode == R_ADDSKY); + + /* view state */ + GPUFXSettings fx_settings = v3d->fx_settings; + bool is_ortho = false; + float winmat[4][4]; + + if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) { + /* sizes differ, can't reuse */ + ofs = NULL; + } + + const bool own_ofs = (ofs == NULL); + + if (own_ofs) { + /* bind */ + ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); + if (ofs == NULL) { + return NULL; + } + } + + ED_view3d_draw_offscreen_init(scene, v3d); + + GPU_offscreen_bind(ofs, true); + + /* read in pixels & stamp */ + ImBuf *ibuf = IMB_allocImBuf(sizex, sizey, 32, flag); + + /* render 3d view */ + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + CameraParams params; + Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); + + BKE_camera_params_init(¶ms); + /* fallback for non camera objects */ + params.clipsta = v3d->near; + params.clipend = v3d->far; + BKE_camera_params_from_object(¶ms, camera); + BKE_camera_multiview_params(&scene->r, ¶ms, camera, viewname); + BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp); + BKE_camera_params_compute_matrix(¶ms); + + BKE_camera_to_gpu_dof(camera, &fx_settings); + + is_ortho = params.is_ortho; + copy_m4_m4(winmat, params.winmat); + } + else { + rctf viewplane; + float clipsta, clipend; + + is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); + if (is_ortho) { + orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); + } + else { + perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); + } + } + + if ((samples && full_samples) == 0) { + /* Single-pass render, common case */ + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat, + draw_background, draw_sky, !is_ortho, viewname, + fx, &fx_settings, ofs); + + if (ibuf->rect_float) { + GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); + } + else if (ibuf->rect) { + GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect); + } + } + else { + /* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling. + * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ + static float jit_ofs[32][2]; + float winmat_jitter[4][4]; + /* use imbuf as temp storage, before writing into it from accumulation buffer */ + unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float; + unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1"); + + BLI_jitter_init(jit_ofs, samples); + + /* first sample buffer, also initializes 'rv3d->persmat' */ + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat, + draw_background, draw_sky, !is_ortho, viewname, + fx, &fx_settings, ofs); + GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); + + unsigned i = sizex * sizey * 4; + while (i--) { + accum_buffer[i] = rect_temp[i]; + } + + /* skip the first sample */ + for (int j = 1; j < samples; j++) { + copy_m4_m4(winmat_jitter, winmat); + window_translate_m4( + winmat_jitter, rv3d->persmat, + (jit_ofs[j][0] * 2.0f) / sizex, + (jit_ofs[j][1] * 2.0f) / sizey); + + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, + draw_background, draw_sky, !is_ortho, viewname, + fx, &fx_settings, ofs); + GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); + + i = sizex * sizey * 4; + while (i--) { + accum_buffer[i] += rect_temp[i]; + } + } + + if (ibuf->rect_float) { + float *rect_float = ibuf->rect_float; + i = sizex * sizey * 4; + while (i--) { + rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f); + } + } + else { + unsigned char *rect_ub = (unsigned char *)ibuf->rect; + i = sizex * sizey * 4; + while (i--) { + rect_ub[i] = accum_buffer[i] / samples; + } + } + + MEM_freeN(accum_buffer); + } + + /* unbind */ + GPU_offscreen_unbind(ofs, true); + + if (own_ofs) { + GPU_offscreen_free(ofs); + } + + if (ibuf->rect_float && ibuf->rect) + IMB_rect_from_float(ibuf); + + return ibuf; +} + +/** + * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf) + * + * \param ofs: Optional off-screen buffer can be NULL. + * (avoids re-creating when doing multiple GL renders). + * + * \note used by the sequencer + */ +ImBuf *ED_view3d_draw_offscreen_imbuf_simple( + Scene *scene, Object *camera, int width, int height, + unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background, + int alpha_mode, int samples, bool full_samples, const char *viewname, + GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) +{ + View3D v3d = {NULL}; + ARegion ar = {NULL}; + RegionView3D rv3d = {{{0}}}; + + /* connect data */ + v3d.regionbase.first = v3d.regionbase.last = &ar; + ar.regiondata = &rv3d; + ar.regiontype = RGN_TYPE_WINDOW; + + v3d.camera = camera; + v3d.lay = scene->lay; + v3d.drawtype = drawtype; + v3d.flag2 = V3D_RENDER_OVERRIDE; + + if (use_gpencil) + v3d.flag2 |= V3D_SHOW_GPENCIL; + + if (use_solid_tex) + v3d.flag2 |= V3D_SOLID_TEX; + + if (draw_background) + v3d.flag3 |= V3D_SHOW_WORLD; + + rv3d.persp = RV3D_CAMOB; + + copy_m4_m4(rv3d.viewinv, v3d.camera->obmat); + normalize_m4(rv3d.viewinv); + invert_m4_m4(rv3d.viewmat, rv3d.viewinv); + + { + CameraParams params; + Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname); + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, view_camera); + BKE_camera_multiview_params(&scene->r, ¶ms, view_camera, viewname); + BKE_camera_params_compute_viewplane(¶ms, width, height, scene->r.xasp, scene->r.yasp); + BKE_camera_params_compute_matrix(¶ms); + + copy_m4_m4(rv3d.winmat, params.winmat); + v3d.near = params.clipsta; + v3d.far = params.clipend; + v3d.lens = params.lens; + } + + mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); + invert_m4_m4(rv3d.persinv, rv3d.viewinv); + + return ED_view3d_draw_offscreen_imbuf( + scene, &v3d, &ar, width, height, flag, + draw_background, alpha_mode, samples, full_samples, viewname, + fx, ofs, err_out); +} + + +/** + * \note The info that this uses is updated in #ED_refresh_viewport_fps, + * which currently gets called during #SCREEN_OT_animation_step. + */ +void ED_scene_draw_fps(Scene *scene, const rcti *rect) +{ + ScreenFrameRateInfo *fpsi = scene->fps_info; + char printable[16]; + + if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) + return; + + printable[0] = '\0'; + +#if 0 + /* this is too simple, better do an average */ + fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)) +#else + fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)); + + float fps = 0.0f; + int tot = 0; + for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) { + if (fpsi->redrawtimes_fps[i]) { + fps += fpsi->redrawtimes_fps[i]; + tot++; + } + } + if (tot) { + fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE; + + //fpsi->redrawtime_index++; + //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE) + // fpsi->redrawtime = 0; + + fps = fps / tot; + } +#endif + + /* is this more than half a frame behind? */ + if (fps + 0.5f < (float)(FPS)) { + UI_ThemeColor(TH_REDALERT); + BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps); + } + else { + UI_ThemeColor(TH_TEXT_HI); + BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f)); + } + +#ifdef WITH_INTERNATIONAL + BLF_draw_default(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); +#else + BLF_draw_default_ascii(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); +#endif +} + +static bool view3d_main_region_do_render_draw(Scene *scene) +{ + RenderEngineType *type = RE_engines_find(scene->r.engine); + + return (type && type->view_update && type->view_draw); +} + +bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *rect) +{ + RegionView3D *rv3d = ar->regiondata; + bool use_border; + + /* test if there is a 3d view rendering */ + if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene)) + return false; + + /* test if there is a border render */ + if (rv3d->persp == RV3D_CAMOB) + use_border = (scene->r.mode & R_BORDER) != 0; + else + use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0; + + if (!use_border) + return false; + + /* compute border */ + if (rv3d->persp == RV3D_CAMOB) { + rctf viewborder; + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + + rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); + rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); + rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder); + rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder); + } + else { + rect->xmin = v3d->render_border.xmin * ar->winx; + rect->xmax = v3d->render_border.xmax * ar->winx; + rect->ymin = v3d->render_border.ymin * ar->winy; + rect->ymax = v3d->render_border.ymax * ar->winy; + } + + BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin); + BLI_rcti_isect(&ar->winrct, rect, rect); + + return true; +} + +/** + * IMPORTANT: this is deprecated, any changes made in this function should + * be mirrored in view3d_draw_render_draw() in view3d_draw.c + */ +static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene, + ARegion *ar, View3D *v3d, + bool clip_border, const rcti *border_rect) +{ + RegionView3D *rv3d = ar->regiondata; + RenderEngineType *type; + GLint scissor[4]; + + /* create render engine */ + if (!rv3d->render_engine) { + RenderEngine *engine; + + type = RE_engines_find(scene->r.engine); + + if (!(type->view_update && type->view_draw)) + return false; + + engine = RE_engine_create_ex(type, true); + + engine->tile_x = scene->r.tilex; + engine->tile_y = scene->r.tiley; + + type->view_update(engine, C); + + rv3d->render_engine = engine; + } + + /* setup view matrices */ + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); + + /* background draw */ + ED_region_pixelspace(ar); + + if (clip_border) { + /* for border draw, we only need to clear a subset of the 3d view */ + if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) { + glGetIntegerv(GL_SCISSOR_BOX, scissor); + glScissor(border_rect->xmin, border_rect->ymin, + BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect)); + } + else { + return false; + } + } + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (v3d->flag & V3D_DISPBGPICS) + view3d_draw_bgpic_test(scene, ar, v3d, false, true); + else + fdrawcheckerboard(0, 0, ar->winx, ar->winy); + + /* render result draw */ + type = rv3d->render_engine->type; + type->view_draw(rv3d->render_engine, C); + + if (v3d->flag & V3D_DISPBGPICS) + view3d_draw_bgpic_test(scene, ar, v3d, true, true); + + if (clip_border) { + /* restore scissor as it was before */ + glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); + } + + return true; +} + +static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border) +{ + float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f}; + + if (!rv3d->render_engine || !rv3d->render_engine->text[0]) + return; + + if (render_border) { + /* draw darkened background color. no alpha because border render does + * partial redraw and will not redraw the region behind this info bar */ + float alpha = 1.0f - fill_color[3]; + Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); + + if (camera) { + if (camera->flag & CAM_SHOWPASSEPARTOUT) { + alpha *= (1.0f - camera->passepartalpha); + } + } + + UI_GetThemeColor3fv(TH_HIGH_GRAD, fill_color); + mul_v3_fl(fill_color, alpha); + fill_color[3] = 1.0f; + } + + ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true); +} + +static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, + float winmat[4][4], const char *viewname) +{ + /* update the viewport matrices with the new camera */ + if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { + float viewmat[4][4]; + const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); + + BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); + } + else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ + float viewmat[4][4]; + Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); + + BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); + } +} + +#ifdef WITH_GAMEENGINE +static void update_lods(Scene *scene, float camera_pos[3]) +{ + Scene *sce_iter; + Base *base; + + for (SETLOOPER(scene, sce_iter, base)) { + Object *ob = base->object; + BKE_object_lod_update(ob, camera_pos); + } +} +#endif + +static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d, + ARegion *ar, const char **grid_unit) +{ + wmWindow *win = CTX_wm_window(C); + RegionView3D *rv3d = ar->regiondata; + unsigned int lay_used = v3d->lay_used; + + /* post processing */ + bool do_compositing = false; + + /* shadow buffers, before we setup matrices */ + if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) + gpu_update_lamps_shadows_world(scene, v3d); + + /* reset default OpenGL lights if needed (i.e. after preferences have been altered) */ + if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) { + rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE; + GPU_default_lights(); + } + + /* setup the view matrix */ + if (VP_legacy_view3d_stereo3d_active(C, scene, v3d, rv3d)) + VP_legacy_view3d_stereo3d_setup(scene, v3d, ar); + else + VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); + + rv3d->rflag &= ~RV3D_IS_GAME_ENGINE; +#ifdef WITH_GAMEENGINE + if (STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)) { + rv3d->rflag |= RV3D_IS_GAME_ENGINE; + + /* Make sure LoDs are up to date */ + update_lods(scene, rv3d->viewinv[3]); + } +#endif + + /* framebuffer fx needed, we need to draw offscreen first */ + if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) { + BKE_screen_gpu_fx_validate(&v3d->fx_settings); + GPUFXSettings fx_settings = v3d->fx_settings; + if (!rv3d->compositor) + rv3d->compositor = GPU_fx_compositor_create(); + + if (rv3d->persp == RV3D_CAMOB && v3d->camera) + BKE_camera_to_gpu_dof(v3d->camera, &fx_settings); + else { + fx_settings.dof = NULL; + } + + do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings); + } + + /* clear the background */ + view3d_main_region_clear(scene, v3d, ar); + + /* enables anti-aliasing for 3D view drawing */ + if (win->multisamples != USER_MULTISAMPLE_NONE) { + glEnable(GL_MULTISAMPLE); + } + + /* main drawing call */ + view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); + + /* post process */ + if (do_compositing) { + GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL); + } + + /* Disable back anti-aliasing */ + if (win->multisamples != USER_MULTISAMPLE_NONE) { + glDisable(GL_MULTISAMPLE); + } + + if (v3d->lay_used != lay_used) { /* happens when loading old files or loading with UI load */ + /* find header and force tag redraw */ + ScrArea *sa = CTX_wm_area(C); + ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); + ED_region_tag_redraw(ar_header); /* can be NULL */ + } + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + BDR_drawSketch(C); + } +} + +static void view3d_main_region_draw_info(const bContext *C, Scene *scene, + ARegion *ar, View3D *v3d, + const char *grid_unit, bool render_border) +{ + wmWindowManager *wm = CTX_wm_manager(C); + RegionView3D *rv3d = ar->regiondata; + rcti rect; + + /* local coordinate visible rect inside region, to accomodate overlapping ui */ + ED_region_visible_rect(ar, &rect); + + if (rv3d->persp == RV3D_CAMOB) { + VP_drawviewborder(scene, ar, v3d); + } + else if (v3d->flag2 & V3D_RENDER_BORDER) { + VP_drawrenderborder(ar, v3d); + } + + if (v3d->flag2 & V3D_SHOW_GPENCIL) { + /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ + ED_gpencil_draw_view3d(wm, scene, v3d, ar, false); + } + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + VP_legacy_drawcursor(scene, ar, v3d); /* 3D cursor */ + + if (U.uiflag & USER_SHOW_ROTVIEWICON) + VP_legacy_draw_view_axis(rv3d, &rect); + else + draw_view_icon(rv3d, &rect); + + if (U.uiflag & USER_DRAWVIEWINFO) { + Object *ob = OBACT; + draw_selected_name(scene, ob, &rect); + } + } + + if (rv3d->render_engine) { + view3d_main_region_draw_engine_info(v3d, rv3d, ar, render_border); + return; + } + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { + ED_scene_draw_fps(scene, &rect); + } + else if (U.uiflag & USER_SHOW_VIEWPORTNAME) { + draw_viewport_name(ar, v3d, &rect); + } + + if (grid_unit) { /* draw below the viewport name */ + char numstr[32] = ""; + + UI_ThemeColor(TH_TEXT_HI); + if (v3d->grid != 1.0f) { + BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); + } + + BLF_draw_default_ascii(rect.xmin + U.widget_unit, + rect.ymax - (USER_SHOW_VIEWPORTNAME ? 2 * U.widget_unit : U.widget_unit), 0.0f, + numstr[0] ? numstr : grid_unit, sizeof(numstr)); + } + } +} + +void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar) +{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + const char *grid_unit = NULL; + rcti border_rect; + + /* if we only redraw render border area, skip opengl draw and also + * don't do scissor because it's already set */ + bool render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect); + bool clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); + + /* draw viewport using opengl */ + if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) { + view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit); + + if (G.debug & G_DEBUG_SIMDATA) + draw_sim_debug_data(scene, v3d, ar); + + ED_region_pixelspace(ar); + } + + /* draw viewport using external renderer */ + if (v3d->drawtype == OB_RENDER) + view3d_main_region_draw_engine(C, scene, ar, v3d, clip_border, &border_rect); + + view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); + + v3d->flag |= V3D_INVALID_BACKBUF; + + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp)); + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray)); + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp)); +} diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 04a6aa215f4..b42afd3a7a9 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -56,6 +56,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_immediate.h" + #include "view3d_intern.h" /* own include */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -257,36 +259,45 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), x2 = xoff + 0.55f * fly->width; y2 = yoff + 0.55f * fly->height; - UI_ThemeColor(TH_VIEW_OVERLAY); - glBegin(GL_LINES); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_VIEW_OVERLAY); + + immBegin(GL_LINES, 16); + /* bottom left */ - glVertex2f(x1, y1); - glVertex2f(x1, y1 + 5); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y1 + 5); - glVertex2f(x1, y1); - glVertex2f(x1 + 5, y1); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1 + 5, y1); /* top right */ - glVertex2f(x2, y2); - glVertex2f(x2, y2 - 5); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y2 - 5); - glVertex2f(x2, y2); - glVertex2f(x2 - 5, y2); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2 - 5, y2); /* top left */ - glVertex2f(x1, y2); - glVertex2f(x1, y2 - 5); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x1, y2 - 5); - glVertex2f(x1, y2); - glVertex2f(x1 + 5, y2); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x1 + 5, y2); /* bottom right */ - glVertex2f(x2, y1); - glVertex2f(x2, y1 + 5); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y1 + 5); + + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2 - 5, y1); - glVertex2f(x2, y1); - glVertex2f(x2 - 5, y1); - glEnd(); + immEnd(); + immUnbindProgram(); } static void fly_update_header(bContext *C, wmOperator *op, FlyInfo *fly) diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 0713377d210..ab0cae6822b 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -334,8 +334,10 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) uiItemMenuEnumO(row, C, "OBJECT_OT_mode_set", "mode", name, icon); } - /* Draw type */ - uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + if (IS_VIEWPORT_LEGACY(v3d)) { + /* Draw type */ + uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + } if (obedit == NULL && is_paint) { if (ob->mode & OB_MODE_ALL_PAINT) { diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index b11f42bcfef..504a8383a41 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -143,10 +143,22 @@ void draw_motion_paths_cleanup(View3D *v3d); /* drawobject.c */ void draw_object(Scene *scene, struct ARegion *ar, View3D *v3d, Base *base, const short dflag); +void draw_mesh_object_outline(View3D *v3d, Object *ob, struct DerivedMesh *dm); + bool draw_glsl_material(Scene *scene, struct Object *ob, View3D *v3d, const char dt); void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline); void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob); -void drawaxes(const float viewmat_local[4][4], float size, char drawtype); + +void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_wire_col[4]); +void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4]); +void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, + const char dt, const short dflag, const unsigned char ob_wire_col[4], + const bool is_obact); +void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, + const short dflag, const unsigned char ob_wire_col[4]); +void drawspeaker(const unsigned char ob_wire_col[3]); +void draw_bounding_volume(struct Object *ob, char type); +void draw_rigidbody_shape(struct Object *ob); void view3d_cached_text_draw_begin(void); void view3d_cached_text_draw_add(const float co[3], @@ -193,11 +205,13 @@ void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar); /* view3d_draw.c */ void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar); + +/* view3d_draw_legacy.c */ +void view3d_main_region_draw_legacy(const struct bContext *C, struct ARegion *ar); void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride); void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d); void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag); -void circf(float x, float y, float rad); void circ(float x, float y, float rad); void view3d_update_depths_rect(struct ARegion *ar, struct ViewDepths *d, struct rcti *rect); float view3d_depth_near(struct ViewDepths *d); @@ -309,5 +323,22 @@ extern unsigned char view3d_camera_border_hack_col[3]; extern bool view3d_camera_border_hack_test; #endif -#endif /* __VIEW3D_INTERN_H__ */ +/* temporary test for blender 2.8 viewport */ +#define IS_VIEWPORT_LEGACY(v3d) ((v3d->tmp_compat_flag & V3D_NEW_VIEWPORT) == 0) + +/* temporary for legacy viewport to work */ +void VP_legacy_drawcursor(Scene *scene, ARegion *ar, View3D *v3d); +void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect); +void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit); +void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth); +void VP_legacy_view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]); +bool VP_legacy_view3d_stereo3d_active(const struct bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d); +void VP_legacy_view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar); +void draw_dupli_objects(Scene *scene, ARegion *ar, View3D *v3d, Base *base); +bool VP_legacy_use_depth(Scene *scene, View3D *v3d); +void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d); +void VP_drawrenderborder(ARegion *ar, View3D *v3d); +void VP_view3d_draw_background_none(void); +void VP_view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d); +#endif /* __VIEW3D_INTERN_H__ */ diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 688f459108b..7540e5ad180 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -429,9 +429,9 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a //unsigned int color_act = 0x666600; unsigned int color_act = 0xffffff; unsigned int color_base = 0x0; - unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80}; unsigned char color_text[3]; unsigned char color_wire[3]; + float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f}; /* anti-aliased lines for more consistent appearance */ glEnable(GL_LINE_SMOOTH); @@ -530,12 +530,11 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); /* draw text (bg) */ - glColor4ubv(color_back); UI_draw_roundbox_corner_set(UI_CNR_ALL); UI_draw_roundbox( pos[0] - bg_margin, pos[1] - bg_margin, pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], - bg_radius); + bg_radius, color_back); /* draw text */ glColor3ubv(color_text); BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); @@ -620,11 +619,10 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a pos[1] -= numstr_size[1] / 2.0f; /* draw text (bg) */ - glColor4ubv(color_back); UI_draw_roundbox_corner_set(UI_CNR_ALL); UI_draw_roundbox(pos[0] - bg_margin, pos[1] - bg_margin, pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], - bg_radius); + bg_radius, color_back); /* draw text */ glColor3ubv(color_text); BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 17c08ed4205..4131a5c33c7 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -57,6 +57,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_immediate.h" + #include "view3d_intern.h" /* own include */ #ifdef WITH_INPUT_NDOF @@ -338,24 +340,33 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a yoff = walk->ar->winy / 2; } - UI_ThemeColor(TH_VIEW_OVERLAY); - glBegin(GL_LINES); + VertexFormat* format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_INT, 2, CONVERT_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_VIEW_OVERLAY); + + immBegin(GL_LINES, 8); + /* North */ - glVertex2i(xoff, yoff + inner_length); - glVertex2i(xoff, yoff + outter_length); + immVertex2i(pos, xoff, yoff + inner_length); + immVertex2i(pos, xoff, yoff + outter_length); /* East */ - glVertex2i(xoff + inner_length, yoff); - glVertex2i(xoff + outter_length, yoff); + immVertex2i(pos, xoff + inner_length, yoff); + immVertex2i(pos, xoff + outter_length, yoff); /* South */ - glVertex2i(xoff, yoff - inner_length); - glVertex2i(xoff, yoff - outter_length); + immVertex2i(pos, xoff, yoff - inner_length); + immVertex2i(pos, xoff, yoff - outter_length); /* West */ - glVertex2i(xoff - inner_length, yoff); - glVertex2i(xoff - outter_length, yoff); - glEnd(); + immVertex2i(pos, xoff - inner_length, yoff); + immVertex2i(pos, xoff - outter_length, yoff); + + immEnd(); + immUnbindProgram(); } static void walk_update_header(bContext *C, wmOperator *op, WalkInfo *walk) diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index e141724f2df..e1abf34b0f4 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -1381,38 +1381,76 @@ static void draw_manipulator_scale( glFrontFace(GL_CCW); } - -static void draw_cone(GLUquadricObj *qobj, float len, float width) +#define NSEGMENTS 8 +static void draw_cone(float len, float width) { - glTranslatef(0.0, 0.0, -0.5f * len); - gluCylinder(qobj, width, 0.0, len, 8, 1); - gluQuadricOrientation(qobj, GLU_INSIDE); - gluDisk(qobj, 0.0, width, 8, 1); - gluQuadricOrientation(qobj, GLU_OUTSIDE); - glTranslatef(0.0, 0.0, 0.5f * len); + /* a ring of vertices in the XY plane */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = width * cosf(angle); + p[i][1] = width * sinf(angle); + } + + float zbase = -0.5f * len; + float ztop = 0.5f * len; + + /* cone sides */ + glBegin(GL_TRIANGLE_FAN); + glVertex3f(0, 0, ztop); + for (int i = 0; i < NSEGMENTS; ++i) + glVertex3f(p[i][0], p[i][1], zbase); + glVertex3f(p[0][0], p[0][1], zbase); + glEnd(); + + /* end cap */ + glBegin(GL_TRIANGLE_FAN); + for (int i = NSEGMENTS - 1; i >= 0; --i) + glVertex3f(p[i][0], p[i][1], zbase); + glEnd(); } -static void draw_cylinder(GLUquadricObj *qobj, float len, float width) +static void draw_cylinder(float len, float width) { - width *= 0.8f; // just for beauty - glTranslatef(0.0, 0.0, -0.5f * len); - gluCylinder(qobj, width, width, len, 8, 1); - gluQuadricOrientation(qobj, GLU_INSIDE); - gluDisk(qobj, 0.0, width, 8, 1); - gluQuadricOrientation(qobj, GLU_OUTSIDE); - glTranslatef(0.0, 0.0, len); - gluDisk(qobj, 0.0, width, 8, 1); - glTranslatef(0.0, 0.0, -0.5f * len); -} + /* a ring of vertices in the XY plane */ + float p[NSEGMENTS][2]; + for (int i = 0; i < NSEGMENTS; ++i) { + float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS); + p[i][0] = width * cosf(angle); + p[i][1] = width * sinf(angle); + } + float zbase = -0.5f * len; + float ztop = 0.5f * len; + + /* cylinder sides */ + glBegin(GL_TRIANGLE_STRIP); + for (int i = 0; i < NSEGMENTS; ++i) { + glVertex3f(p[i][0], p[i][1], zbase); + glVertex3f(p[i][0], p[i][1], ztop); + } + glVertex3f(p[0][0], p[0][1], zbase); + glVertex3f(p[0][0], p[0][1], ztop); + glEnd(); + + /* end caps */ + glBegin(GL_TRIANGLE_FAN); + for (int i = NSEGMENTS - 1; i >= 0; --i) + glVertex3f(p[i][0], p[i][1], zbase); + glEnd(); + glBegin(GL_TRIANGLE_FAN); + for (int i = 0; i < NSEGMENTS; ++i) + glVertex3f(p[i][0], p[i][1], ztop); + glEnd(); +} +#undef NSEGMENTS static void draw_manipulator_translate( View3D *v3d, RegionView3D *rv3d, int drawflags, int combo, int colcode, const bool UNUSED(is_moving), const bool is_picksel) { - GLUquadricObj *qobj; float cylen = 0.01f * (float)U.tw_handlesize; float cywid = 0.25f * cylen, dz, size; float unitmat[4][4]; @@ -1451,63 +1489,57 @@ static void draw_manipulator_translate( axis_order, is_picksel); } - /* offset in combo mode, for rotate a bit more */ if (combo & (V3D_MANIP_ROTATE)) dz = 1.0f + 2.0f * cylen; else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen; else dz = 1.0f; - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - for (i = 0; i < 3; i++) { switch (axis_order[i]) { case 0: /* Z Cone */ if (drawflags & MAN_TRANS_Z) { + glPushMatrix(); glTranslatef(0.0, 0.0, dz); if (is_picksel) GPU_select_load_id(MAN_TRANS_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - draw_cone(qobj, cylen, cywid); - glTranslatef(0.0, 0.0, -dz); + draw_cone(cylen, cywid); + glPopMatrix(); } break; case 1: /* X Cone */ if (drawflags & MAN_TRANS_X) { + glPushMatrix(); glTranslatef(dz, 0.0, 0.0); if (is_picksel) GPU_select_load_id(MAN_TRANS_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); glRotatef(90.0, 0.0, 1.0, 0.0); - draw_cone(qobj, cylen, cywid); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(-dz, 0.0, 0.0); + draw_cone(cylen, cywid); + glPopMatrix(); } break; case 2: /* Y Cone */ if (drawflags & MAN_TRANS_Y) { + glPushMatrix(); glTranslatef(0.0, dz, 0.0); if (is_picksel) GPU_select_load_id(MAN_TRANS_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); glRotatef(-90.0, 1.0, 0.0, 0.0); - draw_cone(qobj, cylen, cywid); - glRotatef(90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, -dz, 0.0); + draw_cone(cylen, cywid); + glPopMatrix(); } break; } } - gluDeleteQuadric(qobj); glLoadMatrixf(rv3d->viewmat); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } static void draw_manipulator_rotate_cyl( View3D *v3d, RegionView3D *rv3d, int drawflags, const int combo, const int colcode, const bool is_moving, const bool is_picksel) { - GLUquadricObj *qobj; float size; float cylen = 0.01f * (float)U.tw_handlesize; float cywid = 0.25f * cylen; @@ -1525,8 +1557,6 @@ static void draw_manipulator_rotate_cyl( glDisable(GL_DEPTH_TEST); - qobj = gluNewQuadric(); - /* Screen aligned view rot circle */ if (drawflags & MAN_ROT_V) { float unitmat[4][4]; @@ -1575,54 +1605,49 @@ static void draw_manipulator_rotate_cyl( drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z, axis_order, is_picksel); } - - /* only has to be set when not in picking */ - gluQuadricDrawStyle(qobj, GLU_FILL); } for (i = 0; i < 3; i++) { switch (axis_order[i]) { case 0: /* X cylinder */ if (drawflags & MAN_ROT_X) { + glPushMatrix(); glTranslatef(1.0, 0.0, 0.0); if (is_picksel) GPU_select_load_id(MAN_ROT_X); glRotatef(90.0, 0.0, 1.0, 0.0); manipulator_setcolor(v3d, 'X', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(-1.0, 0.0, 0.0); + draw_cylinder(cylen, cywid); + glPopMatrix(); } break; case 1: /* Y cylinder */ if (drawflags & MAN_ROT_Y) { + glPushMatrix(); glTranslatef(0.0, 1.0, 0.0); if (is_picksel) GPU_select_load_id(MAN_ROT_Y); glRotatef(-90.0, 1.0, 0.0, 0.0); manipulator_setcolor(v3d, 'Y', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glRotatef(90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, -1.0, 0.0); + draw_cylinder(cylen, cywid); + glPopMatrix(); } break; case 2: /* Z cylinder */ if (drawflags & MAN_ROT_Z) { + glPushMatrix(); glTranslatef(0.0, 0.0, 1.0); if (is_picksel) GPU_select_load_id(MAN_ROT_Z); manipulator_setcolor(v3d, 'Z', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glTranslatef(0.0, 0.0, -1.0); + draw_cylinder(cylen, cywid); + glPopMatrix(); } break; } } /* restore */ - - gluDeleteQuadric(qobj); glLoadMatrixf(rv3d->viewmat); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 1f1a778cac7..482523e56be 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -70,6 +70,8 @@ #include "ED_space_api.h" #include "ED_util.h" +#include "GPU_immediate.h" + #include "UI_interface.h" #include "UI_resources.h" @@ -312,15 +314,23 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info { wmWindow *win = CTX_wm_window(C); const float *mval_src = (float *)arg_info; - const int mval_dst[2] = {win->eventstate->x - ar->winrct.xmin, - win->eventstate->y - ar->winrct.ymin}; + const float mval_dst[2] = {win->eventstate->x - ar->winrct.xmin, + win->eventstate->y - ar->winrct.ymin}; - UI_ThemeColor(TH_VIEW_OVERLAY); setlinestyle(3); - glBegin(GL_LINES); - glVertex2iv(mval_dst); - glVertex2fv(mval_src); - glEnd(); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_VIEW_OVERLAY); + + immBegin(GL_LINES, 2); + immVertex2fv(pos, mval_dst); + immVertex2fv(pos, mval_src); + immEnd(); + immUnbindProgram(); + setlinestyle(0); } diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 8885209ce01..5643400ac66 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -32,6 +32,8 @@ set(INC ../makesdna ../makesrna + ../editors/include + # For node muting stuff... ../nodes ../nodes/intern @@ -47,6 +49,7 @@ set(INC_SYS set(SRC intern/gpu_basic_shader.c + intern/gpu_batch.c intern/gpu_buffers.c intern/gpu_codegen.c intern/gpu_compositing.c @@ -54,11 +57,32 @@ set(SRC intern/gpu_draw.c intern/gpu_extensions.c intern/gpu_framebuffer.c + intern/gpu_immediate.c intern/gpu_init_exit.c intern/gpu_material.c + intern/gpu_matrix.c intern/gpu_select.c intern/gpu_shader.c intern/gpu_texture.c + intern/gpu_viewport.c + + gawain/attrib_binding.c + gawain/attrib_binding.h + gawain/batch.c + gawain/batch.h + gawain/buffer_id.h + gawain/buffer_id.cpp + gawain/common.h + gawain/element.c + gawain/element.h + gawain/immediate.c + gawain/immediate.h + gawain/imm_util.c + gawain/imm_util.h + gawain/vertex_buffer.c + gawain/vertex_buffer.h + gawain/vertex_format.c + gawain/vertex_format.h shaders/gpu_shader_fx_lib.glsl shaders/gpu_shader_fx_ssao_frag.glsl @@ -83,6 +107,7 @@ set(SRC shaders/gpu_shader_smoke_vert.glsl GPU_basic_shader.h + GPU_batch.h GPU_buffers.h GPU_compositing.h GPU_debug.h @@ -90,15 +115,65 @@ set(SRC GPU_extensions.h GPU_framebuffer.h GPU_glew.h + GPU_immediate.h GPU_init_exit.h GPU_material.h + GPU_matrix.h GPU_select.h GPU_shader.h GPU_texture.h + GPU_viewport.h + intern/gpu_codegen.h intern/gpu_private.h ) +data_to_c_simple(shaders/gpu_shader_depth_only_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_mask_uniform_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_uniform_color_smooth_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_varying_color_outline_smooth_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_varying_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_smooth_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_outline_smooth_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_ortho_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_overlay_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_overlay_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_overlay_simple_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_overlay_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC) + data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC) data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC) diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h new file mode 100644 index 00000000000..bc3017e2784 --- /dev/null +++ b/source/blender/gpu/GPU_batch.h @@ -0,0 +1,37 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Batched geometry rendering is powered by the Gawain library. + * This file contains any additions or modifications specific to Blender. + */ + +#pragma once + +#include "gawain/batch.h" +#include "GPU_shader.h" + +/* Extend Batch_set_program to use Blender’s library of built-in shader programs. */ +void Batch_set_builtin_program(Batch*, GPUBuiltinShader); diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h index 61b2bc591ce..921deaaa6d6 100644 --- a/source/blender/gpu/GPU_debug.h +++ b/source/blender/gpu/GPU_debug.h @@ -41,24 +41,9 @@ extern "C" { /* prints something if debug mode is active only */ void GPU_print_error_debug(const char *str); -/* replacement for gluErrorString */ -const char *gpuErrorString(GLenum err); - /* prints current OpenGL state */ void GPU_state_print(void); -void GPU_assert_no_gl_errors(const char *file, int line, const char *str); - -# define GPU_ASSERT_NO_GL_ERRORS(str) GPU_assert_no_gl_errors(__FILE__, __LINE__, (str)) - -# define GPU_CHECK_ERRORS_AROUND(glProcCall) \ - ( \ - GPU_ASSERT_NO_GL_ERRORS("Pre: " #glProcCall), \ - (glProcCall), \ - GPU_ASSERT_NO_GL_ERRORS("Post: " #glProcCall) \ - ) - - /* inserts a debug marker message for the debug context messaging system */ void GPU_string_marker(const char *str); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 90b65af87c8..91d436557f0 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -59,6 +59,13 @@ struct DupliObject; void GPU_state_init(void); +/* Programmable point size + * - shaders set their own point size when enabled + * - use glPointSize when disabled */ + +void GPU_enable_program_point_size(void); +void GPU_disable_program_point_size(void); + /* Material drawing * - first the state is initialized by a particular object and * it's materials diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 2719b8fa6a8..989b874fd38 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -50,7 +50,7 @@ struct GPUTexture; void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex); GPUFrameBuffer *GPU_framebuffer_create(void); -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, char err_out[256]); +bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot); void GPU_framebuffer_texture_detach(struct GPUTexture *tex); void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex); diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h new file mode 100644 index 00000000000..f601d062d48 --- /dev/null +++ b/source/blender/gpu/GPU_immediate.h @@ -0,0 +1,48 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Immediate mode rendering is powered by the Gawain library. + * This file contains any additions or modifications specific to Blender. + */ + +#pragma once + +#include "gawain/immediate.h" +#include "gawain/imm_util.h" +#include "GPU_shader.h" + +/* Extend immBindProgram to use Blender’s library of built-in shader programs. + * Use immUnbindProgram() when done. */ +void immBindBuiltinProgram(GPUBuiltinShader shader_id); + +/* + * Extend immUniformColor to take Blender's themes + */ +void immUniformThemeColor(int color_id); +void immUniformThemeColorShade(int color_id, int offset); +void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset); +void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset); +void immUniformThemeColorBlend(int color_id1, int color_id2, float fac); diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h new file mode 100644 index 00000000000..4390b62379e --- /dev/null +++ b/source/blender/gpu/GPU_matrix.h @@ -0,0 +1,147 @@ +#ifndef _GPU_MATRIX_H_ +#define _GPU_MATRIX_H_ + +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/GPU_matrix.h + * \ingroup gpu + */ + +#include "GPU_glew.h" +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* For now we support the legacy matrix stack in gpuGetMatrix functions. + * Will remove this after switching to core profile, which can happen after + * we convert all code to use the API in this file. */ +#define SUPPORT_LEGACY_MATRIX 1 + + +void gpuMatrixInit(void); /* called by system -- make private? */ + + +/* MatrixMode is conceptually different from GL_MATRIX_MODE */ + +typedef enum { + MATRIX_MODE_INACTIVE, + MATRIX_MODE_2D, + MATRIX_MODE_3D +} MatrixMode; + +MatrixMode gpuMatrixMode(void); + +void gpuMatrixBegin2D(void); +void gpuMatrixBegin3D(void); +void gpuMatrixEnd(void); +/* TODO: gpuMatrixResume2D & gpuMatrixResume3D to switch modes but not reset stack */ + + +/* ModelView Matrix (2D or 3D) */ + +void gpuPushMatrix(void); /* TODO: PushCopy vs PushIdentity? */ +void gpuPopMatrix(void); + +void gpuLoadIdentity(void); + +void gpuScaleUniform(float factor); + + +/* 3D ModelView Matrix */ + +void gpuLoadMatrix3D(const float m[4][4]); +void gpuMultMatrix3D(const float m[4][4]); +//const float *gpuGetMatrix3D(float m[4][4]); + +void gpuTranslate3f(float x, float y, float z); +void gpuTranslate3fv(const float vec[3]); +void gpuScale3f(float x, float y, float z); +void gpuScale3fv(const float vec[3]); +void gpuRotate3fv(float deg, const float axis[3]); /* axis of rotation should be a unit vector */ +void gpuRotateAxis(float deg, char axis); /* TODO: enum for axis? */ + +void gpuLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ); +/* TODO: variant that takes eye[3], center[3], up[3] */ + + +/* 2D ModelView Matrix */ + +void gpuLoadMatrix2D(const float m[3][3]); +void gpuMultMatrix2D(const float m[3][3]); + +void gpuTranslate2f(float x, float y); +void gpuTranslate2fv(const float vec[2]); +void gpuScale2f(float x, float y); +void gpuScale2fv(const float vec[2]); +void gpuRotate2D(float deg); + + +/* 3D Projection Matrix */ + +void gpuOrtho(float left, float right, float bottom, float top, float near, float far); +void gpuFrustum(float left, float right, float bottom, float top, float near, float far); +void gpuPerspective(float fovy, float aspect, float near, float far); + +/* pass vector through current transform (world --> screen) */ +void gpuProject(const float obj[3], const float model[4][4], const float proj[4][4], const GLint view[4], float win[3]); + +/* pass vector through inverse transform (world <-- screen) */ +bool gpuUnProject(const float win[3], const float model[4][4], const float proj[4][4], const GLint view[4], float obj[3]); + + +/* 2D Projection Matrix */ + +void gpuOrtho2D(float left, float right, float bottom, float top); + + +/* functions to get matrix values */ +const float *gpuGetModelViewMatrix3D(float m[4][4]); +const float *gpuGetProjectionMatrix3D(float m[4][4]); +const float *gpuGetModelViewProjectionMatrix3D(float m[4][4]); + +const float *gpuGetNormalMatrix(float m[3][3]); +const float *gpuGetNormalMatrixInverse(float m[3][3]); + + +#if SUPPORT_LEGACY_MATRIX +/* copy top matrix from each legacy stack into new fresh stack */ +void gpuMatrixBegin3D_legacy(void); +#endif + + +/* set uniform values for currently bound shader */ +void gpuBindMatrices(GLuint program); +bool gpuMatricesDirty(void); /* since last bind */ + +#ifdef __cplusplus +} +#endif + +#endif /* GPU_MATRIX_H */ diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 5b94db6e120..c6e4fb5e73a 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -85,11 +85,47 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name); /* Builtin/Non-generated shaders */ typedef enum GPUBuiltinShader { - GPU_SHADER_VSM_STORE = 0, - GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, - GPU_SHADER_SMOKE = 2, - GPU_SHADER_SMOKE_FIRE = 3, - GPU_SHADER_SMOKE_COBA = 4, + GPU_SHADER_VSM_STORE, + GPU_SHADER_SEP_GAUSSIAN_BLUR, + GPU_SHADER_SMOKE, + GPU_SHADER_SMOKE_FIRE, + GPU_SHADER_SMOKE_COBA, + + /* specialized drawing */ + GPU_SHADER_TEXT, + GPU_SHADER_EDGES_FRONT_BACK_PERSP, + GPU_SHADER_EDGES_FRONT_BACK_ORTHO, + GPU_SHADER_EDGES_OVERLAY_SIMPLE, + GPU_SHADER_EDGES_OVERLAY, + /* for simple 2D drawing */ + GPU_SHADER_2D_UNIFORM_COLOR, + GPU_SHADER_2D_FLAT_COLOR, + GPU_SHADER_2D_SMOOTH_COLOR, + GPU_SHADER_2D_IMAGE_COLOR, + /* for simple 3D drawing */ + GPU_SHADER_3D_UNIFORM_COLOR, + GPU_SHADER_3D_FLAT_COLOR, + GPU_SHADER_3D_SMOOTH_COLOR, + GPU_SHADER_3D_DEPTH_ONLY, + /* basic image drawing */ + GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR, + GPU_SHADER_3D_IMAGE_MODULATE_ALPHA, + GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA, + GPU_SHADER_3D_IMAGE_DEPTH, + /* points */ + GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_SMOOTH, + GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR, + GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR, + GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR, + GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH, + GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH, + GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR, + GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR, + + GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */ } GPUBuiltinShader; GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h new file mode 100644 index 00000000000..e2519484eb4 --- /dev/null +++ b/source/blender/gpu/GPU_viewport.h @@ -0,0 +1,52 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_viewport.h + * \ingroup gpu + */ + +#ifndef __GPU_VIEWPORT_H__ +#define __GPU_VIEWPORT_H__ + +#include <stdbool.h> + +typedef struct GPUViewport GPUViewport; + +GPUViewport *GPU_viewport_create(void); + +void GPU_viewport_free(GPUViewport *viewport); + +/* debug */ +bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, int samples, char err_out[256]); +void GPU_viewport_debug_depth_free(GPUViewport *viewport); +void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y); +void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar); +bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport); +int GPU_viewport_debug_depth_width(const GPUViewport *viewport); +int GPU_viewport_debug_depth_height(const GPUViewport *viewport); + +#endif // __GPU_VIEWPORT_H__ diff --git a/source/blender/gpu/gawain/attrib_binding.c b/source/blender/gpu/gawain/attrib_binding.c new file mode 100644 index 00000000000..bb42aaf66eb --- /dev/null +++ b/source/blender/gpu/gawain/attrib_binding.c @@ -0,0 +1,69 @@ + +// Gawain vertex attribute binding +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "attrib_binding.h" + +#if MAX_VERTEX_ATTRIBS != 16 + #error "attrib binding code assumes MAX_VERTEX_ATTRIBS = 16" +#endif + +void clear_AttribBinding(AttribBinding* binding) + { + binding->loc_bits = 0; + binding->enabled_bits = 0; + } + +unsigned read_attrib_location(const AttribBinding* binding, unsigned a_idx) + { +#if TRUST_NO_ONE + assert(a_idx < MAX_VERTEX_ATTRIBS); + assert(binding->enabled_bits & (1 << a_idx)); +#endif + + return (binding->loc_bits >> (4 * a_idx)) & 0xF; + } + +static void write_attrib_location(AttribBinding* binding, unsigned a_idx, unsigned location) + { +#if TRUST_NO_ONE + assert(a_idx < MAX_VERTEX_ATTRIBS); + assert(location < MAX_VERTEX_ATTRIBS); +#endif + + const unsigned shift = 4 * a_idx; + const uint64_t mask = ((uint64_t)0xF) << shift; + // overwrite this attrib's previous location + binding->loc_bits = (binding->loc_bits & ~mask) | (location << shift); + // mark this attrib as enabled + binding->enabled_bits |= 1 << a_idx; + } + +void get_attrib_locations(const VertexFormat* format, AttribBinding* binding, GLuint program) + { +#if TRUST_NO_ONE + assert(glIsProgram(program)); +#endif + + clear_AttribBinding(binding); + + for (unsigned a_idx = 0; a_idx < format->attrib_ct; ++a_idx) + { + const Attrib* a = format->attribs + a_idx; + GLint loc = glGetAttribLocation(program, a->name); + +#if TRUST_NO_ONE + assert(loc != -1); + // TODO: make this a recoverable runtime error? indicates mismatch between vertex format and program +#endif + + write_attrib_location(binding, a_idx, loc); + } + } diff --git a/source/blender/gpu/gawain/attrib_binding.h b/source/blender/gpu/gawain/attrib_binding.h new file mode 100644 index 00000000000..9e2431ca379 --- /dev/null +++ b/source/blender/gpu/gawain/attrib_binding.h @@ -0,0 +1,24 @@ + +// Gawain vertex attribute binding +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" + +typedef struct { + uint64_t loc_bits; // store 4 bits for each of the 16 attribs + uint16_t enabled_bits; // 1 bit for each attrib +} AttribBinding; + +void clear_AttribBinding(AttribBinding*); + +void get_attrib_locations(const VertexFormat*, AttribBinding*, GLuint program); +unsigned read_attrib_location(const AttribBinding*, unsigned a_idx); diff --git a/source/blender/gpu/gawain/batch.c b/source/blender/gpu/gawain/batch.c new file mode 100644 index 00000000000..a60865d41d2 --- /dev/null +++ b/source/blender/gpu/gawain/batch.c @@ -0,0 +1,249 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "batch.h" +#include "buffer_id.h" +#include <stdlib.h> + +// necessary functions from matrix API +extern void gpuBindMatrices(GLuint program); +extern bool gpuMatricesDirty(void); // how best to use this here? + +Batch* Batch_create(PrimitiveType prim_type, VertexBuffer* verts, ElementList* elem) + { +#if TRUST_NO_ONE + assert(verts != NULL); + assert(prim_type == PRIM_POINTS || prim_type == PRIM_LINES || prim_type == PRIM_TRIANGLES); + // we will allow other primitive types in a future update +#endif + + Batch* batch = calloc(1, sizeof(Batch)); + + batch->verts = verts; + batch->elem = elem; + batch->prim_type = prim_type; + batch->phase = READY_TO_DRAW; + + return batch; + } + +void Batch_discard(Batch* batch) + { + if (batch->vao_id) + vao_id_free(batch->vao_id); + + free(batch); + } + +void Batch_discard_all(Batch* batch) + { + VertexBuffer_discard(batch->verts); + if (batch->elem) + ElementList_discard(batch->elem); + Batch_discard(batch); + } + +void Batch_set_program(Batch* batch, GLuint program) + { +#if TRUST_NO_ONE + assert(glIsProgram(program)); +#endif + + batch->program = program; + batch->program_dirty = true; + + Batch_use_program(batch); // hack! to make Batch_Uniform* simpler + } + +static void Batch_update_program_bindings(Batch* batch) + { + const VertexFormat* format = &batch->verts->format; + + const unsigned attrib_ct = format->attrib_ct; + const unsigned stride = format->stride; + + // disable all as a precaution + // why are we not using prev_attrib_enabled_bits?? see immediate.c + for (unsigned a_idx = 0; a_idx < MAX_VERTEX_ATTRIBS; ++a_idx) + glDisableVertexAttribArray(a_idx); + + VertexBuffer_use(batch->verts); + + for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx) + { + const Attrib* a = format->attribs + a_idx; + + const GLvoid* pointer = (const GLubyte*)0 + a->offset; + + const GLint loc = glGetAttribLocation(batch->program, a->name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glEnableVertexAttribArray(loc); + + switch (a->fetch_mode) + { + case KEEP_FLOAT: + case CONVERT_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_FALSE, stride, pointer); + break; + case NORMALIZE_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_TRUE, stride, pointer); + break; + case KEEP_INT: + glVertexAttribIPointer(loc, a->comp_ct, a->comp_type, stride, pointer); + } + } + + batch->program_dirty = false; + } + +void Batch_use_program(Batch* batch) + { + // NOTE: use_program & done_using_program are fragile, depend on staying in sync with + // the GL context's active program. use_program doesn't mark other programs as "not used". + // TODO: make not fragile (somehow) + + if (!batch->program_in_use) + { + glUseProgram(batch->program); + batch->program_in_use = true; + } + } + +void Batch_done_using_program(Batch* batch) + { + if (batch->program_in_use) + { + glUseProgram(0); + batch->program_in_use = false; + } + } + +void Batch_Uniform1b(Batch* batch, const char* name, bool value) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform1i(loc, value ? GL_TRUE : GL_FALSE); + } + +void Batch_Uniform2f(Batch* batch, const char* name, float x, float y) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform2f(loc, x, y); + } + +void Batch_Uniform4f(Batch* batch, const char* name, float x, float y, float z, float w) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform4f(loc, x, y, z, w); + } + +void Batch_Uniform1f(Batch* batch, const char* name, float x) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform1f(loc, x); + } + +void Batch_Uniform3fv(Batch* batch, const char* name, const float data[3]) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform3fv(loc, 1, data); + } + +void Batch_Uniform4fv(Batch* batch, const char* name, const float data[4]) + { + int loc = glGetUniformLocation(batch->program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform4fv(loc, 1, data); + } + +static void Batch_prime(Batch* batch) + { + batch->vao_id = vao_id_alloc(); + glBindVertexArray(batch->vao_id); + + VertexBuffer_use(batch->verts); + + if (batch->elem) + ElementList_use(batch->elem); + + // vertex attribs and element list remain bound to this VAO + } + +void Batch_draw(Batch* batch) + { +#if TRUST_NO_ONE + assert(batch->phase == READY_TO_DRAW); + assert(glIsProgram(batch->program)); +#endif + + if (batch->vao_id) + glBindVertexArray(batch->vao_id); + else + Batch_prime(batch); + + if (batch->program_dirty) + Batch_update_program_bindings(batch); + + Batch_use_program(batch); + + gpuBindMatrices(batch->program); + + if (batch->elem) + { + const ElementList* el = batch->elem; + +#if TRACK_INDEX_RANGE + if (el->base_index) + glDrawRangeElementsBaseVertex(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0, el->base_index); + else + glDrawRangeElements(batch->prim_type, el->min_index, el->max_index, el->index_ct, el->index_type, 0); +#else + glDrawElements(batch->prim_type, el->index_ct, GL_UNSIGNED_INT, 0); +#endif + } + else + glDrawArrays(batch->prim_type, 0, batch->verts->vertex_ct); + + Batch_done_using_program(batch); + glBindVertexArray(0); + } diff --git a/source/blender/gpu/gawain/batch.h b/source/blender/gpu/gawain/batch.h new file mode 100644 index 00000000000..c2768377a96 --- /dev/null +++ b/source/blender/gpu/gawain/batch.h @@ -0,0 +1,97 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_buffer.h" +#include "element.h" + +typedef enum { + READY_TO_FORMAT, + READY_TO_BUILD, + BUILDING, + READY_TO_DRAW +} BatchPhase; + +typedef struct { + // geometry + VertexBuffer* verts; + ElementList* elem; // NULL if element list not needed + PrimitiveType prim_type; + + // book-keeping + GLuint vao_id; // remembers all geometry state (vertex attrib bindings & element buffer) + BatchPhase phase; + bool program_dirty; + bool program_in_use; + + // state + GLuint program; +} Batch; + +Batch* Batch_create(PrimitiveType, VertexBuffer*, ElementList*); + +void Batch_discard(Batch*); // verts & elem are not discarded +void Batch_discard_all(Batch*); // including verts & elem + +void Batch_set_program(Batch*, GLuint program); +// Entire batch draws with one shader program, but can be redrawn later with another program. +// Vertex shader's inputs must be compatible with the batch's vertex format. + +void Batch_use_program(Batch*); // call before Batch_Uniform (temp hack?) +void Batch_done_using_program(Batch*); + +void Batch_Uniform1b(Batch*, const char* name, bool value); +void Batch_Uniform1f(Batch*, const char* name, float value); +void Batch_Uniform2f(Batch*, const char* name, float x, float y); +void Batch_Uniform4f(Batch*, const char* name, float x, float y, float z, float w); +void Batch_Uniform3fv(Batch*, const char* name, const float data[3]); +void Batch_Uniform4fv(Batch*, const char* name, const float data[4]); + +void Batch_draw(Batch*); + + + + + + +#if 0 // future plans + +// Can multiple batches share a VertexBuffer? Use ref count? + + +// We often need a batch with its own data, to be created and discarded together. +// WithOwn variants reduce number of system allocations. + +typedef struct { + Batch batch; + VertexBuffer verts; // link batch.verts to this +} BatchWithOwnVertexBuffer; + +typedef struct { + Batch batch; + ElementList elem; // link batch.elem to this +} BatchWithOwnElementList; + +typedef struct { + Batch batch; + ElementList elem; // link batch.elem to this + VertexBuffer verts; // link batch.verts to this +} BatchWithOwnVertexBufferAndElementList; + +Batch* create_BatchWithOwnVertexBuffer(PrimitiveType, VertexFormat*, unsigned v_ct, ElementList*); +Batch* create_BatchWithOwnElementList(PrimitiveType, VertexBuffer*, unsigned prim_ct); +Batch* create_BatchWithOwnVertexBufferAndElementList(PrimitiveType, VertexFormat*, unsigned v_ct, unsigned prim_ct); +// verts: shared, own +// elem: none, shared, own +Batch* create_BatchInGeneral(PrimitiveType, VertexBufferStuff, ElementListStuff); + +#endif // future plans diff --git a/source/blender/gpu/gawain/buffer_id.cpp b/source/blender/gpu/gawain/buffer_id.cpp new file mode 100644 index 00000000000..a7b8d7a394a --- /dev/null +++ b/source/blender/gpu/gawain/buffer_id.cpp @@ -0,0 +1,116 @@ + +// Gawain buffer IDs +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.#include "buffer_id.h" + +#include "buffer_id.h" +#include <mutex> +#include <vector> + +#define ORPHAN_DEBUG 0 + +#if ORPHAN_DEBUG + #include <cstdio> +#endif + +static std::vector<GLuint> orphaned_buffer_ids; +static std::vector<GLuint> orphaned_vao_ids; + +static std::mutex orphan_mutex; + +extern "C" { +extern int BLI_thread_is_main(void); // Blender-specific function +} + +static bool thread_is_main() + { + // "main" here means the GL context's thread + return BLI_thread_is_main(); + } + +GLuint buffer_id_alloc() + { +#if TRUST_NO_ONE + assert(thread_is_main()); +#endif + + // delete orphaned IDs + orphan_mutex.lock(); + if (!orphaned_buffer_ids.empty()) + { + const auto orphaned_buffer_ct = (unsigned)orphaned_buffer_ids.size(); +#if ORPHAN_DEBUG + printf("deleting %u orphaned VBO%s\n", orphaned_buffer_ct, orphaned_buffer_ct == 1 ? "" : "s"); +#endif + glDeleteBuffers(orphaned_buffer_ct, orphaned_buffer_ids.data()); + orphaned_buffer_ids.clear(); + } + orphan_mutex.unlock(); + + GLuint new_buffer_id; + glGenBuffers(1, &new_buffer_id); + return new_buffer_id; + } + +void buffer_id_free(GLuint buffer_id) + { + if (thread_is_main()) + glDeleteBuffers(1, &buffer_id); + else + { + // add this ID to the orphaned list + orphan_mutex.lock(); +#if ORPHAN_DEBUG + printf("orphaning VBO %u\n", buffer_id); +#endif + orphaned_buffer_ids.emplace_back(buffer_id); + orphan_mutex.unlock(); + } + } + +GLuint vao_id_alloc() + { +#if TRUST_NO_ONE + assert(thread_is_main()); +#endif + + GLuint new_vao_id; + + // delete orphaned IDs + orphan_mutex.lock(); + if (!orphaned_vao_ids.empty()) + { + const auto orphaned_vao_ct = (unsigned)orphaned_vao_ids.size(); +#if ORPHAN_DEBUG + printf("deleting %u orphaned VAO%s\n", orphaned_vao_ct, orphaned_vao_ct == 1 ? "" : "s"); +#endif + glDeleteVertexArrays(orphaned_vao_ct, orphaned_vao_ids.data()); + orphaned_vao_ids.clear(); + } + orphan_mutex.unlock(); + + glGenVertexArrays(1, &new_vao_id); + return new_vao_id; + } + +void vao_id_free(GLuint vao_id) + { + if (thread_is_main()) + glDeleteVertexArrays(1, &vao_id); + else + { + // add this ID to the orphaned list + orphan_mutex.lock(); +#if ORPHAN_DEBUG + printf("orphaning VAO %u\n", vao_id); +#endif + orphaned_vao_ids.emplace_back(vao_id); + orphan_mutex.unlock(); + } + } diff --git a/source/blender/gpu/gawain/buffer_id.h b/source/blender/gpu/gawain/buffer_id.h new file mode 100644 index 00000000000..3f67458d060 --- /dev/null +++ b/source/blender/gpu/gawain/buffer_id.h @@ -0,0 +1,34 @@ + +// Gawain buffer IDs +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// Manage GL buffer IDs in a thread-safe way +// Use these instead of glGenBuffers & its friends +// - alloc must be called from main thread +// - free can be called from any thread + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common.h" + +GLuint buffer_id_alloc(void); +void buffer_id_free(GLuint buffer_id); + +GLuint vao_id_alloc(void); +void vao_id_free(GLuint vao_id); + + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/gpu/gawain/common.h b/source/blender/gpu/gawain/common.h new file mode 100644 index 00000000000..90340b94e4d --- /dev/null +++ b/source/blender/gpu/gawain/common.h @@ -0,0 +1,58 @@ + +// Gawain common #defines and #includes +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// #define TRUST_NO_ONE !defined(NDEBUG) +#define TRUST_NO_ONE 1 +// strict error checking, always enabled during early development + +#include <GL/glew.h> +#include <stdbool.h> +#include <stdint.h> + +#if TRUST_NO_ONE + #include <assert.h> +#endif + +#define PER_THREAD +// #define PER_THREAD __thread +// MSVC uses __declspec(thread) for C code + +#define APPLE_LEGACY (defined(__APPLE__) && defined(WITH_GL_PROFILE_COMPAT)) + +#if APPLE_LEGACY + #undef glGenVertexArrays + #define glGenVertexArrays glGenVertexArraysAPPLE + + #undef glDeleteVertexArrays + #define glDeleteVertexArrays glDeleteVertexArraysAPPLE + + #undef glBindVertexArray + #define glBindVertexArray glBindVertexArrayAPPLE +#endif + +typedef enum { + PRIM_POINTS = GL_POINTS, + PRIM_LINES = GL_LINES, + PRIM_TRIANGLES = GL_TRIANGLES, + +#ifdef WITH_GL_PROFILE_COMPAT + PRIM_QUADS = GL_QUADS, // legacy GL has this, modern GL & Vulkan do not +#endif + + PRIM_LINE_STRIP = GL_LINE_STRIP, + PRIM_LINE_LOOP = GL_LINE_LOOP, // GL has this, Vulkan does not + PRIM_TRIANGLE_STRIP = GL_TRIANGLE_STRIP, + PRIM_TRIANGLE_FAN = GL_TRIANGLE_FAN, + + PRIM_NONE = 0xF +} PrimitiveType; diff --git a/source/blender/gpu/gawain/element.c b/source/blender/gpu/gawain/element.c new file mode 100644 index 00000000000..3c3ca1c7626 --- /dev/null +++ b/source/blender/gpu/gawain/element.c @@ -0,0 +1,283 @@ + +// Gawain element list (AKA index buffer) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "element.h" +#include "buffer_id.h" +#include <stdlib.h> + +#define KEEP_SINGLE_COPY 1 + +unsigned ElementList_size(const ElementList* elem) + { +#if TRACK_INDEX_RANGE + switch (elem->index_type) + { + case INDEX_U8: return elem->index_ct * sizeof(GLubyte); + case INDEX_U16: return elem->index_ct * sizeof(GLushort); + case INDEX_U32: return elem->index_ct * sizeof(GLuint); + default: + #if TRUST_NO_ONE + assert(false); + #endif + return 0; + } + +#else + return elem->index_ct * sizeof(GLuint); +#endif + } + +static void ElementList_prime(ElementList* elem) + { + elem->vbo_id = buffer_id_alloc(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); + // fill with delicious data & send to GPU the first time only + glBufferData(GL_ELEMENT_ARRAY_BUFFER, ElementList_size(elem), elem->data, GL_STATIC_DRAW); + +#if KEEP_SINGLE_COPY + // now that GL has a copy, discard original + free(elem->data); + elem->data = NULL; +#endif + } + +void ElementList_use(ElementList* elem) + { + if (elem->vbo_id) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); + else + ElementList_prime(elem); + } + +void ElementListBuilder_init(ElementListBuilder* builder, PrimitiveType prim_type, unsigned prim_ct, unsigned vertex_ct) + { + unsigned verts_per_prim = 0; + switch (prim_type) + { + case PRIM_POINTS: + verts_per_prim = 1; + break; + case PRIM_LINES: + verts_per_prim = 2; + break; + case PRIM_TRIANGLES: + verts_per_prim = 3; + break; + default: +#if TRUST_NO_ONE + assert(false); +#endif + return; + } + + builder->max_allowed_index = vertex_ct - 1; + builder->max_index_ct = prim_ct * verts_per_prim; + builder->index_ct = 0; // start empty + builder->prim_type = prim_type; + builder->data = calloc(builder->max_index_ct, sizeof(unsigned)); + } + +void add_generic_vertex(ElementListBuilder* builder, unsigned v) + { +#if TRUST_NO_ONE + assert(builder->data != NULL); + assert(builder->index_ct < builder->max_index_ct); + assert(v <= builder->max_allowed_index); +#endif + + builder->data[builder->index_ct++] = v; + } + +void add_point_vertex(ElementListBuilder* builder, unsigned v) + { +#if TRUST_NO_ONE + assert(builder->prim_type == PRIM_POINTS); +#endif + + add_generic_vertex(builder, v); + } + +void add_line_vertices(ElementListBuilder* builder, unsigned v1, unsigned v2) + { +#if TRUST_NO_ONE + assert(builder->prim_type == PRIM_LINES); + assert(v1 != v2); +#endif + + add_generic_vertex(builder, v1); + add_generic_vertex(builder, v2); + } + +void add_triangle_vertices(ElementListBuilder* builder, unsigned v1, unsigned v2, unsigned v3) + { +#if TRUST_NO_ONE + assert(builder->prim_type == PRIM_TRIANGLES); + assert(v1 != v2 && v2 != v3 && v3 != v1); +#endif + + add_generic_vertex(builder, v1); + add_generic_vertex(builder, v2); + add_generic_vertex(builder, v3); + } + +#if TRACK_INDEX_RANGE +// Everything remains 32 bit while building to keep things simple. +// Find min/max after, then convert to smallest index type possible. + +static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned* min_out, unsigned* max_out) + { + unsigned min_value = values[0]; + unsigned max_value = values[0]; + for (unsigned i = 1; i < value_ct; ++i) + { + const unsigned value = values[i]; + if (value < min_value) + min_value = value; + else if (value > max_value) + max_value = value; + } + *min_out = min_value; + *max_out = max_value; + return max_value - min_value; + } + +static void squeeze_indices_byte(const unsigned values[], ElementList* elem) + { + const unsigned index_ct = elem->index_ct; + GLubyte* data = malloc(index_ct * sizeof(GLubyte)); + + if (elem->max_index > 0xFF) + { + const unsigned base = elem->min_index; + + elem->base_index = base; + elem->min_index = 0; + elem->max_index -= base; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLubyte)(values[i] - base); + } + else + { + elem->base_index = 0; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLubyte)(values[i]); + } + + elem->data = data; + } + +static void squeeze_indices_short(const unsigned values[], ElementList* elem) + { + const unsigned index_ct = elem->index_ct; + GLushort* data = malloc(index_ct * sizeof(GLushort)); + + if (elem->max_index > 0xFFFF) + { + const unsigned base = elem->min_index; + + elem->base_index = base; + elem->min_index = 0; + elem->max_index -= base; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLushort)(values[i] - base); + } + else + { + elem->base_index = 0; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLushort)(values[i]); + } + + elem->data = data; + } + +#endif // TRACK_INDEX_RANGE + +ElementList* ElementList_build(ElementListBuilder* builder) + { + ElementList* elem = calloc(1, sizeof(ElementList)); + ElementList_build_in_place(builder, elem); + return elem; + } + +void ElementList_build_in_place(ElementListBuilder* builder, ElementList* elem) + { +#if TRUST_NO_ONE + assert(builder->data != NULL); +#endif + + elem->index_ct = builder->index_ct; + +#if TRACK_INDEX_RANGE + const unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index); + + if (range <= 0xFF) + { + elem->index_type = INDEX_U8; + squeeze_indices_byte(builder->data, elem); + } + else if (range <= 0xFFFF) + { + elem->index_type = INDEX_U16; + squeeze_indices_short(builder->data, elem); + } + else + { + elem->index_type = INDEX_U32; + elem->base_index = 0; + + if (builder->index_ct < builder->max_index_ct) + { + builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned)); + // TODO: realloc only if index_ct is much smaller than max_index_ct + } + + elem->data = builder->data; + } +#else + if (builder->index_ct < builder->max_index_ct) + { + builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned)); + // TODO: realloc only if index_ct is much smaller than max_index_ct + } + + elem->data = builder->data; +#endif + + // elem->data will never be *larger* than builder->data... how about converting + // in place to avoid extra allocation? + + elem->vbo_id = 0; + // TODO: create GL buffer object directly, based on an input flag + + // discard builder (one-time use) + if (builder->data != elem->data) + free(builder->data); + builder->data = NULL; + // other fields are safe to leave + } + +void ElementList_discard(ElementList* elem) + { + if (elem->vbo_id) + buffer_id_free(elem->vbo_id); +#if KEEP_SINGLE_COPY + else +#endif + if (elem->data) + free(elem->data); + + free(elem); + } diff --git a/source/blender/gpu/gawain/element.h b/source/blender/gpu/gawain/element.h new file mode 100644 index 00000000000..4e0d5fb0649 --- /dev/null +++ b/source/blender/gpu/gawain/element.h @@ -0,0 +1,64 @@ + +// Gawain element list (AKA index buffer) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +#define TRACK_INDEX_RANGE 1 + +typedef enum { + INDEX_U8 = GL_UNSIGNED_BYTE, // GL has this, Vulkan does not + INDEX_U16 = GL_UNSIGNED_SHORT, + INDEX_U32 = GL_UNSIGNED_INT +} IndexType; + +typedef struct { + unsigned index_ct; +#if TRACK_INDEX_RANGE + IndexType index_type; + unsigned min_index; + unsigned max_index; + unsigned base_index; +#endif + void* data; // NULL indicates data in VRAM (unmapped) or not yet allocated + GLuint vbo_id; // 0 indicates not yet sent to VRAM +} ElementList; + +void ElementList_use(ElementList*); +unsigned ElementList_size(const ElementList*); + +typedef struct { + unsigned max_allowed_index; + unsigned max_index_ct; + unsigned index_ct; + PrimitiveType prim_type; + unsigned* data; +} ElementListBuilder; + +// supported primitives: +// PRIM_POINTS +// PRIM_LINES +// PRIM_TRIANGLES + +void ElementListBuilder_init(ElementListBuilder*, PrimitiveType, unsigned prim_ct, unsigned vertex_ct); +//void ElementListBuilder_init_custom(ElementListBuilder*, PrimitiveType, unsigned index_ct, unsigned vertex_ct); + +void add_generic_vertex(ElementListBuilder*, unsigned v); + +void add_point_vertex(ElementListBuilder*, unsigned v); +void add_line_vertices(ElementListBuilder*, unsigned v1, unsigned v2); +void add_triangle_vertices(ElementListBuilder*, unsigned v1, unsigned v2, unsigned v3); + +ElementList* ElementList_build(ElementListBuilder*); +void ElementList_build_in_place(ElementListBuilder*, ElementList*); + +void ElementList_discard(ElementList*); diff --git a/source/blender/gpu/gawain/imm_util.c b/source/blender/gpu/gawain/imm_util.c new file mode 100644 index 00000000000..74caeb6fd3a --- /dev/null +++ b/source/blender/gpu/gawain/imm_util.c @@ -0,0 +1,46 @@ + +// Gawain immediate mode drawing utilities +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "imm_util.h" +#include "immediate.h" + + +void immRectf(unsigned pos, float x1, float y1, float x2, float y2) +{ + immBegin(PRIM_TRIANGLE_FAN, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x1, y2); + immEnd(); +} + +void immRecti(unsigned pos, int x1, int y1, int x2, int y2) +{ + immBegin(PRIM_TRIANGLE_FAN, 4); + immVertex2i(pos, x1, y1); + immVertex2i(pos, x2, y1); + immVertex2i(pos, x2, y2); + immVertex2i(pos, x1, y2); + immEnd(); +} + +#if 0 // more complete version in case we want that +void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4]) +{ + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(color); + immRecti(pos, x1, y1, x2, y2); + immUnbindProgram(); +} +#endif diff --git a/source/blender/gpu/gawain/imm_util.h b/source/blender/gpu/gawain/imm_util.h new file mode 100644 index 00000000000..730bd7c1a3c --- /dev/null +++ b/source/blender/gpu/gawain/imm_util.h @@ -0,0 +1,18 @@ + +// Gawain immediate mode drawing utilities +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + + +// Draw 2D rectangles (replaces glRect functions) +// caller is reponsible for vertex format & shader +void immRectf(unsigned pos, float x1, float y1, float x2, float y2); +void immRecti(unsigned pos, int x1, int y1, int x2, int y2); diff --git a/source/blender/gpu/gawain/immediate.c b/source/blender/gpu/gawain/immediate.c new file mode 100644 index 00000000000..03e16ca248e --- /dev/null +++ b/source/blender/gpu/gawain/immediate.c @@ -0,0 +1,813 @@ + +// Gawain immediate mode work-alike +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "immediate.h" +#include "attrib_binding.h" +#include "buffer_id.h" +#include <string.h> + +// necessary functions from matrix API +extern void gpuBindMatrices(GLuint program); +extern bool gpuMatricesDirty(void); + +typedef struct { + // TODO: organize this struct by frequency of change (run-time) + +#if IMM_BATCH_COMBO + Batch* batch; +#endif + + // current draw call + GLubyte* buffer_data; + unsigned buffer_offset; + unsigned buffer_bytes_mapped; + unsigned vertex_ct; + bool strict_vertex_ct; + PrimitiveType prim_type; + + VertexFormat vertex_format; + + // current vertex + unsigned vertex_idx; + GLubyte* vertex_data; + uint16_t unassigned_attrib_bits; // which attributes of current vertex have not been given values? + + GLuint vbo_id; + GLuint vao_id; + + GLuint bound_program; + AttribBinding attrib_binding; + uint16_t prev_enabled_attrib_bits; // <-- only affects this VAO, so we're ok +} Immediate; + +// size of internal buffer -- make this adjustable? +#define IMM_BUFFER_SIZE (4 * 1024 * 1024) + +static PER_THREAD bool initialized = false; +static PER_THREAD Immediate imm; + +void immInit() + { +#if TRUST_NO_ONE + assert(!initialized); +#endif + + memset(&imm, 0, sizeof(Immediate)); + + imm.vbo_id = buffer_id_alloc(); + glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); + +#if APPLE_LEGACY + glBufferParameteriAPPLE(GL_ARRAY_BUFFER, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); + glBufferParameteriAPPLE(GL_ARRAY_BUFFER, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); +#endif + + imm.prim_type = PRIM_NONE; + imm.strict_vertex_ct = true; + + glBindBuffer(GL_ARRAY_BUFFER, 0); + initialized = true; + + immActivate(); + } + +void immActivate() + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == PRIM_NONE); // make sure we're not between a Begin/End pair + assert(imm.vao_id == 0); +#endif + + imm.vao_id = vao_id_alloc(); + } + +void immDeactivate() + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == PRIM_NONE); // make sure we're not between a Begin/End pair + assert(imm.vao_id != 0); +#endif + + vao_id_free(imm.vao_id); + imm.vao_id = 0; + imm.prev_enabled_attrib_bits = 0; + } + +void immDestroy() + { + immDeactivate(); + buffer_id_free(imm.vbo_id); + initialized = false; + } + +VertexFormat* immVertexFormat() + { + VertexFormat_clear(&imm.vertex_format); + return &imm.vertex_format; + } + +void immBindProgram(GLuint program) + { +#if TRUST_NO_ONE + assert(imm.bound_program == 0); + assert(glIsProgram(program)); +#endif + + if (!imm.vertex_format.packed) + VertexFormat_pack(&imm.vertex_format); + + glUseProgram(program); + get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, program); + imm.bound_program = program; + + gpuBindMatrices(program); + } + +void immUnbindProgram() + { +#if TRUST_NO_ONE + assert(imm.bound_program != 0); +#endif + + glUseProgram(0); + imm.bound_program = 0; + } + +static bool vertex_count_makes_sense_for_primitive(unsigned vertex_ct, PrimitiveType prim_type) + { + // does vertex_ct make sense for this primitive type? + if (vertex_ct == 0) + return false; + + switch (prim_type) + { + case PRIM_POINTS: + return true; + case PRIM_LINES: + return vertex_ct % 2 == 0; + case PRIM_LINE_STRIP: + case PRIM_LINE_LOOP: + return vertex_ct >= 2; + case PRIM_TRIANGLES: + return vertex_ct % 3 == 0; + case PRIM_TRIANGLE_STRIP: + case PRIM_TRIANGLE_FAN: + return vertex_ct >= 3; + #ifdef WITH_GL_PROFILE_COMPAT + case PRIM_QUADS: + return vertex_ct % 4 == 0; + #endif + default: + return false; + } + } + +void immBegin(PrimitiveType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == PRIM_NONE); // make sure we haven't already begun + assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type)); +#endif + + imm.prim_type = prim_type; + imm.vertex_ct = vertex_ct; + imm.vertex_idx = 0; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + + // how many bytes do we need for this draw call? + const unsigned bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_ct); + +#if TRUST_NO_ONE + assert(bytes_needed <= IMM_BUFFER_SIZE); +#endif + + glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + + // does the current buffer have enough room? + const unsigned available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset; + // ensure vertex data is aligned + const unsigned pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); // might waste a little space, but it's safe + if ((bytes_needed + pre_padding) <= available_bytes) + imm.buffer_offset += pre_padding; + else + { + // orphan this buffer & start with a fresh one +#if APPLE_LEGACY + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); +#else + if (GLEW_VERSION_4_3 || GLEW_ARB_invalidate_subdata) + glInvalidateBufferData(imm.vbo_id); + else + glMapBufferRange(GL_ARRAY_BUFFER, 0, IMM_BUFFER_SIZE, GL_MAP_INVALIDATE_BUFFER_BIT); +#endif + + imm.buffer_offset = 0; + } + +// printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); + +#if APPLE_LEGACY + imm.buffer_data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY) + imm.buffer_offset; +#else + imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed, + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_ct ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)); +#endif + +#if TRUST_NO_ONE + assert(imm.buffer_data != NULL); +#endif + + imm.buffer_bytes_mapped = bytes_needed; + imm.vertex_data = imm.buffer_data; + } + +void immBeginAtMost(PrimitiveType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(vertex_ct > 0); +#endif + + imm.strict_vertex_ct = false; + immBegin(prim_type, vertex_ct); + } + +#if IMM_BATCH_COMBO + +Batch* immBeginBatch(PrimitiveType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == PRIM_NONE); // make sure we haven't already begun + assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type)); +#endif + + imm.prim_type = prim_type; + imm.vertex_ct = vertex_ct; + imm.vertex_idx = 0; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + + VertexBuffer* verts = VertexBuffer_create_with_format(&imm.vertex_format); + VertexBuffer_allocate_data(verts, vertex_ct); + + imm.buffer_bytes_mapped = VertexBuffer_size(verts); + imm.vertex_data = verts->data; + + imm.batch = Batch_create(prim_type, verts, NULL); + imm.batch->phase = BUILDING; + + Batch_set_program(imm.batch, imm.bound_program); + + return imm.batch; + } + +Batch* immBeginBatchAtMost(PrimitiveType prim_type, unsigned vertex_ct) + { + imm.strict_vertex_ct = false; + return immBeginBatch(prim_type, vertex_ct); + } + +#endif // IMM_BATCH_COMBO + +static void immDrawSetup(void) + { + // set up VAO -- can be done during Begin or End really + glBindVertexArray(imm.vao_id); + + // enable/disable vertex attribs as needed + if (imm.attrib_binding.enabled_bits != imm.prev_enabled_attrib_bits) + { + for (unsigned loc = 0; loc < MAX_VERTEX_ATTRIBS; ++loc) + { + bool is_enabled = imm.attrib_binding.enabled_bits & (1 << loc); + bool was_enabled = imm.prev_enabled_attrib_bits & (1 << loc); + + if (is_enabled && !was_enabled) + { +// printf("enabling attrib %u\n", loc); + glEnableVertexAttribArray(loc); + } + else if (was_enabled && !is_enabled) + { +// printf("disabling attrib %u\n", loc); + glDisableVertexAttribArray(loc); + } + } + + imm.prev_enabled_attrib_bits = imm.attrib_binding.enabled_bits; + } + + const unsigned stride = imm.vertex_format.stride; + + for (unsigned a_idx = 0; a_idx < imm.vertex_format.attrib_ct; ++a_idx) + { + const Attrib* a = imm.vertex_format.attribs + a_idx; + + const unsigned offset = imm.buffer_offset + a->offset; + const GLvoid* pointer = (const GLubyte*)0 + offset; + + const unsigned loc = read_attrib_location(&imm.attrib_binding, a_idx); + +// printf("specifying attrib %u '%s' with offset %u, stride %u\n", loc, a->name, offset, stride); + + switch (a->fetch_mode) + { + case KEEP_FLOAT: + case CONVERT_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_FALSE, stride, pointer); + break; + case NORMALIZE_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->comp_type, GL_TRUE, stride, pointer); + break; + case KEEP_INT: + glVertexAttribIPointer(loc, a->comp_ct, a->comp_type, stride, pointer); + } + } + + if (gpuMatricesDirty()) + gpuBindMatrices(imm.bound_program); + } + +void immEnd() + { +#if TRUST_NO_ONE + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + unsigned buffer_bytes_used; + if (imm.strict_vertex_ct) + { +#if TRUST_NO_ONE + assert(imm.vertex_idx == imm.vertex_ct); // with all vertices defined +#endif + buffer_bytes_used = imm.buffer_bytes_mapped; + } + else + { +#if TRUST_NO_ONE + assert(imm.vertex_idx <= imm.vertex_ct); +#endif + // printf("used %u of %u verts,", imm.vertex_idx, imm.vertex_ct); + if (imm.vertex_idx == imm.vertex_ct) + { + buffer_bytes_used = imm.buffer_bytes_mapped; + } + else + { +#if TRUST_NO_ONE + assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type)); +#endif + imm.vertex_ct = imm.vertex_idx; + buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_ct); + // unused buffer bytes are available to the next immBegin + // printf(" %u of %u bytes\n", buffer_bytes_used, imm.buffer_bytes_mapped); + } +#if !APPLE_LEGACY + // tell OpenGL what range was modified so it doesn't copy the whole mapped range + // printf("flushing %u to %u\n", imm.buffer_offset, imm.buffer_offset + buffer_bytes_used - 1); + glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used); +#endif + } + +#if IMM_BATCH_COMBO + if (imm.batch) + { + if (buffer_bytes_used != imm.buffer_bytes_mapped) + { + VertexBuffer_resize_data(imm.batch->verts, imm.vertex_ct); + // TODO: resize only if vertex count is much smaller + } + + imm.batch->phase = READY_TO_DRAW; + imm.batch = NULL; // don't free, batch belongs to caller + } + else +#endif + { +#if APPLE_LEGACY + // tell OpenGL what range was modified so it doesn't copy the whole buffer + // printf("flushing %u to %u\n", imm.buffer_offset, imm.buffer_offset + buffer_bytes_used - 1); + glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER, imm.buffer_offset, buffer_bytes_used); +#endif + glUnmapBuffer(GL_ARRAY_BUFFER); + + if (imm.vertex_ct > 0) + { + immDrawSetup(); + glDrawArrays(imm.prim_type, 0, imm.vertex_ct); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + // prep for next immBegin + imm.buffer_offset += buffer_bytes_used; + } + + // prep for next immBegin + imm.prim_type = PRIM_NONE; + imm.strict_vertex_ct = true; + } + +static void setAttribValueBit(unsigned attrib_id) + { + uint16_t mask = 1 << attrib_id; + +#if TRUST_NO_ONE + assert(imm.unassigned_attrib_bits & mask); // not already set +#endif + + imm.unassigned_attrib_bits &= ~mask; + } + + +// --- generic attribute functions --- + +void immAttrib1f(unsigned attrib_id, float x) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_F32); + assert(attrib->comp_ct == 1); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + } + +void immAttrib2f(unsigned attrib_id, float x, float y) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_F32); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + } + +void immAttrib3f(unsigned attrib_id, float x, float y, float z) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_F32); + assert(attrib->comp_ct == 3); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + data[2] = z; + } + +void immAttrib4f(unsigned attrib_id, float x, float y, float z, float w) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_F32); + assert(attrib->comp_ct == 4); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = w; + } + +void immAttrib2i(unsigned attrib_id, int x, int y) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_I32); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + int* data = (int*)(imm.vertex_data + attrib->offset); + + data[0] = x; + data[1] = y; + } + +void immAttrib2s(unsigned attrib_id, short x, short y) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_I16); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + short* data = (short*)(imm.vertex_data + attrib->offset); + + data[0] = x; + data[1] = y; + } + +void immAttrib3fv(unsigned attrib_id, const float data[3]) + { + immAttrib3f(attrib_id, data[0], data[1], data[2]); + } + +void immAttrib4fv(unsigned attrib_id, const float data[4]) + { + immAttrib4f(attrib_id, data[0], data[1], data[2], data[3]); + } + +void immAttrib3ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_U8); + assert(attrib->comp_ct == 3); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + GLubyte* data = imm.vertex_data + attrib->offset; +// printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); + + data[0] = r; + data[1] = g; + data[2] = b; + } + +void immAttrib4ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + Attrib* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == COMP_U8); + assert(attrib->comp_ct == 4); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + GLubyte* data = imm.vertex_data + attrib->offset; +// printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); + + data[0] = r; + data[1] = g; + data[2] = b; + data[3] = a; + } + +void immAttrib3ubv(unsigned attrib_id, const unsigned char data[3]) + { + immAttrib3ub(attrib_id, data[0], data[1], data[2]); + } + +void immAttrib4ubv(unsigned attrib_id, const unsigned char data[4]) + { + immAttrib4ub(attrib_id, data[0], data[1], data[2], data[3]); + } + +void immSkipAttrib(unsigned attrib_id) + { +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + } + +static void immEndVertex(void) // and move on to the next vertex + { +#if TRUST_NO_ONE + assert(imm.prim_type != PRIM_NONE); // make sure we're between a Begin/End pair + assert(imm.vertex_idx < imm.vertex_ct); +#endif + + // have all attribs been assigned values? + // if not, copy value from previous vertex + if (imm.unassigned_attrib_bits) + { +#if TRUST_NO_ONE + assert(imm.vertex_idx > 0); // first vertex must have all attribs specified +#endif + + for (unsigned a_idx = 0; a_idx < imm.vertex_format.attrib_ct; ++a_idx) + { + if ((imm.unassigned_attrib_bits >> a_idx) & 1) + { + const Attrib* a = imm.vertex_format.attribs + a_idx; + +// printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx); + + GLubyte* data = imm.vertex_data + a->offset; + memcpy(data, data - imm.vertex_format.stride, a->sz); + // TODO: consolidate copy of adjacent attributes + } + } + } + + imm.vertex_idx++; + imm.vertex_data += imm.vertex_format.stride; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + } + +void immVertex2f(unsigned attrib_id, float x, float y) + { + immAttrib2f(attrib_id, x, y); + immEndVertex(); + } + +void immVertex3f(unsigned attrib_id, float x, float y, float z) + { + immAttrib3f(attrib_id, x, y, z); + immEndVertex(); + } + +void immVertex2i(unsigned attrib_id, int x, int y) + { + immAttrib2i(attrib_id, x, y); + immEndVertex(); + } + +void immVertex2s(unsigned attrib_id, short x, short y) + { + immAttrib2s(attrib_id, x, y); + immEndVertex(); + } + +void immVertex2fv(unsigned attrib_id, const float data[2]) + { + immAttrib2f(attrib_id, data[0], data[1]); + immEndVertex(); + } + +void immVertex3fv(unsigned attrib_id, const float data[3]) + { + immAttrib3f(attrib_id, data[0], data[1], data[2]); + immEndVertex(); + } + +void immVertex2iv(unsigned attrib_id, const int data[2]) + { + immAttrib2i(attrib_id, data[0], data[1]); + immEndVertex(); + } + + +// --- generic uniform functions --- + +void immUniform1f(const char* name, float x) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform1f(loc, x); + } + +void immUniform4f(const char* name, float x, float y, float z, float w) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform4f(loc, x, y, z, w); + } + +void immUniform4fv(const char* name, const float data[4]) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform4fv(loc, 1, data); + } + +void immUniform1i(const char* name, int x) + { + int loc = glGetUniformLocation(imm.bound_program, name); + +#if TRUST_NO_ONE + assert(loc != -1); +#endif + + glUniform1i(loc, x); + } + + +// --- convenience functions for setting "uniform vec4 color" --- + +void immUniformColor4f(float r, float g, float b, float a) + { + immUniform4f("color", r, g, b, a); + } + +void immUniformColor4fv(const float rgba[4]) + { + immUniform4fv("color", rgba); + } + +void immUniformColor3f(float r, float g, float b) + { + immUniform4f("color", r, g, b, 1.0f); + } + +void immUniformColor3fv(const float rgb[3]) + { + immUniform4f("color", rgb[0], rgb[1], rgb[2], 1.0f); + } + +void immUniformColor3fvAlpha(const float rgb[3], float a) + { + immUniform4f("color", rgb[0], rgb[1], rgb[2], a); + } + +// TODO: v-- treat as sRGB? --v + +void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b) + { + const float scale = 1.0f / 255.0f; + immUniform4f("color", scale * r, scale * g, scale * b, 1.0f); + } + +void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + const float scale = 1.0f / 255.0f; + immUniform4f("color", scale * r, scale * g, scale * b, scale * a); + } + +void immUniformColor3ubv(const unsigned char rgb[3]) + { + immUniformColor3ub(rgb[0], rgb[1], rgb[2]); + } + +void immUniformColor4ubv(const unsigned char rgba[4]) + { + immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]); + } diff --git a/source/blender/gpu/gawain/immediate.h b/source/blender/gpu/gawain/immediate.h new file mode 100644 index 00000000000..50965d3d36c --- /dev/null +++ b/source/blender/gpu/gawain/immediate.h @@ -0,0 +1,105 @@ + +// Gawain immediate mode work-alike +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" + +#define IMM_BATCH_COMBO 1 + + +VertexFormat* immVertexFormat(void); // returns a cleared vertex format, ready for add_attrib + +void immBindProgram(GLuint program); // every immBegin must have a program bound first +void immUnbindProgram(void); // call after your last immEnd, or before binding another program + +void immBegin(PrimitiveType, unsigned vertex_ct); // must supply exactly vertex_ct vertices +void immBeginAtMost(PrimitiveType, unsigned max_vertex_ct); // can supply fewer vertices +void immEnd(void); // finishes and draws + +#if IMM_BATCH_COMBO +#include "batch.h" +// immBegin a batch, then use standard immFunctions as usual. +// immEnd will finalize the batch instead of drawing. +// Then you can draw it as many times as you like! Partially replaces the need for display lists. +Batch* immBeginBatch(PrimitiveType, unsigned vertex_ct); +Batch* immBeginBatchAtMost(PrimitiveType, unsigned vertex_ct); +#endif + + +// provide attribute values that can change per vertex +// first vertex after immBegin must have all its attributes specified +// skipped attributes will continue using the previous value for that attrib_id +void immAttrib1f(unsigned attrib_id, float x); +void immAttrib2f(unsigned attrib_id, float x, float y); +void immAttrib3f(unsigned attrib_id, float x, float y, float z); +void immAttrib4f(unsigned attrib_id, float x, float y, float z, float w); + +void immAttrib2i(unsigned attrib_id, int x, int y); + +void immAttrib2s(unsigned attrib_id, short x, short y); + +void immAttrib3fv(unsigned attrib_id, const float data[3]); +void immAttrib4fv(unsigned attrib_id, const float data[4]); + +void immAttrib3ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b); +void immAttrib4ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +void immAttrib3ubv(unsigned attrib_id, const unsigned char data[4]); +void immAttrib4ubv(unsigned attrib_id, const unsigned char data[4]); + +// explicitly skip an attribute +// this advanced option kills automatic value copying for this attrib_id +void immSkipAttrib(unsigned attrib_id); + + +// provide one last attribute value & end the current vertex +// this is most often used for 2D or 3D position (similar to glVertex) +void immVertex2f(unsigned attrib_id, float x, float y); +void immVertex3f(unsigned attrib_id, float x, float y, float z); + +void immVertex2i(unsigned attrib_id, int x, int y); + +void immVertex2s(unsigned attrib_id, short x, short y); + +void immVertex2fv(unsigned attrib_id, const float data[2]); +void immVertex3fv(unsigned attrib_id, const float data[3]); + +void immVertex2iv(unsigned attrib_id, const int data[2]); + + +// provide uniform values that don't change for the entire draw call +void immUniform1i(const char* name, int x); +void immUniform1f(const char* name, float x); +void immUniform4f(const char* name, float x, float y, float z, float w); +void immUniform4fv(const char* name, const float data[4]); + + +// convenience functions for setting "uniform vec4 color" +// the rgb functions have implicit alpha = 1.0 +void immUniformColor4f(float r, float g, float b, float a); +void immUniformColor4fv(const float rgba[4]); +void immUniformColor3f(float r, float g, float b); +void immUniformColor3fv(const float rgb[3]); +void immUniformColor3fvAlpha(const float rgb[3], float a); + +void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b); +void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); +void immUniformColor3ubv(const unsigned char rgb[3]); +void immUniformColor4ubv(const unsigned char rgba[4]); + + +// these are called by the system -- not part of drawing API + +void immInit(void); +void immActivate(void); +void immDeactivate(void); +void immDestroy(void); diff --git a/source/blender/gpu/gawain/vertex_buffer.c b/source/blender/gpu/gawain/vertex_buffer.c new file mode 100644 index 00000000000..5f2da60067d --- /dev/null +++ b/source/blender/gpu/gawain/vertex_buffer.c @@ -0,0 +1,170 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "vertex_buffer.h" +#include "buffer_id.h" +#include <stdlib.h> +#include <string.h> + +#define KEEP_SINGLE_COPY 1 + +VertexBuffer* VertexBuffer_create() + { + VertexBuffer* verts = malloc(sizeof(VertexBuffer)); + VertexBuffer_init(verts); + return verts; + } + +VertexBuffer* VertexBuffer_create_with_format(const VertexFormat* format) + { + VertexBuffer* verts = VertexBuffer_create(); + VertexFormat_copy(&verts->format, format); + if (!format->packed) + VertexFormat_pack(&verts->format); + return verts; + + // this function might seem redundant, but there is potential for memory savings here... + // TODO: implement those memory savings + } + +void VertexBuffer_init(VertexBuffer* verts) + { + memset(verts, 0, sizeof(VertexBuffer)); + } + +void VertexBuffer_init_with_format(VertexBuffer* verts, const VertexFormat* format) + { + VertexBuffer_init(verts); + VertexFormat_copy(&verts->format, format); + if (!format->packed) + VertexFormat_pack(&verts->format); + } + +void VertexBuffer_discard(VertexBuffer* verts) + { + if (verts->vbo_id) + buffer_id_free(verts->vbo_id); +#if KEEP_SINGLE_COPY + else +#endif + if (verts->data) + free(verts->data); + + free(verts); + } + +unsigned VertexBuffer_size(const VertexBuffer* verts) + { + return vertex_buffer_size(&verts->format, verts->vertex_ct); + } + +void VertexBuffer_allocate_data(VertexBuffer* verts, unsigned v_ct) + { + VertexFormat* format = &verts->format; + if (!format->packed) + VertexFormat_pack(format); + + verts->vertex_ct = v_ct; + + // Data initially lives in main memory. Will be transferred to VRAM when we "prime" it. + verts->data = malloc(VertexBuffer_size(verts)); + } + +void VertexBuffer_resize_data(VertexBuffer* verts, unsigned v_ct) + { +#if TRUST_NO_ONE + assert(verts->vertex_ct != v_ct); // allow this? + assert(verts->data != NULL); // has already been allocated + assert(verts->vbo_id == 0); // has not been sent to VRAM +#endif + + verts->vertex_ct = v_ct; + verts->data = realloc(verts->data, VertexBuffer_size(verts)); + // TODO: skip realloc if v_ct < existing vertex count + // extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime) + } + +void setAttrib(VertexBuffer* verts, unsigned a_idx, unsigned v_idx, const void* data) + { + const VertexFormat* format = &verts->format; + const Attrib* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); + assert(v_idx < verts->vertex_ct); + assert(verts->data != NULL); // data must be in main mem +#endif + + memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz); + } + +void fillAttrib(VertexBuffer* verts, unsigned a_idx, const void* data) + { + const VertexFormat* format = &verts->format; + const Attrib* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); +#endif + + const unsigned stride = a->sz; // tightly packed input data + + fillAttribStride(verts, a_idx, stride, data); + } + +void fillAttribStride(VertexBuffer* verts, unsigned a_idx, unsigned stride, const void* data) + { + const VertexFormat* format = &verts->format; + const Attrib* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); + assert(verts->data != NULL); // data must be in main mem +#endif + + const unsigned vertex_ct = verts->vertex_ct; + + if (format->attrib_ct == 1 && stride == format->stride) + { + // we can copy it all at once + memcpy(verts->data, data, vertex_ct * a->sz); + } + else + { + // we must copy it per vertex + for (unsigned v = 0; v < vertex_ct; ++v) + memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz); + } + } + +static void VertexBuffer_prime(VertexBuffer* verts) + { + const VertexFormat* format = &verts->format; + + verts->vbo_id = buffer_id_alloc(); + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + // fill with delicious data & send to GPU the first time only + glBufferData(GL_ARRAY_BUFFER, vertex_buffer_size(format, verts->vertex_ct), verts->data, GL_STATIC_DRAW); + +#if KEEP_SINGLE_COPY + // now that GL has a copy, discard original + free(verts->data); + verts->data = NULL; +#endif + } + +void VertexBuffer_use(VertexBuffer* verts) + { + if (verts->vbo_id) + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + else + VertexBuffer_prime(verts); + } diff --git a/source/blender/gpu/gawain/vertex_buffer.h b/source/blender/gpu/gawain/vertex_buffer.h new file mode 100644 index 00000000000..6a72cfe6ff3 --- /dev/null +++ b/source/blender/gpu/gawain/vertex_buffer.h @@ -0,0 +1,64 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" + +// How to create a VertexBuffer: +// 1) verts = create_VertexBuffer() or init_VertexBuffer(verts) +// 2) add_attrib(verts->format, ...) +// 3) allocate_vertex_data(verts, vertex_ct) <-- finalizes/packs vertex format +// 4) fillAttrib(verts, pos, application_pos_buffer) +// 5) prime_VertexBuffer(verts); + +// Is VertexBuffer always used as part of a Batch? + +typedef struct { + VertexFormat format; + unsigned vertex_ct; + GLubyte* data; // NULL indicates data in VRAM (unmapped) or not yet allocated + GLuint vbo_id; // 0 indicates not yet sent to VRAM +} VertexBuffer; + +VertexBuffer* VertexBuffer_create(void); +VertexBuffer* VertexBuffer_create_with_format(const VertexFormat*); + +void VertexBuffer_discard(VertexBuffer*); + +void VertexBuffer_init(VertexBuffer*); +void VertexBuffer_init_with_format(VertexBuffer*, const VertexFormat*); + +unsigned VertexBuffer_size(const VertexBuffer*); +void VertexBuffer_allocate_data(VertexBuffer*, unsigned v_ct); +void VertexBuffer_resize_data(VertexBuffer*, unsigned v_ct); + +// The most important setAttrib variant is the untyped one. Get it right first. +// It takes a void* so the app developer is responsible for matching their app data types +// to the vertex attribute's type and component count. They're in control of both, so this +// should not be a problem. + +void setAttrib(VertexBuffer*, unsigned a_idx, unsigned v_idx, const void* data); +void fillAttrib(VertexBuffer*, unsigned a_idx, const void* data); // tightly packed, non interleaved input data +void fillAttribStride(VertexBuffer*, unsigned a_idx, unsigned stride, const void* data); + +// TODO: decide whether to keep the functions below +// doesn't immediate mode satisfy these needs? + +// void setAttrib1f(unsigned a_idx, unsigned v_idx, float x); +// void setAttrib2f(unsigned a_idx, unsigned v_idx, float x, float y); +// void setAttrib3f(unsigned a_idx, unsigned v_idx, float x, float y, float z); +// void setAttrib4f(unsigned a_idx, unsigned v_idx, float x, float y, float z, float w); +// +// void setAttrib3ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b); +// void setAttrib4ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +void VertexBuffer_use(VertexBuffer*); diff --git a/source/blender/gpu/gawain/vertex_format.c b/source/blender/gpu/gawain/vertex_format.c new file mode 100644 index 00000000000..671b979a810 --- /dev/null +++ b/source/blender/gpu/gawain/vertex_format.c @@ -0,0 +1,246 @@ + +// Gawain vertex format +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "vertex_format.h" +#include <stdlib.h> +#include <string.h> + +#define PACK_DEBUG 0 + +#if PACK_DEBUG + #include <stdio.h> +#endif + +void VertexFormat_clear(VertexFormat* format) + { +#if TRUST_NO_ONE + memset(format, 0, sizeof(VertexFormat)); +#else + format->attrib_ct = 0; + format->packed = false; + format->name_offset = 0; +#endif + } + +void VertexFormat_copy(VertexFormat* dest, const VertexFormat* src) + { + // copy regular struct fields + memcpy(dest, src, sizeof(VertexFormat)); + } + +static unsigned comp_sz(VertexCompType type) + { +#if TRUST_NO_ONE + assert(type >= GL_BYTE && type <= GL_FLOAT); +#endif + + const GLubyte sizes[] = {1,1,2,2,4,4,4}; + return sizes[type - GL_BYTE]; + } + +static unsigned attrib_sz(const Attrib *a) + { +#if USE_10_10_10 + if (a->comp_type == COMP_I10) + return 4; // always packed as 10_10_10_2 +#endif + + return a->comp_ct * comp_sz(a->comp_type); + } + +static unsigned attrib_align(const Attrib *a) + { +#if USE_10_10_10 + if (a->comp_type == COMP_I10) + return 4; // always packed as 10_10_10_2 +#endif + + unsigned c = comp_sz(a->comp_type); + if (a->comp_ct == 3 && c <= 2) + return 4 * c; // AMD HW can't fetch these well, so pad it out (other vendors too?) + else + return c; // most fetches are ok if components are naturally aligned + } + +unsigned vertex_buffer_size(const VertexFormat* format, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(format->packed && format->stride > 0); +#endif + + return format->stride * vertex_ct; + } + +static const char* copy_attrib_name(VertexFormat* format, const char* name) + { + // strncpy does 110% of what we need; let's do exactly 100% + char* name_copy = format->names + format->name_offset; + unsigned available = VERTEX_ATTRIB_NAMES_BUFFER_LEN - format->name_offset; + bool terminated = false; + + for (unsigned i = 0; i < available; ++i) + { + const char c = name[i]; + name_copy[i] = c; + if (c == '\0') + { + terminated = true; + format->name_offset += (i + 1); + break; + } + } + +#if TRUST_NO_ONE + assert(terminated); + assert(format->name_offset <= VERTEX_ATTRIB_NAMES_BUFFER_LEN); +#endif + + return name_copy; + } + +unsigned add_attrib(VertexFormat* format, const char* name, VertexCompType comp_type, unsigned comp_ct, VertexFetchMode fetch_mode) + { +#if TRUST_NO_ONE + assert(format->attrib_ct < MAX_VERTEX_ATTRIBS); // there's room for more + assert(!format->packed); // packed means frozen/locked + assert(comp_ct >= 1 && comp_ct <= 4); + switch (comp_type) + { + case COMP_F32: + // float type can only kept as float + assert(fetch_mode == KEEP_FLOAT); + break; + #if USE_10_10_10 + case COMP_I10: + assert(comp_ct == 3); // 10_10_10 format intended for normals (xyz) or colors (rgb) + assert(fetch_mode == NORMALIZE_INT_TO_FLOAT); + break; + #endif + default: + // integer types can be kept as int or converted/normalized to float + assert(fetch_mode != KEEP_FLOAT); + } +#endif + + const unsigned attrib_id = format->attrib_ct++; + Attrib* attrib = format->attribs + attrib_id; + + attrib->name = copy_attrib_name(format, name); + attrib->comp_type = comp_type; +#if USE_10_10_10 + attrib->comp_ct = (comp_type == COMP_I10) ? 4 : comp_ct; // system needs 10_10_10_2 to be 4 or BGRA +#else + attrib->comp_ct = comp_ct; +#endif + attrib->sz = attrib_sz(attrib); + attrib->offset = 0; // offsets & stride are calculated later (during pack) + attrib->fetch_mode = fetch_mode; + + return attrib_id; + } + +unsigned padding(unsigned offset, unsigned alignment) + { + const unsigned mod = offset % alignment; + return (mod == 0) ? 0 : (alignment - mod); + } + +#if PACK_DEBUG +static void show_pack(unsigned a_idx, unsigned sz, unsigned pad) + { + const char c = 'A' + a_idx; + for (unsigned i = 0; i < pad; ++i) + putchar('-'); + for (unsigned i = 0; i < sz; ++i) + putchar(c); + } +#endif + +void VertexFormat_pack(VertexFormat* format) + { + // for now, attributes are packed in the order they were added, + // making sure each attrib is naturally aligned (add padding where necessary) + + // later we can implement more efficient packing w/ reordering + // (keep attrib ID order, adjust their offsets to reorder in buffer) + + // TODO: + // realloc just enough to hold the final combo string. And just enough to + // hold used attribs, not all 16. + + Attrib* a0 = format->attribs + 0; + a0->offset = 0; + unsigned offset = a0->sz; + +#if PACK_DEBUG + show_pack(0, a0->sz, 0); +#endif + + for (unsigned a_idx = 1; a_idx < format->attrib_ct; ++a_idx) + { + Attrib* a = format->attribs + a_idx; + unsigned mid_padding = padding(offset, attrib_align(a)); + offset += mid_padding; + a->offset = offset; + offset += a->sz; + +#if PACK_DEBUG + show_pack(a_idx, a->sz, mid_padding); +#endif + } + + unsigned end_padding = padding(offset, attrib_align(a0)); + +#if PACK_DEBUG + show_pack(0, 0, end_padding); + putchar('\n'); +#endif + + format->stride = offset + end_padding; + format->packed = true; + } + + +#if USE_10_10_10 + +// OpenGL ES packs in a different order as desktop GL but component conversion is the same. +// Of the code here, only struct PackedNormal needs to change. + +#define SIGNED_INT_10_MAX 511 +#define SIGNED_INT_10_MIN -512 + +static int clampi(int x, int min_allowed, int max_allowed) + { +#if TRUST_NO_ONE + assert(min_allowed <= max_allowed); +#endif + + if (x < min_allowed) + return min_allowed; + else if (x > max_allowed) + return max_allowed; + else + return x; + } + +static int quantize(float x) + { + int qx = x * 511.0f; + return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX); + } + +PackedNormal convert_i10_v3(const float data[3]) + { + PackedNormal n = { .x = quantize(data[0]), .y = quantize(data[1]), .z = quantize(data[2]) }; + return n; + } + +#endif // USE_10_10_10 diff --git a/source/blender/gpu/gawain/vertex_format.h b/source/blender/gpu/gawain/vertex_format.h new file mode 100644 index 00000000000..66477b0cfc7 --- /dev/null +++ b/source/blender/gpu/gawain/vertex_format.h @@ -0,0 +1,87 @@ + +// Gawain vertex format +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +#define MAX_VERTEX_ATTRIBS 16 +#define AVG_VERTEX_ATTRIB_NAME_LEN 5 +#define VERTEX_ATTRIB_NAMES_BUFFER_LEN ((AVG_VERTEX_ATTRIB_NAME_LEN + 1) * MAX_VERTEX_ATTRIBS) + +#define USE_10_10_10 defined(_WIN32) +// (GLEW_VERSION_3_3 || GLEW_ARB_vertex_type_2_10_10_10_rev) +// ^-- this is only guaranteed on Windows right now, will be true on all platforms soon + +typedef enum { + COMP_I8 = GL_BYTE, + COMP_U8 = GL_UNSIGNED_BYTE, + COMP_I16 = GL_SHORT, + COMP_U16 = GL_UNSIGNED_SHORT, + COMP_I32 = GL_INT, + COMP_U32 = GL_UNSIGNED_INT, + + COMP_F32 = GL_FLOAT, // TODO: drop the GL_ equivalence here, use a private lookup table + +#if USE_10_10_10 + COMP_I10 = GL_INT_2_10_10_10_REV +#endif +} VertexCompType; + +typedef enum { + KEEP_FLOAT, + KEEP_INT, + NORMALIZE_INT_TO_FLOAT, // 127 (ubyte) -> 0.5 (and so on for other int types) + CONVERT_INT_TO_FLOAT // 127 (any int type) -> 127.0 +} VertexFetchMode; + +typedef struct { + VertexCompType comp_type; + unsigned comp_ct; // 1 to 4 + unsigned sz; // size in bytes, 1 to 16 + unsigned offset; // from beginning of vertex, in bytes + VertexFetchMode fetch_mode; + const char* name; +} Attrib; + +typedef struct { + unsigned attrib_ct; // 0 to 16 (MAX_VERTEX_ATTRIBS) + unsigned stride; // stride in bytes, 1 to 256 + bool packed; + Attrib attribs[MAX_VERTEX_ATTRIBS]; // TODO: variable-size attribs array + char names[VERTEX_ATTRIB_NAMES_BUFFER_LEN]; + unsigned name_offset; +} VertexFormat; + +void VertexFormat_clear(VertexFormat*); +void VertexFormat_copy(VertexFormat* dest, const VertexFormat* src); + +unsigned add_attrib(VertexFormat*, const char* name, VertexCompType, unsigned comp_ct, VertexFetchMode); + +// format conversion + +#if USE_10_10_10 + +typedef struct { + int x : 10; + int y : 10; + int z : 10; + int w : 2; // ignored for our purposes +} PackedNormal; + +PackedNormal convert_i10_v3(const float data[3]); + +#endif // USE_10_10_10 + +// for internal use +void VertexFormat_pack(VertexFormat*); +unsigned padding(unsigned offset, unsigned alignment); +unsigned vertex_buffer_size(const VertexFormat*, unsigned vertex_ct); diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c index a2b89239344..9d1e84cd44e 100644 --- a/source/blender/gpu/intern/gpu_basic_shader.c +++ b/source/blender/gpu/intern/gpu_basic_shader.c @@ -269,7 +269,7 @@ const GLubyte stipple_hexagon[128] = { /* GLSL State */ -static bool USE_GLSL = false; +static bool USE_GLSL = true; /** * \note this isn't part of the basic shader API, @@ -422,23 +422,6 @@ void GPU_basic_shader_bind(int options) { if (USE_GLSL) { if (options) { - const int bound_options = GPU_MATERIAL_STATE.bound_options; - - /* texture options need to be set for basic shader too */ - if (options & GPU_SHADER_TEXTURE_2D) { - glEnable(GL_TEXTURE_2D); - } - else if (bound_options & GPU_SHADER_TEXTURE_2D) { - glDisable(GL_TEXTURE_2D); - } - - if (options & GPU_SHADER_TEXTURE_RECT) { - glEnable(GL_TEXTURE_RECTANGLE); - } - else if (bound_options & GPU_SHADER_TEXTURE_RECT) { - glDisable(GL_TEXTURE_RECTANGLE); - } - GPUShader *shader = gpu_basic_shader(options); if (shader) { diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c new file mode 100644 index 00000000000..23f9f68f1aa --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch.c @@ -0,0 +1,35 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "GPU_batch.h" +#include "gpu_shader_private.h" + +void Batch_set_builtin_program(Batch* batch, GPUBuiltinShader shader_id) +{ + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + Batch_set_program(batch, shader->program); +} diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 964c2b5051e..13596f2a0de 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -382,9 +382,6 @@ bool GPU_fx_compositor_initialize_passes( fx->effects = 0; - if (!GLEW_EXT_framebuffer_object) - return false; - if (!fx_settings) { cleanup_fx_gl_data(fx, true); return false; @@ -585,11 +582,8 @@ bool GPU_fx_compositor_initialize_passes( /* bind the buffers */ /* first depth buffer, because system assumes read/write buffers */ - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out)) - printf("%.256s\n", err_out); - - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out)) - printf("%.256s\n", err_out); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0); if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out)) printf("%.256s\n", err_out); @@ -634,7 +628,7 @@ static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOff } else { /* bind the ping buffer to the color buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, target, 0); } } @@ -663,8 +657,7 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray) GPU_framebuffer_texture_detach(fx->depth_buffer); /* first depth buffer, because system assumes read/write buffers */ - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out)) - printf("%.256s\n", err_out); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0); } @@ -674,7 +667,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) GPU_framebuffer_texture_detach(fx->depth_buffer_xray); /* attach regular framebuffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0); /* full screen quad where we will always write to depth buffer */ glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT); @@ -922,9 +915,9 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2); /* binding takes care of setting the viewport to the downsampled size */ GPU_framebuffer_slots_bind(fx->gbuffer, 0); @@ -968,7 +961,7 @@ bool GPU_fx_do_composite_pass( GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0); GPU_texture_bind_as_framebuffer(fx->dof_far_blur); glDisable(GL_DEPTH_TEST); @@ -992,7 +985,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0); /* have to clear the buffer unfortunately */ glClear(GL_COLOR_BUFFER_BIT); /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ @@ -1111,7 +1104,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0); /* binding takes care of setting the viewport to the downsampled size */ GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); @@ -1151,7 +1144,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_buffer); /* use final buffer as a temp here */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0); /* Drawing quad */ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -1168,7 +1161,7 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_final_buffer); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* *unbind/detach */ @@ -1195,7 +1188,7 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_blurred, fx->dof_near_coc_blurred_buffer); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ @@ -1221,7 +1214,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass4, interface->near_coc_downsampled, fx->dof_near_coc_final_buffer); GPU_shader_uniform_vector(dof_shader_pass4, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c index d632e767ca9..e306394c4c3 100644 --- a/source/blender/gpu/intern/gpu_debug.c +++ b/source/blender/gpu/intern/gpu_debug.c @@ -43,118 +43,12 @@ #include <stdlib.h> #include <string.h> -#define CASE_CODE_RETURN_STR(code) case code: return #code; +/* control whether we use older AMD_debug_output extension, or just the newer extensions + * TODO(merwin): determine whether all supported GPU + OS combos have newer extensions */ +#define LEGACY_DEBUG 0 -static const char *gpu_gl_error_symbol(GLenum err) -{ - switch (err) { - CASE_CODE_RETURN_STR(GL_NO_ERROR) - CASE_CODE_RETURN_STR(GL_INVALID_ENUM) - CASE_CODE_RETURN_STR(GL_INVALID_VALUE) - CASE_CODE_RETURN_STR(GL_INVALID_OPERATION) - CASE_CODE_RETURN_STR(GL_STACK_OVERFLOW) - CASE_CODE_RETURN_STR(GL_STACK_UNDERFLOW) - CASE_CODE_RETURN_STR(GL_OUT_OF_MEMORY) - -#if GL_ARB_imaging - CASE_CODE_RETURN_STR(GL_TABLE_TOO_LARGE) -#endif - -#if defined(WITH_GLU) - CASE_CODE_RETURN_STR(GLU_INVALID_ENUM) - CASE_CODE_RETURN_STR(GLU_INVALID_VALUE) - CASE_CODE_RETURN_STR(GLU_OUT_OF_MEMORY) -#endif - - default: - return "<unknown error>"; - } -} - -#undef CASE_CODE_RETURN_STR - - -static bool gpu_report_gl_errors(const char *file, int line, const char *str) -{ - GLenum gl_error = glGetError(); - - if (gl_error == GL_NO_ERROR) { - return true; - } - else { - /* glGetError should have cleared the error flag, so if we get the - * same flag twice that means glGetError itself probably triggered - * the error. This happens on Windows if the GL context is invalid. - */ - { - GLenum new_error = glGetError(); - if (gl_error == new_error) { - fprintf(stderr, "GL: Possible context invalidation issue\n"); - return false; - } - } - - fprintf(stderr, - "%s:%d: ``%s'' -> GL Error (0x%04X - %s): %s\n", - file, line, str, gl_error, - gpu_gl_error_symbol(gl_error), - gpuErrorString(gl_error)); - - return false; - } -} - - -const char *gpuErrorString(GLenum err) -{ - switch (err) { - case GL_NO_ERROR: - return "No Error"; - - case GL_INVALID_ENUM: - return "Invalid Enumeration"; - - case GL_INVALID_VALUE: - return "Invalid Value"; - - case GL_INVALID_OPERATION: - return "Invalid Operation"; - - case GL_STACK_OVERFLOW: - return "Stack Overflow"; - - case GL_STACK_UNDERFLOW: - return "Stack Underflow"; - - case GL_OUT_OF_MEMORY: - return "Out of Memory"; - -#if GL_ARB_imaging - case GL_TABLE_TOO_LARGE: - return "Table Too Large"; -#endif - -#if defined(WITH_GLU) - case GLU_INVALID_ENUM: - return "Invalid Enum (GLU)"; - - case GLU_INVALID_VALUE: - return "Invalid Value (GLU)"; - - case GLU_OUT_OF_MEMORY: - return "Out of Memory (GLU)"; -#endif - - default: - return "<unknown error>"; - } -} - - -/* Debug callbacks need the same calling convention as OpenGL functions. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) - /* Win32 but not WinCE */ +/* Debug callbacks need the same calling convention as OpenGL functions. */ +#if defined(_WIN32) # define APIENTRY __stdcall #else # define APIENTRY @@ -188,32 +82,11 @@ static const char* message_type_name(GLenum message) } } -static const char* category_name_amd(GLenum category) -{ - switch (category) { - case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error"; - case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system"; - case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior"; - case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior"; - case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance"; - case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler"; - case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application"; - case GL_DEBUG_CATEGORY_OTHER_AMD: return "other"; - default: return "???"; - } -} - - static void APIENTRY gpu_debug_proc( GLenum source, GLenum type, GLuint UNUSED(id), GLenum severity, GLsizei UNUSED(length), const GLchar *message, const GLvoid *UNUSED(userParm)) { - if (type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) { - /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */ - return; - } - bool backtrace = false; switch (severity) { @@ -232,18 +105,28 @@ static void APIENTRY gpu_debug_proc( } } +#if LEGACY_DEBUG + +static const char* category_name_amd(GLenum category) +{ + switch (category) { + case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error"; + case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system"; + case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior"; + case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior"; + case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance"; + case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler"; + case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application"; + case GL_DEBUG_CATEGORY_OTHER_AMD: return "other"; + default: return "???"; + } +} -#ifndef GLEW_ES_ONLY static void APIENTRY gpu_debug_proc_amd( GLuint UNUSED(id), GLenum category, GLenum severity, GLsizei UNUSED(length), const GLchar *message, GLvoid *UNUSED(userParm)) { - if (category == GL_DEBUG_CATEGORY_DEPRECATION_AMD) { - /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */ - return; - } - bool backtrace = false; switch (severity) { @@ -260,8 +143,7 @@ static void APIENTRY gpu_debug_proc_amd( fflush(stderr); } } -#endif - +#endif /* LEGACY_DEBUG */ #undef APIENTRY @@ -269,137 +151,67 @@ void gpu_debug_init(void) { const char success[] = "Successfully hooked OpenGL debug callback."; -#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY) - if (GLEW_VERSION_4_3) { - fprintf(stderr, "Using OpenGL 4.3 debug facilities\n"); + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { + fprintf(stderr, "Using %s\n", GLEW_VERSION_4_3 ? "OpenGL 4.3 debug facilities" : "KHR_debug extension"); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext()); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - return; } -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY - fprintf(stderr, "Using KHR_debug extension\n"); - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext()); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); - GPU_string_marker(success); -#endif - return; - } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { fprintf(stderr, "Using ARB_debug_output extension\n"); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, mxGetCurrentContext()); glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - - return; } - - if (GLEW_AMD_debug_output) { +#if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { fprintf(stderr, "Using AMD_debug_output extension\n"); glDebugMessageCallbackAMD(gpu_debug_proc_amd, mxGetCurrentContext()); glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - - return; } #endif - - fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); - - return; + else { + fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); + } } void gpu_debug_exit(void) { -#ifndef WITH_GLEW_ES -#ifndef GLEW_ES_ONLY - if (GLEW_VERSION_4_3) { + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { glDebugMessageCallback(NULL, NULL); - - return; } -#endif -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY - glDebugMessageCallback(NULL, NULL); -#endif - return; - } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { glDebugMessageCallbackARB(NULL, NULL); - - return; } - - if (GLEW_AMD_debug_output) { +#if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { glDebugMessageCallbackAMD(NULL, NULL); - - return; } #endif - - return; } void GPU_string_marker(const char *buf) { -#ifndef WITH_GLEW_ES -#ifndef GLEW_ES_ONLY - if (GLEW_VERSION_4_3) { - glDebugMessageInsert( - GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, - GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf); - - return; - } -#endif -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { glDebugMessageInsert( GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf); -#endif - return; } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { glDebugMessageInsertARB( GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, -1, buf); - - return; } - - if (GLEW_AMD_debug_output) { +#if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { glDebugMessageInsertAMD( GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0, 0, buf); - - return; - } - - if (GLEW_GREMEDY_string_marker) { - glStringMarkerGREMEDY(0, buf); - - return; } #endif } @@ -410,18 +222,6 @@ void GPU_print_error_debug(const char *str) fprintf(stderr, "GPU: %s\n", str); } - -void GPU_assert_no_gl_errors(const char *file, int line, const char *str) -{ - if (G.debug) { - GLboolean gl_ok = gpu_report_gl_errors(file, line, str); - - BLI_assert(gl_ok); - (void) gl_ok; - } -} - - static void gpu_state_print_fl_ex(const char *name, GLenum type) { const unsigned char err_mark[4] = {0xff, 0xff, 0xff, 0xff}; @@ -448,7 +248,8 @@ static void gpu_state_print_fl_ex(const char *name, GLenum type) void GPU_state_print(void) { - GPU_ASSERT_NO_GL_ERRORS("GPU_state_print"); /* clear any errors */ + /* clear any errors */ + while (glGetError() != GL_NO_ERROR) {} gpu_state_print_fl(GL_ACCUM_ALPHA_BITS); gpu_state_print_fl(GL_ACCUM_BLUE_BITS); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 7936811ab4d..c8d5d92b66b 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -278,7 +278,7 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap) int old_value = GTS.gpu_mipmap; /* only actually enable if it's supported */ - GTS.gpu_mipmap = gpu_mipmap && GLEW_EXT_framebuffer_object; + GTS.gpu_mipmap = gpu_mipmap; if (old_value != GTS.gpu_mipmap) { GPU_free_images(); @@ -298,11 +298,7 @@ static void gpu_generate_mipmap(GLenum target) glEnable(target); } - /* TODO: simplify when we transition to GL >= 3 */ - if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object) - glGenerateMipmap(target); - else if (GLEW_EXT_framebuffer_object) - glGenerateMipmapEXT(target); + glGenerateMipmap(target); if (is_ati && !target_enabled) glDisable(target); @@ -857,6 +853,7 @@ void GPU_create_gl_tex( int tpx = rectw; int tpy = recth; +#if 0 /* NPOT support should be a compile-time check */ /* scale if not a power of two. this is not strictly necessary for newer * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures * Then don't bother scaling for hardware that supports NPOT textures! */ @@ -880,6 +877,7 @@ void GPU_create_gl_tex( rect = ibuf->rect; } } +#endif /* create image */ glGenTextures(1, (GLuint *)bind); @@ -1205,8 +1203,12 @@ void GPU_paint_set_mipmap(bool mipmap) /* check if image has been downscaled and do scaled partial update */ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) { +#if 0 /* NPOT suport should be a compile-time check */ if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) || is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) +#else + if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) +#endif { int x_limit = smaller_power_of_2_limit(ibuf->x); int y_limit = smaller_power_of_2_limit(ibuf->y); @@ -2285,7 +2287,13 @@ void GPU_state_init(void) glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); GPU_default_lights(); - + + GPU_disable_program_point_size(); + + /* TODO: remove this when we switch to core profile */ + glEnable(GL_POINT_SPRITE); + + glDepthFunc(GL_LEQUAL); /* scaling matrices */ glEnable(GL_NORMALIZE); @@ -2307,7 +2315,7 @@ void GPU_state_init(void) glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); - + glPixelTransferi(GL_MAP_COLOR, GL_FALSE); glPixelTransferi(GL_RED_SCALE, 1); glPixelTransferi(GL_RED_BIAS, 0); @@ -2317,7 +2325,7 @@ void GPU_state_init(void) glPixelTransferi(GL_BLUE_BIAS, 0); glPixelTransferi(GL_ALPHA_SCALE, 1); glPixelTransferi(GL_ALPHA_BIAS, 0); - + glPixelTransferi(GL_DEPTH_BIAS, 0); glPixelTransferi(GL_DEPTH_SCALE, 1); glDepthRange(0.0, 1.0); @@ -2335,6 +2343,26 @@ void GPU_state_init(void) GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } +void GPU_enable_program_point_size() +{ +#ifdef __APPLE__ + /* TODO: remove this when we switch to core profile */ + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); +#else + glEnable(GL_PROGRAM_POINT_SIZE); +#endif +} + +void GPU_disable_program_point_size() +{ +#ifdef __APPLE__ + /* TODO: remove this when we switch to core profile */ + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); +#else + glDisable(GL_PROGRAM_POINT_SIZE); +#endif +} + #ifdef WITH_OPENSUBDIV /* Update face-varying variables offset which might be * different from mesh to mesh sharing the same material. diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e0ce87d0e68..e8fd4b8b8b1 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -56,10 +56,8 @@ /* Extensions support */ /* -- extension: version of GL that absorbs it + * EXT_gpu_shader4: 3.0 * ARB_framebuffer object: 3.0 - * EXT_framebuffer_object: 3.0 - * EXT_framebuffer_blit: 3.0 - * EXT_framebuffer_multisample: 3.0 * EXT_framebuffer_multisample_blit_scaled: ??? * ARB_draw_instanced: 3.1 * ARB_texture_multisample: 3.2 @@ -130,8 +128,21 @@ void GPU_get_dfdy_factors(float fac[2]) void gpu_extensions_init(void) { - /* BLI_assert(GLEW_VERSION_2_1); */ - /* ^-- maybe a bit extreme? */ + /* during 2.8 development each platform has its own OpenGL minimum requirements + * final 2.8 release will be unified on OpenGL 3.3 core profile, no required extensions + * see developer.blender.org/T49012 for details + */ +#ifdef _WIN32 + BLI_assert(GLEW_VERSION_3_3); +#elif defined(__APPLE__) + BLI_assert(GLEW_VERSION_2_1 && GLEW_EXT_gpu_shader4 + && GLEW_ARB_framebuffer_object + && GLEW_ARB_draw_elements_base_vertex + && GLEW_APPLE_flush_buffer_range); +#else + BLI_assert(GLEW_VERSION_3_3 || (GLEW_VERSION_3_0 && GLEW_ARB_draw_elements_base_vertex)); + /* vendor driver || Mesa compatibility profile */ +#endif glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures); @@ -249,6 +260,8 @@ void gpu_extensions_exit(void) bool GPU_legacy_support(void) { /* return whether or not current GL context is compatible with legacy OpenGL */ + /* (will be removed after switching to core profile) */ + static bool checked = false; static bool support = true; diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index f62ef677434..ec1471744fa 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -54,44 +54,37 @@ struct GPUFrameBuffer { static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) { + const char *format = "GPUFrameBuffer: framebuffer status %s"; const char *err = "unknown"; +#define format_status(X) \ + case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \ + break; + switch (status) { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - case GL_INVALID_OPERATION: - err = "Invalid operation"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - err = "Incomplete attachment"; - break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - err = "Unsupported framebuffer format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - err = "Missing attachment"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - err = "Attached images must have same dimensions"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - err = "Attached images must have same format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - err = "Missing draw buffer"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - err = "Missing read buffer"; - break; + /* success */ + format_status(COMPLETE) + /* errors shared by OpenGL desktop & ES */ + format_status(INCOMPLETE_ATTACHMENT) + format_status(INCOMPLETE_MISSING_ATTACHMENT) + format_status(UNSUPPORTED) +#if 0 /* for OpenGL ES only */ + format_status(INCOMPLETE_DIMENSIONS) +#else /* for desktop GL only */ + format_status(INCOMPLETE_DRAW_BUFFER) + format_status(INCOMPLETE_READ_BUFFER) + format_status(INCOMPLETE_MULTISAMPLE) + format_status(UNDEFINED) +#endif } +#undef format_status + if (err_out) { - BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'", - (int)status, err); + BLI_snprintf(err_out, 256, format, err); } else { - fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n", - (int)status, err); + fprintf(stderr, format, err); } } @@ -101,41 +94,33 @@ GPUFrameBuffer *GPU_framebuffer_create(void) { GPUFrameBuffer *fb; - if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object || - (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit))) - { - return NULL; - } - fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); - glGenFramebuffersEXT(1, &fb->object); + glGenFramebuffers(1, &fb->object); if (!fb->object) { - fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n", - (int)glGetError()); + fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n"); GPU_framebuffer_free(fb); return NULL; } /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); glReadBuffer(GL_NONE); glDrawBuffer(GL_NONE); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); return fb; } -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) +bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot) { GLenum attachment; - GLenum error; if (slot >= GPU_FB_MAX_SLOTS) { fprintf(stderr, "Attaching to index %d framebuffer slot unsupported. " "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return 0; + return false; } if ((G.debug & G_DEBUG)) { @@ -147,27 +132,16 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot } if (GPU_texture_depth(tex)) - attachment = GL_DEPTH_ATTACHMENT_EXT; + attachment = GL_DEPTH_ATTACHMENT; else - attachment = GL_COLOR_ATTACHMENT0_EXT + slot; + attachment = GL_COLOR_ATTACHMENT0 + slot; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0); - error = glGetError(); - - if (error == GL_INVALID_OPERATION) { - GPU_framebuffer_restore(); - GPU_print_framebuffer_error(error, err_out); - return 0; - } - if (GPU_texture_depth(tex)) fb->depthtex = tex; else @@ -175,7 +149,7 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot GPU_texture_framebuffer_set(tex, fb, slot); - return 1; + return true; } void GPU_framebuffer_texture_detach(GPUTexture *tex) @@ -188,21 +162,21 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex) return; if (GG.currentfb != fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; } if (GPU_texture_depth(tex)) { fb->depthtex = NULL; - attachment = GL_DEPTH_ATTACHMENT_EXT; + attachment = GL_DEPTH_ATTACHMENT; } else { BLI_assert(fb->colortex[fb_attachment] == tex); fb->colortex[fb_attachment] = NULL; - attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment; + attachment = GL_COLOR_ATTACHMENT0 + fb_attachment; } - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GPU_texture_target(tex), 0, 0); GPU_texture_framebuffer_set(tex, NULL, -1); } @@ -222,7 +196,7 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); if (GPU_texture_depth(tex)) { glDrawBuffer(GL_NONE); @@ -230,8 +204,8 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) } else { /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); + glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); } if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { @@ -260,7 +234,7 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) for (i = 0; i < 4; i++) { if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i; + attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; numslots++; } } @@ -270,11 +244,11 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); /* last bound prevails here, better allow explicit control here too */ glDrawBuffers(numslots, attachments); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); /* push matrices and set default viewport and matrix */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); @@ -301,10 +275,10 @@ void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUS void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); /* push matrices and set default viewport and matrix */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); @@ -319,22 +293,17 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb) bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) { - GLenum status; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; - - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { GPU_framebuffer_restore(); GPU_print_framebuffer_error(status, err_out); return false; } - + return true; } @@ -351,10 +320,10 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) } if (fb->object) { - glDeleteFramebuffersEXT(1, &fb->object); + glDeleteFramebuffers(1, &fb->object); if (GG.currentfb == fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GG.currentfb = 0; } } @@ -365,7 +334,7 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) void GPU_framebuffer_restore(void) { if (GG.currentfb != 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GG.currentfb = 0; } } @@ -390,8 +359,8 @@ void GPU_framebuffer_blur( /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid * pushing unnecessary matrices onto the OpenGL stack. */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebuffer(GL_FRAMEBUFFER, blurfb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); /* avoid warnings from texture binding */ GG.currentfb = blurfb->object; @@ -423,8 +392,8 @@ void GPU_framebuffer_blur( /* Blurring vertically */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); GG.currentfb = fb->object; @@ -464,12 +433,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ } if (samples) { - if (!GLEW_EXT_framebuffer_multisample || - !GLEW_ARB_texture_multisample || - /* Only needed for GPU_offscreen_read_pixels. - * We could add an arg if we intend to use multi-sample - * offscreen buffers w/o reading their pixels */ - !GLEW_EXT_framebuffer_blit || + if (!GLEW_ARB_texture_multisample || /* This is required when blitting from a multi-sampled buffers, * even though we're not scaling. */ !GLEW_EXT_framebuffer_multisample_blit_scaled) @@ -484,7 +448,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0)) { GPU_offscreen_free(ofs); return NULL; } @@ -495,7 +459,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0)) { GPU_offscreen_free(ofs); return NULL; } @@ -569,37 +533,37 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) #ifdef USE_FBO_CTX_SWITCH /* read from multi-sample buffer */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object); - glFramebufferTexture2DEXT( - GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment, + glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } #endif /* write into new single-sample buffer */ - glGenFramebuffersEXT(1, &fbo_blit); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit); - glFramebufferTexture2DEXT( - GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + glGenFramebuffers(1, &fbo_blit); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } /* perform the copy */ - glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); /* read the results */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit); glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); #ifdef USE_FBO_CTX_SWITCH /* restore the original frame-bufer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ofs->color->fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object); #undef USE_FBO_CTX_SWITCH #endif @@ -610,10 +574,8 @@ finally: glDeleteTextures(1, &tex_blit); } if (fbo_blit) { - glDeleteFramebuffersEXT(1, &fbo_blit); + glDeleteFramebuffers(1, &fbo_blit); } - - GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); } else { glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c new file mode 100644 index 00000000000..685c31dc3e0 --- /dev/null +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -0,0 +1,73 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "UI_resources.h" + +#include "gpu_shader_private.h" + +void immBindBuiltinProgram(GPUBuiltinShader shader_id) +{ + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + immBindProgram(shader->program); +} + +void immUniformThemeColor(int color_id) +{ + float color[4]; + UI_GetThemeColor4fv(color_id, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorShade(int color_id, int offset) +{ + float color[4]; + UI_GetThemeColorShade4fv(color_id, offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset) +{ + float color[4]; + UI_GetThemeColorShadeAlpha4fv(color_id, color_offset, alpha_offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset) +{ + float color[4]; + UI_GetThemeColorBlendShade4fv(color_id1, color_id2, fac, offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorBlend(int color_id1, int color_id2, float fac) +{ + uint8_t color[3]; + UI_GetThemeColorBlend3ubv(color_id1, color_id2, fac, color); + immUniformColor3ubv(color); +} diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index c72c83b6b07..817756a3088 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -31,7 +31,7 @@ #include "BLI_sys_types.h" #include "GPU_init_exit.h" /* interface */ - +#include "GPU_immediate.h" #include "BKE_global.h" #include "intern/gpu_codegen.h" @@ -59,14 +59,18 @@ void GPU_init(void) if (G.debug & G_DEBUG_GPU) gpu_debug_init(); + immInit(); } void GPU_exit(void) { + immDestroy(); + if (G.debug & G_DEBUG_GPU) gpu_debug_exit(); + gpu_codegen_exit(); gpu_extensions_exit(); /* must come last */ diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index b857aea29ad..56b7af787e7 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -2409,7 +2409,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0)) { gpu_lamp_shadow_free(lamp); return lamp; } @@ -2421,7 +2421,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0)) { gpu_lamp_shadow_free(lamp); return lamp; } @@ -2444,7 +2444,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0)) { gpu_lamp_shadow_free(lamp); return lamp; } @@ -2466,7 +2466,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0)) { gpu_lamp_shadow_free(lamp); return lamp; } diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c new file mode 100644 index 00000000000..19ff856b688 --- /dev/null +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -0,0 +1,701 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 ipmlied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_matrix.c + * \ingroup gpu + */ + +#include "GPU_matrix.h" + +#include "BLI_math_matrix.h" +#include "BLI_math_rotation.h" +#include "BLI_math_vector.h" + + +#define DEBUG_MATRIX_BIND 0 + +#define MATRIX_STACK_DEPTH 32 + +typedef float Mat4[4][4]; +typedef float Mat3[3][3]; + +typedef struct { + Mat4 ModelViewStack3D[MATRIX_STACK_DEPTH]; + Mat4 ProjectionMatrix3D; + + Mat3 ModelViewStack2D[MATRIX_STACK_DEPTH]; + Mat3 ProjectionMatrix2D; + + MatrixMode mode; + unsigned top; /* of current stack (would have to replicate if gpuResume2D/3D are implemented) */ + + bool dirty; + + /* TODO: cache of derived matrices (Normal, MVP, inverse MVP, etc) + * generate as needed for shaders, invalidate when original matrices change + * + * TODO: separate Model from View transform? Batches/objects have model, + * camera/eye has view & projection + */ +} MatrixState; + +static MatrixState state; /* TODO(merwin): make part of GPUContext, alongside immediate mode & state tracker */ + +#define ModelView3D state.ModelViewStack3D[state.top] +#define ModelView2D state.ModelViewStack2D[state.top] +#define Projection3D state.ProjectionMatrix3D +#define Projection2D state.ProjectionMatrix2D + +void gpuMatrixInit() +{ + memset(&state, 0, sizeof(MatrixState)); +} + +void gpuMatrixBegin2D() +{ + state.mode = MATRIX_MODE_2D; + state.top = 0; + unit_m3(ModelView2D); + gpuOrtho2D(-1.0f, +1.0f, -1.0f, +1.0f); // or identity? +} + +void gpuMatrixBegin3D() +{ + state.mode = MATRIX_MODE_3D; + state.top = 0; + unit_m4(ModelView3D); + gpuOrtho(-1.0f, +1.0f, -1.0f, +1.0f, -1.0f, +1.0f); // or identity? +} + +#if SUPPORT_LEGACY_MATRIX +void gpuMatrixBegin3D_legacy() +{ + /* copy top matrix from each legacy stack into new fresh stack */ + state.mode = MATRIX_MODE_3D; + state.top = 0; + state.dirty = true; + glGetFloatv(GL_MODELVIEW_MATRIX, (float*)ModelView3D); + glGetFloatv(GL_PROJECTION_MATRIX, (float*)Projection3D); +} +#endif + +void gpuMatrixEnd() +{ + state.mode = MATRIX_MODE_INACTIVE; +} + + +#ifdef WITH_GPU_SAFETY + +/* Check if matrix is numerically good */ +static void checkmat(cosnt float *m) +{ + const int n = state.mode == MATRIX_MODE_3D ? 16 : 9; + for (int i = 0; i < n; i++) { +#if _MSC_VER + BLI_assert(_finite(m[i])); +#else + BLI_assert(!isinf(m[i])); +#endif + } +} + +#define CHECKMAT(m) checkmat((const float*)m) + +#else + +#define CHECKMAT(m) + +#endif + + +void gpuPushMatrix() +{ + BLI_assert(state.mode != MATRIX_MODE_INACTIVE); + BLI_assert(state.top < MATRIX_STACK_DEPTH); + state.top++; + if (state.mode == MATRIX_MODE_3D) + copy_m4_m4(ModelView3D, state.ModelViewStack3D[state.top - 1]); + else + copy_m3_m3(ModelView2D, state.ModelViewStack2D[state.top - 1]); +} + +void gpuPopMatrix() +{ + BLI_assert(state.mode != MATRIX_MODE_INACTIVE); + BLI_assert(state.top > 0); + state.top--; + state.dirty = true; +} + +void gpuLoadMatrix3D(const float m[4][4]) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); + copy_m4_m4(ModelView3D, m); + CHECKMAT(ModelView3D); + state.dirty = true; +} + +void gpuLoadMatrix2D(const float m[3][3]) +{ + BLI_assert(state.mode == MATRIX_MODE_2D); + copy_m3_m3(ModelView2D, m); + CHECKMAT(ModelView2D); + state.dirty = true; +} + +void gpuLoadIdentity() +{ + switch (state.mode) { + case MATRIX_MODE_3D: + unit_m4(ModelView3D); + break; + case MATRIX_MODE_2D: + unit_m3(ModelView2D); + break; + default: + BLI_assert(false); + } + state.dirty = true; +} + +void gpuTranslate2f(float x, float y) +{ + Mat3 m; + unit_m3(m); + m[2][0] = x; + m[2][1] = y; + gpuMultMatrix2D(m); +} + +void gpuTranslate2fv(const float vec[2]) +{ + gpuTranslate2f(vec[0], vec[1]); +} + +void gpuTranslate3f(float x, float y, float z) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); +#if 1 + translate_m4(ModelView3D, x, y, z); + CHECKMAT(ModelView3D); +#else /* above works well in early testing, below is generic version */ + Mat4 m; + unit_m4(m); + m[3][0] = x; + m[3][1] = y; + m[3][2] = z; + gpuMultMatrix3D(m); +#endif + state.dirty = true; +} + +void gpuTranslate3fv(const float vec[3]) +{ + gpuTranslate3f(vec[0], vec[1], vec[2]); +} + +void gpuScaleUniform(float factor) +{ + switch (state.mode) { + case MATRIX_MODE_3D: + { + Mat4 m; + scale_m4_fl(m, factor); + gpuMultMatrix3D(m); + break; + } + case MATRIX_MODE_2D: + { + #if 0 + Mat3 m; + scale_m3_fl(m, factor); + /* this does 3D scaling in a 3x3 matrix. Can 2D scaling use this safely, or must set m[2][2] = 1.0? */ + #else + Mat3 m = {{0.0f}}; + m[0][0] = factor; + m[1][1] = factor; + m[2][2] = 1.0f; + #endif + gpuMultMatrix2D(m); + break; + } + default: + BLI_assert(false); + } +} + +void gpuScale2f(float x, float y) +{ + Mat3 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = 1.0f; + gpuMultMatrix2D(m); +} + +void gpuScale2fv(const float vec[2]) +{ + gpuScale2f(vec[0], vec[1]); +} + +void gpuScale3f(float x, float y, float z) +{ + Mat4 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = z; + m[3][3] = 1.0f; + gpuMultMatrix3D(m); +} + +void gpuScale3fv(const float vec[3]) +{ + gpuScale3f(vec[0], vec[1], vec[2]); +} + +void gpuMultMatrix3D(const float m[4][4]) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); + mul_m4_m4_pre(ModelView3D, m); + CHECKMAT(ModelView3D); + state.dirty = true; +} + +void gpuMultMatrix2D(const float m[3][3]) +{ + BLI_assert(state.mode == MATRIX_MODE_2D); + mul_m3_m3_pre(ModelView2D, m); + CHECKMAT(ModelView2D); + state.dirty = true; +} + +void gpuRotate3fv(float deg, const float axis[3]) +{ + Mat4 m; + axis_angle_to_mat4(m, axis, DEG2RADF(deg)); + gpuMultMatrix3D(m); +} + +void gpuRotateAxis(float deg, char axis) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); +#if 1 /* rotate_m4 works in place, right? */ + rotate_m4(ModelView3D, axis, DEG2RADF(deg)); + CHECKMAT(ModelView3D); + state.dirty = true; +#else /* rotate_m4 creates a new matrix */ + Mat4 m; + rotate_m4(m, axis, DEG2RADF(deg)); + gpuMultMatrix3D(m); +#endif +} + +static void mat4_ortho_set(float m[4][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f / (right - left); + m[1][0] = 0.0f; + m[2][0] = 0.0f; + m[3][0] = -(right + left) / (right - left); + + m[0][1] = 0.0f; + m[1][1] = 2.0f / (top - bottom); + m[2][1] = 0.0f; + m[3][1] = -(top + bottom) / (top - bottom); + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -2.0f / (far - near); + m[3][2] = -(far + near) / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + state.dirty = true; +} + +static void mat4_frustum_set(float m[][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f * near / (right - left); + m[1][0] = 0.0f; + m[2][0] = (right + left) / (right - left); + m[3][0] = 0.0f; + + m[0][1] = 0.0f; + m[1][1] = 2.0f * near / (top - bottom); + m[2][1] = (top + bottom) / (top - bottom); + m[3][1] = 0.0f; + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -(far + near) / (far - near); + m[3][2] = -2.0f * far * near / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = -1.0f; + m[3][3] = 0.0f; + + state.dirty = true; +} + +static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3]) +{ +/* This function is loosely based on Mesa implementation. + * + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + + float side[3]; + + normalize_v3(lookdir); + + cross_v3_v3v3(side, lookdir, camup); + + normalize_v3(side); + + cross_v3_v3v3(camup, side, lookdir); + + m[0][0] = side[0]; + m[1][0] = side[1]; + m[2][0] = side[2]; + m[3][0] = 0.0f; + + m[0][1] = camup[0]; + m[1][1] = camup[1]; + m[2][1] = camup[2]; + m[3][1] = 0.0f; + + m[0][2] = -lookdir[0]; + m[1][2] = -lookdir[1]; + m[2][2] = -lookdir[2]; + m[3][2] = 0.0f; + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + state.dirty = true; +} + +void gpuOrtho(float left, float right, float bottom, float top, float near, float far) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); + mat4_ortho_set(Projection3D, left, right, bottom, top, near, far); + CHECKMAT(Projection3D); + state.dirty = true; +} + +void gpuOrtho2D(float left, float right, float bottom, float top) +{ + /* TODO: this function, but correct */ + BLI_assert(state.mode == MATRIX_MODE_2D); + Mat4 m; + mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f); + copy_m3_m4(Projection2D, m); + CHECKMAT(Projection2D); + state.dirty = true; +} + +void gpuFrustum(float left, float right, float bottom, float top, float near, float far) +{ + BLI_assert(state.mode == MATRIX_MODE_3D); + mat4_frustum_set(Projection3D, left, right, bottom, top, near, far); + CHECKMAT(Projection3D); + state.dirty = true; +} + +void gpuPerspective(float fovy, float aspect, float near, float far) +{ + float half_height = tanf(fovy * (float)(M_PI / 360.0)) * near; + float half_width = half_height * aspect; + gpuFrustum(-half_width, +half_width, -half_height, +half_height, near, far); +} + +void gpuLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) +{ + Mat4 cm; + float lookdir[3]; + float camup[3] = {upX, upY, upZ}; + + lookdir[0] = centerX - eyeX; + lookdir[1] = centerY - eyeY; + lookdir[2] = centerZ - eyeZ; + + mat4_look_from_origin(cm, lookdir, camup); + + gpuMultMatrix3D(cm); + gpuTranslate3f(-eyeX, -eyeY, -eyeZ); +} + +void gpuProject(const float obj[3], const float model[4][4], const float proj[4][4], const GLint view[4], float win[3]) +{ + float v[4]; + + mul_v4_m4v3(v, model, obj); + mul_m4_v4(proj, v); + + win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f; + win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f; + win[2] = (v[2] + 1) * 0.5f; +} + +bool gpuUnProject(const float win[3], const float model[4][4], const float proj[4][4], const GLint view[4], float obj[3]) +{ + float pm[4][4]; + float in[4]; + float out[4]; + + mul_m4_m4m4(pm, proj, model); + + if (!invert_m4(pm)) { + return false; + } + + in[0] = win[0]; + in[1] = win[1]; + in[2] = win[2]; + in[3] = 1; + + /* Map x and y from window coordinates */ + in[0] = (in[0] - view[0]) / view[2]; + in[1] = (in[1] - view[1]) / view[3]; + + /* Map to range -1 to +1 */ + in[0] = 2 * in[0] - 1; + in[1] = 2 * in[1] - 1; + in[2] = 2 * in[2] - 1; + + mul_v4_m4v3(out, pm, in); + + if (out[3] == 0.0f) { + return false; + } + else { + out[0] /= out[3]; + out[1] /= out[3]; + out[2] /= out[3]; + + obj[0] = out[0]; + obj[1] = out[1]; + obj[2] = out[2]; + + return true; + } +} + +const float *gpuGetModelViewMatrix3D(float m[4][4]) +{ +#if SUPPORT_LEGACY_MATRIX + if (state.mode == MATRIX_MODE_INACTIVE) { + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + glGetFloatv(GL_MODELVIEW_MATRIX, (float*)m); + return (const float*)m; + } +#endif + + BLI_assert(state.mode == MATRIX_MODE_3D); + + if (m) { + copy_m4_m4(m, ModelView3D); + return (const float*)m; + } + else { + return (const float*)ModelView3D; + } +} + +const float *gpuGetProjectionMatrix3D(float m[4][4]) +{ +#if SUPPORT_LEGACY_MATRIX + if (state.mode == MATRIX_MODE_INACTIVE) { + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + glGetFloatv(GL_PROJECTION_MATRIX, (float*)m); + return (const float*)m; + } +#endif + + BLI_assert(state.mode == MATRIX_MODE_3D); + + if (m) { + copy_m4_m4(m, ModelView3D); + return (const float*)m; + } + else { + return (const float*)ModelView3D; + } +} + +const float *gpuGetModelViewProjectionMatrix3D(float m[4][4]) +{ +#if SUPPORT_LEGACY_MATRIX + if (state.mode == MATRIX_MODE_INACTIVE) { + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + Mat4 proj; + glGetFloatv(GL_MODELVIEW_MATRIX, (float*)proj); + glGetFloatv(GL_PROJECTION_MATRIX, (float*)m); + mul_m4_m4_post(m, proj); + return (const float*)m; + } +#endif + + BLI_assert(state.mode == MATRIX_MODE_3D); + + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + mul_m4_m4m4(m, Projection3D, ModelView3D); + return (const float*)m; +} + +const float *gpuGetNormalMatrix(float m[3][3]) +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + copy_m3_m4(m, gpuGetModelViewMatrix3D(NULL)); + + invert_m3(m); + transpose_m3(m); + + return (const float*)m; +} + +const float *gpuGetNormalMatrixInverse(float m[3][3]) +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + gpuGetNormalMatrix(m); + invert_m3(m); + + return (const float*)m; +} + +void gpuBindMatrices(GLuint program) +{ + /* TODO: split this into 2 functions + * 1) get uniform locations & determine 2D or 3D + */ + GLint loc_MV = glGetUniformLocation(program, "ModelViewMatrix"); + GLint loc_P = glGetUniformLocation(program, "ProjectionMatrix"); + GLint loc_MVP = glGetUniformLocation(program, "ModelViewProjectionMatrix"); + GLint loc_N = glGetUniformLocation(program, "NormalMatrix"); + + /* 2) set uniform values to matrix stack values + * program needs to be bound + */ + glUseProgram(program); + + + /* call this portion before a draw call if desired matrices are dirty */ + if (loc_MV != -1) { + #if DEBUG_MATRIX_BIND + puts("setting 3D MV matrix"); + #endif + + glUniformMatrix4fv(loc_MV, 1, GL_FALSE, gpuGetModelViewMatrix3D(NULL)); + } + + if (loc_P != -1) { + #if DEBUG_MATRIX_BIND + puts("setting 3D P matrix"); + #endif + + glUniformMatrix4fv(loc_P, 1, GL_FALSE, gpuGetProjectionMatrix3D(NULL)); + } + + if (loc_MVP != -1) { + #if DEBUG_MATRIX_BIND + puts("setting 3D MVP matrix"); + #endif + + glUniformMatrix4fv(loc_MVP, 1, GL_FALSE, gpuGetModelViewProjectionMatrix3D(NULL)); + } + + if (loc_N != -1) { + #if DEBUG_MATRIX_BIND + puts("setting 3D normal matrix"); + #endif + + glUniformMatrix3fv(loc_N, 1, GL_FALSE, gpuGetNormalMatrix(NULL)); + } + + state.dirty = false; +} + +bool gpuMatricesDirty() +{ + return state.dirty; +} diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 14f2764b009..5f41cda3fc2 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -36,15 +36,63 @@ #include "GPU_compositing.h" #include "GPU_debug.h" #include "GPU_extensions.h" -#include "GPU_glew.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "gpu_shader_private.h" + /* TODO(sergey): Find better default values for this constants. */ #define MAX_DEFINE_LENGTH 1024 #define MAX_EXT_DEFINE_LENGTH 1024 /* Non-generated shaders */ +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl[]; +extern char datatoc_gpu_shader_2D_vert_glsl[]; +extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_2D_image_vert_glsl[]; + +extern char datatoc_gpu_shader_3D_image_vert_glsl[]; +extern char datatoc_gpu_shader_image_color_frag_glsl[]; +extern char datatoc_gpu_shader_image_mask_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[]; +extern char datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl[]; +extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[]; +extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; + +extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_point_uniform_color_smooth_frag_glsl[]; +extern char datatoc_gpu_shader_point_uniform_color_outline_smooth_frag_glsl[]; +extern char datatoc_gpu_shader_point_varying_color_outline_smooth_frag_glsl[]; +extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; +extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_uniform_size_smooth_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_uniform_size_outline_smooth_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_smooth_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_outline_smooth_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert_glsl[]; + +extern char datatoc_gpu_shader_edges_front_back_persp_vert_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_persp_geom_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_ortho_vert_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_vert_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_geom_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_simple_geom_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_frag_glsl[]; +extern char datatoc_gpu_shader_text_vert_glsl[]; +extern char datatoc_gpu_shader_text_frag_glsl[]; + extern char datatoc_gpu_shader_fire_frag_glsl[]; extern char datatoc_gpu_shader_smoke_vert_glsl[]; extern char datatoc_gpu_shader_smoke_frag_glsl[]; @@ -62,41 +110,25 @@ extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; extern char datatoc_gpu_shader_fx_lib_glsl[]; -static struct GPUShadersGlobal { - struct { - GPUShader *vsm_store; - GPUShader *sep_gaussian_blur; - GPUShader *smoke; - GPUShader *smoke_fire; - GPUShader *smoke_coba; - /* cache for shader fx. Those can exist in combinations so store them here */ - GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; - } shaders; -} GG = {{NULL}}; - -/* GPUShader */ - -struct GPUShader { - GLuint program; /* handle for full program (links shader stages below) */ - - GLuint vertex; /* handle for vertex shader */ - GLuint geometry; /* handle for geometry shader */ - GLuint fragment; /* handle for fragment shader */ +/* cache of built-in shaders (each is created on first use) */ +static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL }; - int totattrib; /* total number of attributes */ - int uniforms; /* required uniforms */ +/* cache for shader fx. Those can exist in combinations so store them here */ +static GPUShader *fx_shaders[MAX_FX_SHADERS * 2] = { NULL }; - void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ -}; +typedef struct { + const char *vert; + const char *frag; + const char *geom; /* geometry stage runs between vert & frag, but is less common, so it goes last */ +} GPUShaderStages; static void shader_print_errors(const char *task, const char *log, const char **code, int totcode) { - int i; int line = 1; fprintf(stderr, "GPUShader: %s error:\n", task); - for (i = 0; i < totcode; i++) { + for (int i = 0; i < totcode; i++) { const char *c, *pos, *end = code[i] + strlen(code[i]); if (G.debug & G_DEBUG) { @@ -119,9 +151,9 @@ static void shader_print_errors(const char *task, const char *log, const char ** static const char *gpu_shader_version(void) { - if (GLEW_VERSION_3_2) { - if (GLEW_ARB_compatibility) { - return "#version 150 compatibility\n"; + if (GLEW_VERSION_3_3) { + if (GPU_legacy_support()) { + return "#version 330 compatibility\n"; /* highest version that is widely supported * gives us native geometry shaders! * use compatibility profile so we can continue using builtin shader input/output names @@ -132,16 +164,6 @@ static const char *gpu_shader_version(void) /* latest version that is compatible with existing shaders */ } } - else if (GLEW_VERSION_3_1) { - if (GLEW_ARB_compatibility) { - return "#version 140\n"; - /* also need the ARB_compatibility extension, handled below */ - } - else { - return "#version 130\n"; - /* latest version that is compatible with existing shaders */ - } - } else if (GLEW_VERSION_3_0) { return "#version 130\n"; /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available @@ -179,9 +201,8 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], strcat(defines, "#extension GL_ARB_draw_instanced: enable\n"); } - if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) { - strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); - /* TODO: maybe require this? shaders become so much nicer */ + if (!GLEW_VERSION_3_0) { + strcat(defines, "#extension GL_EXT_gpu_shader4: require\n"); } } } @@ -453,20 +474,20 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, void GPU_shader_bind(GPUShader *shader) { - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind"); + BLI_assert(shader && shader->program); + glUseProgram(shader->program); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind"); } void GPU_shader_unbind(void) { - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind"); glUseProgram(0); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); } void GPU_shader_free(GPUShader *shader) { + BLI_assert(shader); + if (shader->vertex) glDeleteShader(shader->vertex); if (shader->geometry) @@ -484,6 +505,8 @@ void GPU_shader_free(GPUShader *shader) int GPU_shader_get_uniform(GPUShader *shader, const char *name) { + BLI_assert(shader && shader->program); + return glGetUniformLocation(shader->program, name); } @@ -502,16 +525,12 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng if (location == -1 || value == NULL) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - if (length == 1) glUniform1fv(location, arraysize, value); else if (length == 2) glUniform2fv(location, arraysize, value); else if (length == 3) glUniform3fv(location, arraysize, value); else if (length == 4) glUniform4fv(location, arraysize, value); else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value); else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value) @@ -519,14 +538,10 @@ void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int if (location == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - if (length == 1) glUniform1iv(location, arraysize, value); else if (length == 2) glUniform2iv(location, arraysize, value); else if (length == 3) glUniform3iv(location, arraysize, value); else if (length == 4) glUniform4iv(location, arraysize, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) @@ -534,7 +549,7 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) if (location == -1) return; - GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value)); + glUniform1i(location, value); } void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) @@ -549,7 +564,6 @@ void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int ou void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) { - GLenum arbnumber; int number = GPU_texture_bound_number(tex); int bindcode = GPU_texture_opengl_bindcode(tex); int target = GPU_texture_target(tex); @@ -565,78 +579,125 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText if (location == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); + if (number != 0) + glActiveTexture(GL_TEXTURE0 + number); - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); - - if (number != 0) glActiveTexture(arbnumber); if (bindcode != 0) glBindTexture(target, bindcode); else GPU_invalid_tex_bind(target); + glUniform1i(location, number); - glEnable(target); - if (number != 0) glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture"); + if (number != 0) + glActiveTexture(GL_TEXTURE0); } int GPU_shader_get_attribute(GPUShader *shader, const char *name) { - int index; - - GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name)); + BLI_assert(shader && shader->program); - return index; + return glGetAttribLocation(shader->program, name); } GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) { - GPUShader *retval = NULL; - - switch (shader) { - case GPU_SHADER_VSM_STORE: - if (!GG.shaders.vsm_store) - GG.shaders.vsm_store = GPU_shader_create( - datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.vsm_store; - break; - case GPU_SHADER_SEP_GAUSSIAN_BLUR: - if (!GG.shaders.sep_gaussian_blur) - GG.shaders.sep_gaussian_blur = GPU_shader_create( - datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, - datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.sep_gaussian_blur; - break; - case GPU_SHADER_SMOKE: - if (!GG.shaders.smoke) - GG.shaders.smoke = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.smoke; - break; - case GPU_SHADER_SMOKE_FIRE: - if (!GG.shaders.smoke_fire) - GG.shaders.smoke_fire = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.smoke_fire; - break; - case GPU_SHADER_SMOKE_COBA: - if (!GG.shaders.smoke_coba) - GG.shaders.smoke_coba = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, "#define USE_COBA;\n", 0, 0, 0); - retval = GG.shaders.smoke_coba; - break; - } + BLI_assert(shader != GPU_NUM_BUILTIN_SHADERS); /* don't be a troll */ + + static const GPUShaderStages builtin_shader_stages[GPU_NUM_BUILTIN_SHADERS] = { + [GPU_SHADER_VSM_STORE] = { datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl }, + [GPU_SHADER_SEP_GAUSSIAN_BLUR] = { datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, + datatoc_gpu_shader_sep_gaussian_blur_frag_glsl }, + [GPU_SHADER_SMOKE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + [GPU_SHADER_SMOKE_FIRE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + [GPU_SHADER_SMOKE_COBA] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + + [GPU_SHADER_TEXT] = { datatoc_gpu_shader_text_vert_glsl, datatoc_gpu_shader_text_frag_glsl }, + [GPU_SHADER_EDGES_FRONT_BACK_PERSP] = { datatoc_gpu_shader_edges_front_back_persp_vert_glsl, + /* this version is */ datatoc_gpu_shader_flat_color_frag_glsl, + /* magical but slooow */ datatoc_gpu_shader_edges_front_back_persp_geom_glsl }, + [GPU_SHADER_EDGES_FRONT_BACK_ORTHO] = { datatoc_gpu_shader_edges_front_back_ortho_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_EDGES_OVERLAY_SIMPLE] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_edges_overlay_frag_glsl, + datatoc_gpu_shader_edges_overlay_simple_geom_glsl }, + [GPU_SHADER_EDGES_OVERLAY] = { datatoc_gpu_shader_edges_overlay_vert_glsl, + datatoc_gpu_shader_edges_overlay_frag_glsl, + datatoc_gpu_shader_edges_overlay_geom_glsl }, + + [GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_mask_uniform_color_frag_glsl }, + [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_modulate_alpha_frag_glsl }, + [GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl }, + [GPU_SHADER_3D_IMAGE_DEPTH] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_depth_linear_frag_glsl }, + + [GPU_SHADER_2D_UNIFORM_COLOR] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_2D_FLAT_COLOR] = { datatoc_gpu_shader_2D_flat_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_2D_SMOOTH_COLOR] = { datatoc_gpu_shader_2D_smooth_color_vert_glsl, + datatoc_gpu_shader_2D_smooth_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_color_frag_glsl }, + [GPU_SHADER_3D_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_3D_FLAT_COLOR] = { datatoc_gpu_shader_3D_flat_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_3D_SMOOTH_COLOR] = { datatoc_gpu_shader_3D_smooth_color_vert_glsl, + datatoc_gpu_shader_3D_smooth_color_frag_glsl }, + [GPU_SHADER_3D_DEPTH_ONLY] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_depth_only_frag_glsl }, + + [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] = + { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] = + { datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH] = + { datatoc_gpu_shader_2D_point_uniform_size_smooth_vert_glsl, + datatoc_gpu_shader_point_uniform_color_smooth_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH] = + { datatoc_gpu_shader_2D_point_uniform_size_outline_smooth_vert_glsl, + datatoc_gpu_shader_point_uniform_color_outline_smooth_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_SMOOTH] = + { datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert_glsl, + datatoc_gpu_shader_point_varying_color_outline_smooth_frag_glsl }, + [GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, + datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] = { datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_point_varying_size_vert_glsl, + datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] = + { datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH] = + { datatoc_gpu_shader_3D_point_uniform_size_smooth_vert_glsl, + datatoc_gpu_shader_point_uniform_color_smooth_frag_glsl }, + [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH] = + { datatoc_gpu_shader_3D_point_uniform_size_outline_smooth_vert_glsl, + datatoc_gpu_shader_point_uniform_color_outline_smooth_frag_glsl }, + }; + + if (builtin_shaders[shader] == NULL) { + /* just a few special cases */ + const char *defines = (shader == GPU_SHADER_SMOKE_COBA) ? "#define USE_COBA;\n" : NULL; + + const GPUShaderStages *stages = builtin_shader_stages + shader; + + if (shader == GPU_SHADER_EDGES_FRONT_BACK_PERSP && !GLEW_VERSION_3_2) { + /* TODO: remove after switch to core profile (maybe) */ + static const GPUShaderStages legacy_fancy_edges = + { datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl, + datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl }; + stages = &legacy_fancy_edges; + } - if (retval == NULL) - printf("Unable to create a GPUShader for builtin shader: %u\n", shader); + /* common case */ + builtin_shaders[shader] = GPU_shader_create(stages->vert, stages->frag, stages->geom, + NULL, defines, 0, 0, 0); + } - return retval; + return builtin_shaders[shader]; } #define MAX_DEFINES 100 @@ -656,7 +717,7 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp) strcat(defines, "#define PERSP_MATRIX\n"); } - if (!GG.shaders.fx_shaders[offset]) { + if (!fx_shaders[offset]) { GPUShader *shader = NULL; switch (effect) { @@ -710,49 +771,27 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp) break; } - GG.shaders.fx_shaders[offset] = shader; + fx_shaders[offset] = shader; GPU_fx_shader_init_interface(shader, effect); } - return GG.shaders.fx_shaders[offset]; + return fx_shaders[offset]; } void GPU_shader_free_builtin_shaders(void) { - int i; - - if (GG.shaders.vsm_store) { - GPU_shader_free(GG.shaders.vsm_store); - GG.shaders.vsm_store = NULL; - } - - if (GG.shaders.sep_gaussian_blur) { - GPU_shader_free(GG.shaders.sep_gaussian_blur); - GG.shaders.sep_gaussian_blur = NULL; - } - - if (GG.shaders.smoke) { - GPU_shader_free(GG.shaders.smoke); - GG.shaders.smoke = NULL; - } - - if (GG.shaders.smoke_fire) { - GPU_shader_free(GG.shaders.smoke_fire); - GG.shaders.smoke_fire = NULL; - } - - if (GG.shaders.smoke_coba) { - GPU_shader_free(GG.shaders.smoke_coba); - GG.shaders.smoke_coba = NULL; + for (int i = 0; i < GPU_NUM_BUILTIN_SHADERS; ++i) { + if (builtin_shaders[i]) { + GPU_shader_free(builtin_shaders[i]); + builtin_shaders[i] = NULL; + } } - for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) { - if (GG.shaders.fx_shaders[i]) { - GPU_shader_free(GG.shaders.fx_shaders[i]); - GG.shaders.fx_shaders[i] = NULL; + for (int i = 0; i < 2 * MAX_FX_SHADERS; ++i) { + if (fx_shaders[i]) { + GPU_shader_free(fx_shaders[i]); + fx_shaders[i] = NULL; } } } - - diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h new file mode 100644 index 00000000000..d5193e09aa4 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_private.h @@ -0,0 +1,40 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_shader_private.h + * \ingroup gpu + */ + +#pragma once + +#include "GPU_glew.h" + +struct GPUShader { + GLuint program; /* handle for full program (links shader stages below) */ + + GLuint vertex; /* handle for vertex shader */ + GLuint geometry; /* handle for geometry shader */ + GLuint fragment; /* handle for fragment shader */ + + int totattrib; /* total number of attributes */ + int uniforms; /* required uniforms */ + + void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ +}; diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 54f0003c086..6956a815ac5 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -117,21 +117,21 @@ static GPUTexture *GPU_texture_create_nD( if (!tex->bindcode) { if (err_out) { - BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d", - (int)glGetError()); + BLI_snprintf(err_out, 256, "GPUTexture: texture create failed"); } else { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); + fprintf(stderr, "GPUTexture: texture create failed"); } GPU_texture_free(tex); return NULL; } +#if 0 /* this should be a compile-time check */ if (!GPU_full_non_power_of_two_support()) { tex->w = power_of_2_max_i(tex->w); tex->h = power_of_2_max_i(tex->h); } +#endif tex->number = 0; glBindTexture(tex->target, tex->bindcode); @@ -260,8 +260,7 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const f glGenTextures(1, &tex->bindcode); if (!tex->bindcode) { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); + fprintf(stderr, "GPUTexture: texture create failed"); GPU_texture_free(tex); return NULL; } @@ -269,8 +268,6 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const f tex->number = 0; glBindTexture(tex->target, tex->bindcode); - GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); - type = GL_FLOAT; if (channels == 4) { format = GL_RGBA; @@ -308,8 +305,6 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const f pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); #endif - GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D"); - /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it * for gooseberry */ if (rescale && fpixels) { @@ -346,14 +341,10 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const f MEM_freeN(tex3d); } - else { - if (fpixels) { - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); - GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D"); - } + else if (fpixels) { + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); } - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -400,7 +391,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget ima->gputexture[gputt] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + GPU_print_error_debug("Blender Texture Not Loaded"); } else { GLint w, h, border; @@ -454,7 +445,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) prv->gputexture[0] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + GPU_print_error_debug("Blender Texture Not Loaded"); } else { GLint w, h; @@ -625,21 +616,20 @@ void GPU_texture_bind(GPUTexture *tex, int number) if (number < 0) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); + if (number != 0) + glActiveTexture(GL_TEXTURE0 + number); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); - if (number != 0) glActiveTexture(arbnumber); - if (tex->bindcode != 0) { + if (tex->bindcode != 0) glBindTexture(tex->target_base, tex->bindcode); - } else GPU_invalid_tex_bind(tex->target_base); - glEnable(tex->target_base); - if (number != 0) glActiveTexture(GL_TEXTURE0); - tex->number = number; + glEnable(tex->target_base); /* TODO: remove this line once we're using GLSL everywhere */ - GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); + if (number != 0) + glActiveTexture(GL_TEXTURE0); + + tex->number = number; } void GPU_texture_unbind(GPUTexture *tex) @@ -651,18 +641,17 @@ void GPU_texture_unbind(GPUTexture *tex) if (tex->number == -1) return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + glBindTexture(tex->target_base, 0); - glDisable(tex->target_base); - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + glDisable(tex->target_base); /* TODO: remove this line */ - tex->number = -1; + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + tex->number = -1; } int GPU_texture_bound_number(GPUTexture *tex) @@ -680,29 +669,19 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) if (tex->number == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); - - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); if (tex->depth) { - if (compare) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE); } - if (use_filter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); } void GPU_texture_free(GPUTexture *tex) diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c new file mode 100644 index 00000000000..ea54f3cc57c --- /dev/null +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -0,0 +1,138 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_viewport.c + * \ingroup gpu + * + * System that manages viewport drawing. + */ + +#include "GPU_glew.h" +#include "GPU_immediate.h" +#include "GPU_viewport.h" +#include "GPU_texture.h" + +#include "MEM_guardedalloc.h" + +struct GPUViewport { + float pad[4]; + + /* debug */ + GPUTexture *debug_depth; + int debug_width, debug_height; +}; + +GPUViewport *GPU_viewport_create(void) +{ + GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport"); + return viewport; +} + +void GPU_viewport_free(GPUViewport *viewport) +{ + GPU_viewport_debug_depth_free(viewport); + MEM_freeN(viewport); +} + +/****************** debug ********************/ + +bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, int samples, char err_out[256]) +{ + viewport->debug_depth = GPU_texture_create_2D(width, height, NULL, GPU_HDR_HALF_FLOAT, err_out); + return (viewport->debug_depth != NULL); +} + +void GPU_viewport_debug_depth_free(GPUViewport *viewport) +{ + if (viewport->debug_depth != NULL) { + MEM_freeN(viewport->debug_depth); + viewport->debug_depth = NULL; + } +} + +void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y) +{ + const int w = GPU_texture_width(viewport->debug_depth); + const int h = GPU_texture_height(viewport->debug_depth); + + GPU_texture_bind(viewport->debug_depth, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, x, y, w, h, 0); + GPU_texture_unbind(viewport->debug_depth); +} + +void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar) +{ + const float w = (float)GPU_texture_width(viewport->debug_depth); + const float h = (float)GPU_texture_height(viewport->debug_depth); + + VertexFormat *format = immVertexFormat(); + unsigned texcoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_DEPTH); + + GPU_texture_bind(viewport->debug_depth, 0); + + immUniform1f("znear", znear); + immUniform1f("zfar", zfar); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GL_QUADS, 4); + + immAttrib2f(texcoord, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texcoord, 1.0f, 0.0f); + immVertex2f(pos, w, 0.0f); + + immAttrib2f(texcoord, 1.0f, 1.0f); + immVertex2f(pos, w, h); + + immAttrib2f(texcoord, 0.0f, 1.0f); + immVertex2f(pos, 0.0f, h); + + immEnd(); + + GPU_texture_unbind(viewport->debug_depth); + + immUnbindProgram(); +} + +int GPU_viewport_debug_depth_width(const GPUViewport *viewport) +{ + return GPU_texture_width(viewport->debug_depth); +} + +int GPU_viewport_debug_depth_height(const GPUViewport *viewport) +{ + return GPU_texture_height(viewport->debug_depth); +} + +bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport) +{ + return viewport->debug_depth != NULL; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl new file mode 100644 index 00000000000..96c833f3b93 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl @@ -0,0 +1,20 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute vec4 color; + + flat varying vec4 finalColor; +#else + in vec2 pos; + in vec4 color; + + flat out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl new file mode 100644 index 00000000000..a6c00b080b2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl @@ -0,0 +1,18 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 texCoord; + attribute vec2 pos; + varying vec2 texCoord_interp; +#else + in vec2 texCoord; + in vec2 pos; + out vec2 texCoord_interp; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f); + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl new file mode 100644 index 00000000000..a37ae16f837 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +#if __VERSION__ == 120 + attribute vec2 pos; + varying vec4 radii; +#else + in vec2 pos; + out vec4 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl new file mode 100644 index 00000000000..201e5e90ecc --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl @@ -0,0 +1,26 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; + +#if __VERSION__ == 120 + attribute vec2 pos; + varying vec2 radii; +#else + in vec2 pos; + out vec2 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl new file mode 100644 index 00000000000..d3a142cc7bd --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl @@ -0,0 +1,34 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute vec4 color; + varying vec4 radii; + varying vec4 fillColor; +#else + in vec2 pos; + in vec4 color; + out vec4 radii; + out vec4 fillColor; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + fillColor = color; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl new file mode 100644 index 00000000000..42ff51e3d03 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl @@ -0,0 +1,21 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute float size; + attribute vec4 color; + varying vec4 finalColor; +#else + in vec2 pos; + in float size; + in vec4 color; + out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl new file mode 100644 index 00000000000..654439d1feb --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl @@ -0,0 +1,13 @@ + +#if __VERSION__ == 120 + noperspective varying vec4 finalColor; + #define fragColor gl_FragColor +#else + noperspective in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl new file mode 100644 index 00000000000..9daf2d75016 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl @@ -0,0 +1,20 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute vec4 color; + + noperspective varying vec4 finalColor; +#else + in vec2 pos; + in vec4 color; + + noperspective out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl new file mode 100644 index 00000000000..4049171f73d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; +#else + in vec2 pos; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl new file mode 100644 index 00000000000..8c241cff5d4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl @@ -0,0 +1,20 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute vec4 color; + + flat varying vec4 finalColor; +#else + in vec3 pos; + in vec4 color; + + flat out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl new file mode 100644 index 00000000000..e9f847f28b3 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl @@ -0,0 +1,18 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 texCoord; + attribute vec3 pos; + varying vec2 texCoord_interp; +#else + in vec2 texCoord; + in vec3 pos; + out vec2 texCoord_interp; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos.xyz, 1.0f); + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl new file mode 100644 index 00000000000..84e77e59e90 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl @@ -0,0 +1,18 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute vec4 color; + varying vec4 finalColor; +#else + in vec3 pos; + in vec4 color; + out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_smooth_vert.glsl new file mode 100644 index 00000000000..d05920002ed --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_smooth_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +#if __VERSION__ == 120 + attribute vec3 pos; + varying vec4 radii; +#else + in vec3 pos; + out vec4 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_smooth_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_smooth_vert.glsl new file mode 100644 index 00000000000..287f95b48ab --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_smooth_vert.glsl @@ -0,0 +1,26 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; + +#if __VERSION__ == 120 + attribute vec3 pos; + varying vec2 radii; +#else + in vec3 pos; + out vec2 radii; +#endif + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl new file mode 100644 index 00000000000..7999435f0e4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl @@ -0,0 +1,21 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute float size; + attribute vec4 color; + varying vec4 finalColor; +#else + in vec3 pos; + in float size; + in vec4 color; + out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl new file mode 100644 index 00000000000..1fcda765b99 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl @@ -0,0 +1,16 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute float size; +#else + in vec3 pos; + in float size; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl new file mode 100644 index 00000000000..955a49aa7d2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl @@ -0,0 +1,13 @@ + +#if __VERSION__ == 120 + varying vec4 finalColor; + #define fragColor gl_FragColor +#else + in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl new file mode 100644 index 00000000000..22c2cfa8b93 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl @@ -0,0 +1,20 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + attribute vec4 color; + + varying vec4 finalColor; +#else + in vec3 pos; + in vec4 color; + + out vec4 finalColor; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl new file mode 100644 index 00000000000..32da3a99c63 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; +#else + in vec3 pos; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl index 01a335af048..ed2339736e7 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl @@ -58,7 +58,7 @@ uniform sampler2D_default texture_map; #ifdef USE_STIPPLE uniform int stipple_id; #if defined(DRAW_LINE) -varying in float t; +varying float t; uniform int stipple_pattern; #endif #endif diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl index a88681a5fd3..13f05b340bf 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl @@ -14,9 +14,9 @@ layout(line_strip, max_vertices = 10) out; layout(triangle_strip, max_vertices = 6) out; #endif -varying out float t; -varying in vec4 varying_vertex_color_line[]; -varying out vec4 varying_vertex_color; +out float t; +in vec4 varying_vertex_color_line[]; +out vec4 varying_vertex_color; uniform ivec4 viewport; uniform float line_width; diff --git a/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl new file mode 100644 index 00000000000..60e71e19004 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl @@ -0,0 +1,6 @@ + +void main() +{ + // no color output, only depth (line below is implicit) + // gl_FragDepth = gl_FragCoord.z; +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl new file mode 100755 index 00000000000..ed281141e16 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl @@ -0,0 +1,64 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +uniform vec3 eye; // direction we are looking + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + + // normals of faces this edge joins (object coords) + attribute vec3 N1; + attribute vec3 N2; + + flat varying vec4 finalColor; +#else + in vec3 pos; + + // normals of faces this edge joins (object coords) + in vec3 N1; + in vec3 N2; + + flat out vec4 finalColor; +#endif + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +// to discard an entire line, set both endpoints to nowhere +// and it won't produce any fragments +const vec4 nowhere = vec4(vec3(0.0), 1.0); + +void main() +{ + bool face_1_front = dot(N1, eye) > 0.0; + bool face_2_front = dot(N2, eye) > 0.0; + + vec4 position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + if (face_1_front && face_2_front) { + // front-facing edge + gl_Position = drawFront ? position : nowhere; + finalColor = frontColor; + } + else if (face_1_front || face_2_front) { + // exactly one face is front-facing, silhouette edge + gl_Position = drawSilhouette ? position : nowhere; + finalColor = silhouetteColor; + } + else { + // back-facing edge + gl_Position = drawBack ? position : nowhere; + finalColor = backColor; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl new file mode 100644 index 00000000000..10b5fad7972 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl @@ -0,0 +1,60 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. This geometry shader +// decides which edge type to use if endpoints disagree. + +uniform mat4 ProjectionMatrix; + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +layout(lines) in; +layout(line_strip, max_vertices = 2) out; + +in vec4 MV_pos[]; +in float edgeClass[]; + +flat out vec4 finalColor; + +void emitLine(vec4 color) +{ + gl_Position = ProjectionMatrix * MV_pos[0]; + EmitVertex(); + gl_Position = ProjectionMatrix * MV_pos[1]; + finalColor = color; + EmitVertex(); + EndPrimitive(); +} + +void main() +{ + float finalEdgeClass = max(edgeClass[0], edgeClass[1]); + + if (finalEdgeClass > 0.0f) { + // front-facing edge + if (drawFront) + emitLine(frontColor); + } + else if (finalEdgeClass < 0.0f) { + // back-facing edge + if (drawBack) + emitLine(backColor); + } + else { + // exactly one face is front-facing, silhouette edge + if (drawSilhouette) + emitLine(silhouetteColor); + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl new file mode 100644 index 00000000000..baf69c3e272 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl @@ -0,0 +1,78 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// This shader is an imperfect stepping stone until all platforms are +// ready for geometry shaders. + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. Need to use a geometry +// shader or pass in an extra position attribute (the other endpoint) +// to do this properly. + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +uniform mat4 ModelViewMatrix; +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; + +#if __VERSION__ == 120 + attribute vec3 pos; + + // normals of faces this edge joins (object coords) + attribute vec3 N1; + attribute vec3 N2; + + flat varying vec4 finalColor; +#else + in vec3 pos; + + // normals of faces this edge joins (object coords) + in vec3 N1; + in vec3 N2; + + flat out vec4 finalColor; +#endif + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +// to discard an entire line, set its color to invisible +// (must have GL_BLEND enabled, or discard in fragment shader) +const vec4 invisible = vec4(0.0); + +bool front(vec3 N) +{ + vec4 xformed = ModelViewMatrix * vec4(pos, 1.0); + return dot(NormalMatrix * N, normalize(-xformed.xyz)) > 0.0; +} + +void main() +{ + bool face_1_front = front(N1); + bool face_2_front = front(N2); + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + if (face_1_front && face_2_front) { + // front-facing edge + finalColor = drawFront ? frontColor : invisible; + } + else if (face_1_front || face_2_front) { + // exactly one face is front-facing, silhouette edge + finalColor = drawSilhouette ? silhouetteColor : invisible; + } + else { + // back-facing edge + finalColor = drawBack ? backColor : invisible; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl new file mode 100755 index 00000000000..e1fb78dd1a9 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl @@ -0,0 +1,44 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. We use a geometry +// shader to resolve this properly. + +uniform mat4 ModelViewMatrix; +uniform mat3 NormalMatrix; + +in vec3 pos; +in vec3 N1, N2; // normals of faces this edge joins (object coords) + +out vec4 MV_pos; +out float edgeClass; + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +bool front(vec3 N, vec3 eye) +{ + return dot(NormalMatrix * N, eye) > 0.0; +} + +void main() +{ + MV_pos = ModelViewMatrix * vec4(pos, 1.0); + + vec3 eye = normalize(-MV_pos.xyz); + + bool face_1_front = front(N1, eye); + bool face_2_front = front(N2, eye); + + if (face_1_front && face_2_front) + edgeClass = 1.0; // front-facing edge + else if (face_1_front || face_2_front) + edgeClass = 0.0; // exactly one face is front-facing, silhouette edge + else + edgeClass = -1.0; // back-facing edge +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl new file mode 100644 index 00000000000..0538c037dcf --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl @@ -0,0 +1,20 @@ + +#define SMOOTH 1 + +const float transitionWidth = 1.0; + +uniform vec4 fillColor = vec4(0); +uniform vec4 outlineColor = vec4(0,0,0,1); + +noperspective in vec3 distanceToOutline; + +out vec4 FragColor; + +void main() { + float edgeness = min(min(distanceToOutline.x, distanceToOutline.y), distanceToOutline.z); +#if SMOOTH + FragColor = mix(outlineColor, fillColor, smoothstep(0, transitionWidth, edgeness)); +#else + FragColor = (edgeness <= 0) ? outlineColor : fillColor; +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl new file mode 100644 index 00000000000..ad0dccb6c81 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl @@ -0,0 +1,67 @@ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +uniform float outlineWidth = 1.0; +uniform vec2 viewportSize; + +in vec4 pos_xformed[]; +in float widthModulator[]; + +noperspective out vec3 distanceToOutline; + +// project to screen space +vec2 proj(int axis) { + vec4 pos = pos_xformed[axis]; + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +float dist(vec2 pos[3], int v) { + // current vertex position + vec2 vpos = pos[v]; + // endpoints of opposite edge + vec2 e1 = pos[(v + 1) % 3]; + vec2 e2 = pos[(v + 2) % 3]; + + float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify + return abs_det / distance(e2, e1); +} + +vec3 distance[3]; + +void clearEdge(int v) { + float distant = 10 * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] += distant; +} + +void modulateEdge(int v) { + float offset = min(widthModulator[v],1) * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] -= offset; +} + +void main() { + vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2)); + + for (int v = 0; v < 3; ++v) + distance[v] = vec3(0); + + for (int v = 0; v < 3; ++v) { + if (widthModulator[v] > 0) { + distance[v][v] = dist(pos, v); + modulateEdge(v); + } + } + + for (int v = 0; v < 3; ++v) + if (widthModulator[v] <= 0) + clearEdge(v); + + for (int v = 0; v < 3; ++v) { + gl_Position = pos_xformed[v]; + distanceToOutline = distance[v]; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl new file mode 100644 index 00000000000..ec692e210c2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl @@ -0,0 +1,52 @@ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +uniform float outlineWidth = 1.0; +uniform vec2 viewportSize; + +noperspective out vec3 distanceToOutline; + +// project to screen space +vec2 proj(int axis) { + vec4 pos = gl_in[axis].gl_Position; + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +float dist(vec2 pos[3], int v) { + // current vertex position + vec2 vpos = pos[v]; + // endpoints of opposite edge + vec2 e1 = pos[(v + 1) % 3]; + vec2 e2 = pos[(v + 2) % 3]; + + float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify + return abs_det / distance(e2, e1); +} + +vec3 distance[3]; + +void modulateEdge(int v) { + float offset = 0.5 * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] -= offset; +} + +void main() { + vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2)); + + for (int v = 0; v < 3; ++v) + distance[v] = vec3(0); + + for (int v = 0; v < 3; ++v) { + distance[v][v] = dist(pos, v); + modulateEdge(v); + } + + for (int v = 0; v < 3; ++v) { + gl_Position = gl_in[v].gl_Position; + distanceToOutline = distance[v]; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl new file mode 100644 index 00000000000..71a43d1b7ae --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl @@ -0,0 +1,13 @@ + +//mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in float edgeWidthModulator; + +out vec4 pos_xformed; +out float widthModulator; + +void main() { + pos_xformed = gl_ModelViewProjectionMatrix * vec4(pos, 1.0); + widthModulator = edgeWidthModulator; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl new file mode 100644 index 00000000000..10b4c2ac39d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl @@ -0,0 +1,16 @@ + +#if __VERSION__ == 120 + flat varying vec4 finalColor; + #define fragColor gl_FragColor +#else + flat in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + if (finalColor.a > 0.0) + fragColor = finalColor; + else + discard; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl new file mode 100644 index 00000000000..91097d24cb2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl @@ -0,0 +1,13 @@ + +#if __VERSION__ == 120 + flat varying vec4 finalColor; + #define fragColor gl_FragColor +#else + flat in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl new file mode 100644 index 00000000000..b7697b0a3cc --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl @@ -0,0 +1,17 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform vec4 color; +uniform sampler2D image; + +void main() +{ + fragColor = texture2D(image, texCoord_interp) * color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl new file mode 100644 index 00000000000..7f76fbf03be --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl @@ -0,0 +1,22 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform float znear; +uniform float zfar; +uniform sampler2D image; + +void main() +{ + float depth = texture2D(image, texCoord_interp).r; + + /* normalize */ + fragColor.rgb = vec3((2.0f * znear) / (zfar + znear - (depth * (zfar - znear)))); + fragColor.a = 1.0f; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl new file mode 100644 index 00000000000..e78779559a1 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl @@ -0,0 +1,18 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform sampler2D image; +uniform vec4 color; + +void main() +{ + fragColor.a = texture2D(image, texCoord_interp).a * color.a; + fragColor.rgb = color.rgb; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl new file mode 100644 index 00000000000..74e17198985 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl @@ -0,0 +1,18 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform float alpha; +uniform sampler2D image; + +void main() +{ + fragColor = texture2D(image, texCoord_interp); + fragColor.a *= alpha; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl new file mode 100644 index 00000000000..aae3b40efd4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl @@ -0,0 +1,18 @@ + +#if __VERSION__ == 120 + varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2DRect texture +#endif + +uniform float alpha; +uniform sampler2DRect image; + +void main() +{ + fragColor = texture2DRect(image, texCoord_interp); + fragColor.a *= alpha; +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl new file mode 100644 index 00000000000..8e0c75db6bf --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl @@ -0,0 +1,21 @@ + +uniform vec4 color; + +#if __VERSION__ == 120 + #define fragColor gl_FragColor +#else + out vec4 fragColor; +#endif + +void main() +{ + vec2 centered = gl_PointCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + // round point with jaggy edges + if (dist_squared > rad_squared) + discard; + + fragColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl new file mode 100644 index 00000000000..f83785de95e --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_smooth_frag.glsl @@ -0,0 +1,36 @@ + +uniform vec4 color; +uniform vec4 outlineColor; + +#if __VERSION__ == 120 + varying vec4 radii; + #define fragColor gl_FragColor +#else + in vec4 radii; + out vec4 fragColor; +#endif + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure point color +// ... +// dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else + fragColor = mix(color, outlineColor, smoothstep(radii[3], radii[2], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_smooth_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_smooth_frag.glsl new file mode 100644 index 00000000000..8c8d81f6997 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_smooth_frag.glsl @@ -0,0 +1,25 @@ + +uniform vec4 color; + +#if __VERSION__ == 120 + varying vec2 radii; + #define fragColor gl_FragColor +#else + in vec2 radii; + out vec4 fragColor; +#endif + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure point color +// ... +// dist = 0 at center of point + + fragColor.rgb = color.rgb; + fragColor.a = mix(color.a, 0.0, smoothstep(radii[1], radii[0], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl new file mode 100644 index 00000000000..91092a9f727 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl @@ -0,0 +1,21 @@ + +#if __VERSION__ == 120 + varying vec4 finalColor; + #define fragColor gl_FragColor +#else + in vec4 finalColor; + out vec4 fragColor; +#endif + +void main() +{ + vec2 centered = gl_PointCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + // round point with jaggy edges + if (dist_squared > rad_squared) + discard; + + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_smooth_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_smooth_frag.glsl new file mode 100644 index 00000000000..d6cbe2d9a22 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_smooth_frag.glsl @@ -0,0 +1,37 @@ + +uniform vec4 outlineColor; + +#if __VERSION__ == 120 + varying vec4 radii; + varying vec4 fillColor; + #define fragColor gl_FragColor +#else + in vec4 radii; + in vec4 fillColor; + out vec4 fragColor; +#endif + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure fill color +// ... +// dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else + fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl new file mode 100644 index 00000000000..9283d682767 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl @@ -0,0 +1,22 @@ + +#if __VERSION__ == 120 + flat varying vec4 color_flat; + noperspective varying vec2 texCoord_interp; + #define fragColor gl_FragColor +#else + flat in vec4 color_flat; + noperspective in vec2 texCoord_interp; + out vec4 fragColor; + #define texture2D texture +#endif + +uniform sampler2D glyph; + +void main() +{ + // input color replaces texture color + fragColor.rgb = color_flat.rgb; + + // modulate input alpha & texture alpha + fragColor.a = color_flat.a * texture2D(glyph, texCoord_interp).a; +} diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl new file mode 100644 index 00000000000..44568f28c8e --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -0,0 +1,24 @@ + +uniform mat4 ModelViewProjectionMatrix; + +#if __VERSION__ == 120 + attribute vec2 pos; + attribute vec2 texCoord; + attribute vec4 color; + flat varying vec4 color_flat; + noperspective varying vec2 texCoord_interp; +#else + in vec2 pos; + in vec2 texCoord; + in vec4 color; + flat out vec4 color_flat; + noperspective out vec2 texCoord_interp; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + + color_flat = color; + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl new file mode 100644 index 00000000000..af200bf8661 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl @@ -0,0 +1,13 @@ + +uniform vec4 color; + +#if __VERSION__ == 120 + #define fragColor gl_FragColor +#else + out vec4 fragColor; +#endif + +void main() +{ + fragColor = color; +} diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 23b73424da5..180dd5577ce 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -295,6 +295,7 @@ typedef struct bGPdata { short sbuffer_sflag; /* flags for stroke that cache represents */ void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */ float scolor[4]; /* buffer color using palettes */ + float sfill[4]; /* buffer fill color */ char pad[6]; /* padding for compiler alignment error */ short sflag; /* settings for palette color */ diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 984e3334414..8310856510c 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -50,11 +50,14 @@ typedef struct TreeStore { } TreeStore; /* TreeStoreElem->flag */ -#define TSE_CLOSED 1 -#define TSE_SELECTED 2 -#define TSE_TEXTBUT 4 -#define TSE_CHILDSEARCH 8 -#define TSE_SEARCHMATCH 16 +enum { + TSE_CLOSED = (1 << 0), + TSE_SELECTED = (1 << 1), + TSE_TEXTBUT = (1 << 2), + TSE_CHILDSEARCH = (1 << 3), + TSE_SEARCHMATCH = (1 << 4), + TSE_HIGHLIGHTED = (1 << 5), +}; /* TreeStoreElem->types */ #define TSE_NLA 1 /* NO ID */ diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index e208ef39719..ce1f8d1a7d4 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -76,6 +76,8 @@ typedef struct bScreen { struct wmTimer *animtimer; /* if set, screen has timer handler added in window */ void *context; /* context callback */ + + PreviewImage *preview; } bScreen; typedef struct ScrVert { @@ -265,9 +267,10 @@ typedef struct ARegion { ListBase ui_previews; /* uiPreview */ ListBase handlers; /* wmEventHandler */ ListBase panels_category; /* Panel categories runtime */ - + + struct wmManipulatorMap *manipulator_map; /* manipulator-map of this region */ struct wmTimer *regiontimer; /* blend in/out */ - + char *headerstr; /* use this string to draw info */ void *regiondata; /* XXX 2.50, need spacedata equivalent? */ } ARegion; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 0ad4482708f..1dc6c7ab578 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -490,6 +490,7 @@ typedef struct UserDef { short tb_leftmouse, tb_rightmouse; struct SolidLight light[3]; short tw_hotspot, tw_flag, tw_handlesize, tw_size; + short manipulator_scale, pad3[3]; short textimeout, texcollectrate; short wmdrawmethod; /* removed wmpad */ short dragthreshold; @@ -782,8 +783,6 @@ typedef enum eText_Draw_Options { USER_TEXT_DISABLE_AA = (1 << 0), } eText_Draw_Options; -/* tw_flag (transform widget) */ - /* gp_settings (Grease Pencil Settings) */ typedef enum eGP_UserdefSettings { GP_PAINT_DOSMOOTH = (1 << 0), diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 4c243507e82..f84a6c3efc8 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -45,6 +45,7 @@ struct SmoothView3DStore; struct wmTimer; struct Material; struct GPUFX; +struct GPUViewport; /* This is needed to not let VC choke on near and far... old * proprietary MS extensions... */ @@ -65,6 +66,12 @@ struct GPUFX; /* The near/far thing is a Win EXCEPTION. Thus, leave near/far in the * code, and patch for windows. */ + +typedef struct View3DDebug { + float znear, zfar; + char background; + char pad[7]; +} View3DDebug; /* Background Picture in 3D-View */ typedef struct BGpic { @@ -111,7 +118,7 @@ typedef struct RegionView3D { struct wmTimer *smooth_timer; - /* transform widget matrix */ + /* transform manipulator matrix */ float twmat[4][4]; float viewquat[4]; /* view rotation, must be kept normalized */ @@ -147,6 +154,7 @@ typedef struct RegionView3D { float rot_axis[3]; struct GPUFX *compositor; + struct GPUViewport *viewport; } RegionView3D; /* 3D ViewPort Struct */ @@ -202,7 +210,7 @@ typedef struct View3D { short gridsubdiv; /* Number of subdivisions in the grid between each highlighted grid line */ char gridflag; - /* transform widget info */ + /* transform manipulator info */ char twtype, twmode, twflag; short flag3; @@ -217,8 +225,11 @@ typedef struct View3D { char multiview_eye; /* multiview current eye - for internal use */ - /* built-in shader effects (eGPUFXFlags) */ - char pad3[4]; + /* XXX tmp flags for 2.8 viewport transition to avoid compatibility issues that would be caused by + * using usual flag bitfields (which are saved to files). Can be removed when not needed anymore. */ + char tmp_compat_flag; + + char pad3[3]; /* note, 'fx_settings.dof' is currently _not_ allocated, * instead set (temporarily) from camera */ @@ -244,6 +255,7 @@ typedef struct View3D { short prev_drawtype; short pad1; float pad2; + View3DDebug debug; } View3D; @@ -320,6 +332,20 @@ typedef struct View3D { /* View3d->flag3 (short) */ #define V3D_SHOW_WORLD (1 << 0) +/* View3d->tmp_compat_flag */ +enum { + V3D_NEW_VIEWPORT = (1 << 0), + V3D_DEBUG_SHOW_SCENE_DEPTH = (1 << 1), + V3D_DEBUG_SHOW_COMBINED_DEPTH = (1 << 2), +}; + +/* View3d->debug.background */ +enum { + V3D_DEBUG_BACKGROUND_NONE = (1 << 0), + V3D_DEBUG_BACKGROUND_GRADIENT = (1 << 1), + V3D_DEBUG_BACKGROUND_WORLD = (1 << 2), +}; + /* View3D->around */ enum { /* center of the bounding box */ diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 344c1781b46..bb927603e46 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -251,6 +251,8 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag); + /* TODO(merwin): validate input (dimensions, filter, mag) before calling OpenGL + * instead of trusting input & testing for error after */ error = glGetError(); if (error) { diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index c110dbff6c4..244820f5a49 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -1587,6 +1587,7 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_Main_particles_is_updated_get", NULL); } + void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 1feae9e0bca..97217f749d6 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2389,6 +2389,13 @@ static void rna_def_space_view3d(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem debug_background_items[] = { + {V3D_DEBUG_BACKGROUND_NONE, "NONE", 0, "None", ""}, + {V3D_DEBUG_BACKGROUND_GRADIENT, "GRADIENT", 0, "Gradient", ""}, + {V3D_DEBUG_BACKGROUND_WORLD, "WORLD", 0, "World", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "SpaceView3D", "Space"); RNA_def_struct_sdna(srna, "View3D"); RNA_def_struct_ui_text(srna, "3D View Space", "3D View space data"); @@ -2781,6 +2788,42 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Volume Alpha", "Opacity (alpha) of the cameras' frustum volume"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + /* *** Blender 2.8 Viewport temporary *** */ + prop = RNA_def_property(srna, "use_modern_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "tmp_compat_flag", V3D_NEW_VIEWPORT); + RNA_def_property_ui_text(prop, "Modern Viewport", "Use modern viewport"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "show_scene_depth", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "tmp_compat_flag", V3D_DEBUG_SHOW_SCENE_DEPTH); + RNA_def_property_ui_text(prop, "Show Scene Depth", "Debug option to show the depth in the viewport"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "show_combined_depth", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "tmp_compat_flag", V3D_DEBUG_SHOW_COMBINED_DEPTH); + RNA_def_property_ui_text(prop, "Show Combined Depth", "Debug option to show the depth in the viewport"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "debug_near", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "debug.znear"); + RNA_def_property_ui_text(prop, "Near", "Near distance for depth debugging"); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "debug_far", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "debug.zfar"); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); + RNA_def_property_ui_text(prop, "Far", "Far distance for depth debugging"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "debug_background", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "debug.background"); + RNA_def_property_enum_items(prop, debug_background_items); + RNA_def_property_ui_text(prop, "Background", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + /* *** Animated *** */ RNA_define_animate_sdna(true); /* region */ diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 3ea10228ad4..1fc575480dc 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -1687,9 +1687,6 @@ static void py_module_dict_add_method(PyObject *submodule, PyObject *dict, PyMet } } -/* TODO, expose to users */ -static bool use_deprecated = true; - PyObject *BPyInit_bgl(void) { PyObject *submodule, *dict; @@ -1764,268 +1761,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexParameteriv); PY_MOD_ADD_METHOD(Viewport); } - /* adding in GL_VERSION_1_0 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(Accum); - PY_MOD_ADD_METHOD(AlphaFunc); - PY_MOD_ADD_METHOD(Begin); - PY_MOD_ADD_METHOD(Bitmap); - PY_MOD_ADD_METHOD(CallList); - PY_MOD_ADD_METHOD(CallLists); - PY_MOD_ADD_METHOD(ClearAccum); - PY_MOD_ADD_METHOD(ClearIndex); - PY_MOD_ADD_METHOD(ClipPlane); - PY_MOD_ADD_METHOD(Color3b); - PY_MOD_ADD_METHOD(Color3bv); - PY_MOD_ADD_METHOD(Color3d); - PY_MOD_ADD_METHOD(Color3dv); - PY_MOD_ADD_METHOD(Color3f); - PY_MOD_ADD_METHOD(Color3fv); - PY_MOD_ADD_METHOD(Color3i); - PY_MOD_ADD_METHOD(Color3iv); - PY_MOD_ADD_METHOD(Color3s); - PY_MOD_ADD_METHOD(Color3sv); - PY_MOD_ADD_METHOD(Color3ub); - PY_MOD_ADD_METHOD(Color3ubv); - PY_MOD_ADD_METHOD(Color3ui); - PY_MOD_ADD_METHOD(Color3uiv); - PY_MOD_ADD_METHOD(Color3us); - PY_MOD_ADD_METHOD(Color3usv); - PY_MOD_ADD_METHOD(Color4b); - PY_MOD_ADD_METHOD(Color4bv); - PY_MOD_ADD_METHOD(Color4d); - PY_MOD_ADD_METHOD(Color4dv); - PY_MOD_ADD_METHOD(Color4f); - PY_MOD_ADD_METHOD(Color4fv); - PY_MOD_ADD_METHOD(Color4i); - PY_MOD_ADD_METHOD(Color4iv); - PY_MOD_ADD_METHOD(Color4s); - PY_MOD_ADD_METHOD(Color4sv); - PY_MOD_ADD_METHOD(Color4ub); - PY_MOD_ADD_METHOD(Color4ubv); - PY_MOD_ADD_METHOD(Color4ui); - PY_MOD_ADD_METHOD(Color4uiv); - PY_MOD_ADD_METHOD(Color4us); - PY_MOD_ADD_METHOD(Color4usv); - PY_MOD_ADD_METHOD(ColorMaterial); - PY_MOD_ADD_METHOD(CopyPixels); - PY_MOD_ADD_METHOD(DeleteLists); - PY_MOD_ADD_METHOD(DrawPixels); - PY_MOD_ADD_METHOD(EdgeFlag); - PY_MOD_ADD_METHOD(EdgeFlagv); - PY_MOD_ADD_METHOD(End); - PY_MOD_ADD_METHOD(EndList); - PY_MOD_ADD_METHOD(EvalCoord1d); - PY_MOD_ADD_METHOD(EvalCoord1dv); - PY_MOD_ADD_METHOD(EvalCoord1f); - PY_MOD_ADD_METHOD(EvalCoord1fv); - PY_MOD_ADD_METHOD(EvalCoord2d); - PY_MOD_ADD_METHOD(EvalCoord2dv); - PY_MOD_ADD_METHOD(EvalCoord2f); - PY_MOD_ADD_METHOD(EvalCoord2fv); - PY_MOD_ADD_METHOD(EvalMesh1); - PY_MOD_ADD_METHOD(EvalMesh2); - PY_MOD_ADD_METHOD(EvalPoint1); - PY_MOD_ADD_METHOD(EvalPoint2); - PY_MOD_ADD_METHOD(FeedbackBuffer); - PY_MOD_ADD_METHOD(Fogf); - PY_MOD_ADD_METHOD(Fogfv); - PY_MOD_ADD_METHOD(Fogi); - PY_MOD_ADD_METHOD(Fogiv); - PY_MOD_ADD_METHOD(Frustum); - PY_MOD_ADD_METHOD(GenLists); - PY_MOD_ADD_METHOD(GetClipPlane); - PY_MOD_ADD_METHOD(GetLightfv); - PY_MOD_ADD_METHOD(GetLightiv); - PY_MOD_ADD_METHOD(GetMapdv); - PY_MOD_ADD_METHOD(GetMapfv); - PY_MOD_ADD_METHOD(GetMapiv); - PY_MOD_ADD_METHOD(GetMaterialfv); - PY_MOD_ADD_METHOD(GetMaterialiv); - PY_MOD_ADD_METHOD(GetPixelMapfv); - PY_MOD_ADD_METHOD(GetPixelMapuiv); - PY_MOD_ADD_METHOD(GetPixelMapusv); - PY_MOD_ADD_METHOD(GetPolygonStipple); - PY_MOD_ADD_METHOD(GetTexEnvfv); - PY_MOD_ADD_METHOD(GetTexEnviv); - PY_MOD_ADD_METHOD(GetTexGendv); - PY_MOD_ADD_METHOD(GetTexGenfv); - PY_MOD_ADD_METHOD(GetTexGeniv); - PY_MOD_ADD_METHOD(IndexMask); - PY_MOD_ADD_METHOD(Indexd); - PY_MOD_ADD_METHOD(Indexdv); - PY_MOD_ADD_METHOD(Indexf); - PY_MOD_ADD_METHOD(Indexfv); - PY_MOD_ADD_METHOD(Indexi); - PY_MOD_ADD_METHOD(Indexiv); - PY_MOD_ADD_METHOD(Indexs); - PY_MOD_ADD_METHOD(Indexsv); - PY_MOD_ADD_METHOD(InitNames); - PY_MOD_ADD_METHOD(IsList); - PY_MOD_ADD_METHOD(LightModelf); - PY_MOD_ADD_METHOD(LightModelfv); - PY_MOD_ADD_METHOD(LightModeli); - PY_MOD_ADD_METHOD(LightModeliv); - PY_MOD_ADD_METHOD(Lightf); - PY_MOD_ADD_METHOD(Lightfv); - PY_MOD_ADD_METHOD(Lighti); - PY_MOD_ADD_METHOD(Lightiv); - PY_MOD_ADD_METHOD(LineStipple); - PY_MOD_ADD_METHOD(ListBase); - PY_MOD_ADD_METHOD(LoadIdentity); - PY_MOD_ADD_METHOD(LoadMatrixd); - PY_MOD_ADD_METHOD(LoadMatrixf); - PY_MOD_ADD_METHOD(LoadName); - PY_MOD_ADD_METHOD(Map1d); - PY_MOD_ADD_METHOD(Map1f); - PY_MOD_ADD_METHOD(Map2d); - PY_MOD_ADD_METHOD(Map2f); - PY_MOD_ADD_METHOD(MapGrid1d); - PY_MOD_ADD_METHOD(MapGrid1f); - PY_MOD_ADD_METHOD(MapGrid2d); - PY_MOD_ADD_METHOD(MapGrid2f); - PY_MOD_ADD_METHOD(Materialf); - PY_MOD_ADD_METHOD(Materialfv); - PY_MOD_ADD_METHOD(Materiali); - PY_MOD_ADD_METHOD(Materialiv); - PY_MOD_ADD_METHOD(MatrixMode); - PY_MOD_ADD_METHOD(MultMatrixd); - PY_MOD_ADD_METHOD(MultMatrixf); - PY_MOD_ADD_METHOD(NewList); - PY_MOD_ADD_METHOD(Normal3b); - PY_MOD_ADD_METHOD(Normal3bv); - PY_MOD_ADD_METHOD(Normal3d); - PY_MOD_ADD_METHOD(Normal3dv); - PY_MOD_ADD_METHOD(Normal3f); - PY_MOD_ADD_METHOD(Normal3fv); - PY_MOD_ADD_METHOD(Normal3i); - PY_MOD_ADD_METHOD(Normal3iv); - PY_MOD_ADD_METHOD(Normal3s); - PY_MOD_ADD_METHOD(Normal3sv); - PY_MOD_ADD_METHOD(Ortho); - PY_MOD_ADD_METHOD(PassThrough); - PY_MOD_ADD_METHOD(PixelMapfv); - PY_MOD_ADD_METHOD(PixelMapuiv); - PY_MOD_ADD_METHOD(PixelMapusv); - PY_MOD_ADD_METHOD(PixelTransferf); - PY_MOD_ADD_METHOD(PixelTransferi); - PY_MOD_ADD_METHOD(PixelZoom); - PY_MOD_ADD_METHOD(PolygonStipple); - PY_MOD_ADD_METHOD(PopAttrib); - PY_MOD_ADD_METHOD(PopMatrix); - PY_MOD_ADD_METHOD(PopName); - PY_MOD_ADD_METHOD(PushAttrib); - PY_MOD_ADD_METHOD(PushMatrix); - PY_MOD_ADD_METHOD(PushName); - PY_MOD_ADD_METHOD(RasterPos2d); - PY_MOD_ADD_METHOD(RasterPos2dv); - PY_MOD_ADD_METHOD(RasterPos2f); - PY_MOD_ADD_METHOD(RasterPos2fv); - PY_MOD_ADD_METHOD(RasterPos2i); - PY_MOD_ADD_METHOD(RasterPos2iv); - PY_MOD_ADD_METHOD(RasterPos2s); - PY_MOD_ADD_METHOD(RasterPos2sv); - PY_MOD_ADD_METHOD(RasterPos3d); - PY_MOD_ADD_METHOD(RasterPos3dv); - PY_MOD_ADD_METHOD(RasterPos3f); - PY_MOD_ADD_METHOD(RasterPos3fv); - PY_MOD_ADD_METHOD(RasterPos3i); - PY_MOD_ADD_METHOD(RasterPos3iv); - PY_MOD_ADD_METHOD(RasterPos3s); - PY_MOD_ADD_METHOD(RasterPos3sv); - PY_MOD_ADD_METHOD(RasterPos4d); - PY_MOD_ADD_METHOD(RasterPos4dv); - PY_MOD_ADD_METHOD(RasterPos4f); - PY_MOD_ADD_METHOD(RasterPos4fv); - PY_MOD_ADD_METHOD(RasterPos4i); - PY_MOD_ADD_METHOD(RasterPos4iv); - PY_MOD_ADD_METHOD(RasterPos4s); - PY_MOD_ADD_METHOD(RasterPos4sv); - PY_MOD_ADD_METHOD(Rectd); - PY_MOD_ADD_METHOD(Rectdv); - PY_MOD_ADD_METHOD(Rectf); - PY_MOD_ADD_METHOD(Rectfv); - PY_MOD_ADD_METHOD(Recti); - PY_MOD_ADD_METHOD(Rectiv); - PY_MOD_ADD_METHOD(Rects); - PY_MOD_ADD_METHOD(Rectsv); - PY_MOD_ADD_METHOD(RenderMode); - PY_MOD_ADD_METHOD(Rotated); - PY_MOD_ADD_METHOD(Rotatef); - PY_MOD_ADD_METHOD(Scaled); - PY_MOD_ADD_METHOD(Scalef); - PY_MOD_ADD_METHOD(SelectBuffer); - PY_MOD_ADD_METHOD(ShadeModel); - PY_MOD_ADD_METHOD(TexCoord1d); - PY_MOD_ADD_METHOD(TexCoord1dv); - PY_MOD_ADD_METHOD(TexCoord1f); - PY_MOD_ADD_METHOD(TexCoord1fv); - PY_MOD_ADD_METHOD(TexCoord1i); - PY_MOD_ADD_METHOD(TexCoord1iv); - PY_MOD_ADD_METHOD(TexCoord1s); - PY_MOD_ADD_METHOD(TexCoord1sv); - PY_MOD_ADD_METHOD(TexCoord2d); - PY_MOD_ADD_METHOD(TexCoord2dv); - PY_MOD_ADD_METHOD(TexCoord2f); - PY_MOD_ADD_METHOD(TexCoord2fv); - PY_MOD_ADD_METHOD(TexCoord2i); - PY_MOD_ADD_METHOD(TexCoord2iv); - PY_MOD_ADD_METHOD(TexCoord2s); - PY_MOD_ADD_METHOD(TexCoord2sv); - PY_MOD_ADD_METHOD(TexCoord3d); - PY_MOD_ADD_METHOD(TexCoord3dv); - PY_MOD_ADD_METHOD(TexCoord3f); - PY_MOD_ADD_METHOD(TexCoord3fv); - PY_MOD_ADD_METHOD(TexCoord3i); - PY_MOD_ADD_METHOD(TexCoord3iv); - PY_MOD_ADD_METHOD(TexCoord3s); - PY_MOD_ADD_METHOD(TexCoord3sv); - PY_MOD_ADD_METHOD(TexCoord4d); - PY_MOD_ADD_METHOD(TexCoord4dv); - PY_MOD_ADD_METHOD(TexCoord4f); - PY_MOD_ADD_METHOD(TexCoord4fv); - PY_MOD_ADD_METHOD(TexCoord4i); - PY_MOD_ADD_METHOD(TexCoord4iv); - PY_MOD_ADD_METHOD(TexCoord4s); - PY_MOD_ADD_METHOD(TexCoord4sv); - PY_MOD_ADD_METHOD(TexEnvf); - PY_MOD_ADD_METHOD(TexEnvfv); - PY_MOD_ADD_METHOD(TexEnvi); - PY_MOD_ADD_METHOD(TexEnviv); - PY_MOD_ADD_METHOD(TexGend); - PY_MOD_ADD_METHOD(TexGendv); - PY_MOD_ADD_METHOD(TexGenf); - PY_MOD_ADD_METHOD(TexGenfv); - PY_MOD_ADD_METHOD(TexGeni); - PY_MOD_ADD_METHOD(TexGeniv); - PY_MOD_ADD_METHOD(Translated); - PY_MOD_ADD_METHOD(Translatef); - PY_MOD_ADD_METHOD(Vertex2d); - PY_MOD_ADD_METHOD(Vertex2dv); - PY_MOD_ADD_METHOD(Vertex2f); - PY_MOD_ADD_METHOD(Vertex2fv); - PY_MOD_ADD_METHOD(Vertex2i); - PY_MOD_ADD_METHOD(Vertex2iv); - PY_MOD_ADD_METHOD(Vertex2s); - PY_MOD_ADD_METHOD(Vertex2sv); - PY_MOD_ADD_METHOD(Vertex3d); - PY_MOD_ADD_METHOD(Vertex3dv); - PY_MOD_ADD_METHOD(Vertex3f); - PY_MOD_ADD_METHOD(Vertex3fv); - PY_MOD_ADD_METHOD(Vertex3i); - PY_MOD_ADD_METHOD(Vertex3iv); - PY_MOD_ADD_METHOD(Vertex3s); - PY_MOD_ADD_METHOD(Vertex3sv); - PY_MOD_ADD_METHOD(Vertex4d); - PY_MOD_ADD_METHOD(Vertex4dv); - PY_MOD_ADD_METHOD(Vertex4f); - PY_MOD_ADD_METHOD(Vertex4fv); - PY_MOD_ADD_METHOD(Vertex4i); - PY_MOD_ADD_METHOD(Vertex4iv); - PY_MOD_ADD_METHOD(Vertex4s); - PY_MOD_ADD_METHOD(Vertex4sv); - } - /* GL_VERSION_1_1 */ { @@ -2043,27 +1778,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexSubImage1D); PY_MOD_ADD_METHOD(TexSubImage2D); } - /* adding in GL_VERSION_1_1 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(AreTexturesResident); - PY_MOD_ADD_METHOD(ArrayElement); - PY_MOD_ADD_METHOD(ColorPointer); - PY_MOD_ADD_METHOD(DisableClientState); - PY_MOD_ADD_METHOD(EdgeFlagPointer); - PY_MOD_ADD_METHOD(EnableClientState); - PY_MOD_ADD_METHOD(GetPointerv); - PY_MOD_ADD_METHOD(IndexPointer); - PY_MOD_ADD_METHOD(Indexub); - PY_MOD_ADD_METHOD(Indexubv); - PY_MOD_ADD_METHOD(InterleavedArrays); - PY_MOD_ADD_METHOD(NormalPointer); - PY_MOD_ADD_METHOD(PopClientAttrib); - PY_MOD_ADD_METHOD(PrioritizeTextures); - PY_MOD_ADD_METHOD(PushClientAttrib); - PY_MOD_ADD_METHOD(TexCoordPointer); - PY_MOD_ADD_METHOD(VertexPointer); - } - /* GL_VERSION_1_2 */ { @@ -2073,7 +1787,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexSubImage3D); } - /* GL_VERSION_1_3 */ { PY_MOD_ADD_METHOD(ActiveTexture); @@ -2086,47 +1799,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(GetCompressedTexImage); PY_MOD_ADD_METHOD(SampleCoverage); } - /* adding in GL_VERSION_1_3 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(ClientActiveTexture); - PY_MOD_ADD_METHOD(LoadTransposeMatrixd); - PY_MOD_ADD_METHOD(LoadTransposeMatrixf); - PY_MOD_ADD_METHOD(MultTransposeMatrixd); - PY_MOD_ADD_METHOD(MultTransposeMatrixf); - PY_MOD_ADD_METHOD(MultiTexCoord1d); - PY_MOD_ADD_METHOD(MultiTexCoord1dv); - PY_MOD_ADD_METHOD(MultiTexCoord1f); - PY_MOD_ADD_METHOD(MultiTexCoord1fv); - PY_MOD_ADD_METHOD(MultiTexCoord1i); - PY_MOD_ADD_METHOD(MultiTexCoord1iv); - PY_MOD_ADD_METHOD(MultiTexCoord1s); - PY_MOD_ADD_METHOD(MultiTexCoord1sv); - PY_MOD_ADD_METHOD(MultiTexCoord2d); - PY_MOD_ADD_METHOD(MultiTexCoord2dv); - PY_MOD_ADD_METHOD(MultiTexCoord2f); - PY_MOD_ADD_METHOD(MultiTexCoord2fv); - PY_MOD_ADD_METHOD(MultiTexCoord2i); - PY_MOD_ADD_METHOD(MultiTexCoord2iv); - PY_MOD_ADD_METHOD(MultiTexCoord2s); - PY_MOD_ADD_METHOD(MultiTexCoord2sv); - PY_MOD_ADD_METHOD(MultiTexCoord3d); - PY_MOD_ADD_METHOD(MultiTexCoord3dv); - PY_MOD_ADD_METHOD(MultiTexCoord3f); - PY_MOD_ADD_METHOD(MultiTexCoord3fv); - PY_MOD_ADD_METHOD(MultiTexCoord3i); - PY_MOD_ADD_METHOD(MultiTexCoord3iv); - PY_MOD_ADD_METHOD(MultiTexCoord3s); - PY_MOD_ADD_METHOD(MultiTexCoord3sv); - PY_MOD_ADD_METHOD(MultiTexCoord4d); - PY_MOD_ADD_METHOD(MultiTexCoord4dv); - PY_MOD_ADD_METHOD(MultiTexCoord4f); - PY_MOD_ADD_METHOD(MultiTexCoord4fv); - PY_MOD_ADD_METHOD(MultiTexCoord4i); - PY_MOD_ADD_METHOD(MultiTexCoord4iv); - PY_MOD_ADD_METHOD(MultiTexCoord4s); - PY_MOD_ADD_METHOD(MultiTexCoord4sv); - } - /* GL_VERSION_1_4 */ { @@ -2134,7 +1806,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(BlendEquation); } - /* GL_VERSION_1_5 */ { PY_MOD_ADD_METHOD(BeginQuery); @@ -2158,7 +1829,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UnmapBuffer); } - /* GL_VERSION_2_0 */ { PY_MOD_ADD_METHOD(AttachShader); @@ -2256,7 +1926,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(VertexAttribPointer); } - /* GL_VERSION_2_1 */ { PY_MOD_ADD_METHOD(UniformMatrix2x3fv); @@ -2267,7 +1936,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UniformMatrix4x3fv); } - /* GL_VERSION_3_0 */ { PY_MOD_ADD_METHOD(BindVertexArray); @@ -2276,7 +1944,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(IsVertexArray); } - /* GL_VERSION_3_1 */ { PY_MOD_ADD_METHOD(BindBufferBase); @@ -2291,7 +1958,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UniformBlockBinding); } - /* GL_VERSION_3_2 */ { PY_MOD_ADD_METHOD(FramebufferTexture); @@ -2303,7 +1969,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexImage3DMultisample); } - /* GL_VERSION_3_3 */ { PY_MOD_ADD_METHOD(ColorP3ui); @@ -2544,338 +2209,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_XOR); PY_DICT_ADD_INT(GL_ZERO); } - /* adding in GL_VERSION_1_1 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_2D); - PY_DICT_ADD_INT(GL_2_BYTES); - PY_DICT_ADD_INT(GL_3D); - PY_DICT_ADD_INT(GL_3D_COLOR); - PY_DICT_ADD_INT(GL_3D_COLOR_TEXTURE); - PY_DICT_ADD_INT(GL_3_BYTES); - PY_DICT_ADD_INT(GL_4D_COLOR_TEXTURE); - PY_DICT_ADD_INT(GL_4_BYTES); - PY_DICT_ADD_INT(GL_ACCUM); - PY_DICT_ADD_INT(GL_ACCUM_ALPHA_BITS); - PY_DICT_ADD_INT(GL_ACCUM_BLUE_BITS); - PY_DICT_ADD_INT(GL_ACCUM_BUFFER_BIT); - PY_DICT_ADD_INT(GL_ACCUM_CLEAR_VALUE); - PY_DICT_ADD_INT(GL_ACCUM_GREEN_BITS); - PY_DICT_ADD_INT(GL_ACCUM_RED_BITS); - PY_DICT_ADD_INT(GL_ADD); - PY_DICT_ADD_INT(GL_ALL_ATTRIB_BITS); - PY_DICT_ADD_INT(GL_ALPHA12); - PY_DICT_ADD_INT(GL_ALPHA16); - PY_DICT_ADD_INT(GL_ALPHA4); - PY_DICT_ADD_INT(GL_ALPHA8); - PY_DICT_ADD_INT(GL_ALPHA_BIAS); - PY_DICT_ADD_INT(GL_ALPHA_BITS); - PY_DICT_ADD_INT(GL_ALPHA_SCALE); - PY_DICT_ADD_INT(GL_ALPHA_TEST); - PY_DICT_ADD_INT(GL_ALPHA_TEST_FUNC); - PY_DICT_ADD_INT(GL_ALPHA_TEST_REF); - PY_DICT_ADD_INT(GL_AMBIENT); - PY_DICT_ADD_INT(GL_AMBIENT_AND_DIFFUSE); - PY_DICT_ADD_INT(GL_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_AUTO_NORMAL); - PY_DICT_ADD_INT(GL_AUX0); - PY_DICT_ADD_INT(GL_AUX1); - PY_DICT_ADD_INT(GL_AUX2); - PY_DICT_ADD_INT(GL_AUX3); - PY_DICT_ADD_INT(GL_AUX_BUFFERS); - PY_DICT_ADD_INT(GL_BITMAP); - PY_DICT_ADD_INT(GL_BITMAP_TOKEN); - PY_DICT_ADD_INT(GL_BLUE_BIAS); - PY_DICT_ADD_INT(GL_BLUE_BITS); - PY_DICT_ADD_INT(GL_BLUE_SCALE); - PY_DICT_ADD_INT(GL_C3F_V3F); - PY_DICT_ADD_INT(GL_C4F_N3F_V3F); - PY_DICT_ADD_INT(GL_C4UB_V2F); - PY_DICT_ADD_INT(GL_C4UB_V3F); - PY_DICT_ADD_INT(GL_CLAMP); - PY_DICT_ADD_INT(GL_CLIENT_ALL_ATTRIB_BITS); - PY_DICT_ADD_INT(GL_CLIENT_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_CLIENT_PIXEL_STORE_BIT); - PY_DICT_ADD_INT(GL_CLIENT_VERTEX_ARRAY_BIT); - PY_DICT_ADD_INT(GL_CLIP_PLANE0); - PY_DICT_ADD_INT(GL_CLIP_PLANE1); - PY_DICT_ADD_INT(GL_CLIP_PLANE2); - PY_DICT_ADD_INT(GL_CLIP_PLANE3); - PY_DICT_ADD_INT(GL_CLIP_PLANE4); - PY_DICT_ADD_INT(GL_CLIP_PLANE5); - PY_DICT_ADD_INT(GL_COEFF); - PY_DICT_ADD_INT(GL_COLOR_ARRAY); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_COLOR_INDEX); - PY_DICT_ADD_INT(GL_COLOR_INDEXES); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL_FACE); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL_PARAMETER); - PY_DICT_ADD_INT(GL_COMPILE); - PY_DICT_ADD_INT(GL_COMPILE_AND_EXECUTE); - PY_DICT_ADD_INT(GL_CONSTANT_ATTENUATION); - PY_DICT_ADD_INT(GL_COPY_PIXEL_TOKEN); - PY_DICT_ADD_INT(GL_CURRENT_BIT); - PY_DICT_ADD_INT(GL_CURRENT_COLOR); - PY_DICT_ADD_INT(GL_CURRENT_INDEX); - PY_DICT_ADD_INT(GL_CURRENT_NORMAL); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_COLOR); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_DISTANCE); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_INDEX); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_POSITION); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_POSITION_VALID); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_CURRENT_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_DECAL); - PY_DICT_ADD_INT(GL_DEPTH_BIAS); - PY_DICT_ADD_INT(GL_DEPTH_BITS); - PY_DICT_ADD_INT(GL_DEPTH_SCALE); - PY_DICT_ADD_INT(GL_DIFFUSE); - PY_DICT_ADD_INT(GL_DOMAIN); - PY_DICT_ADD_INT(GL_DRAW_PIXEL_TOKEN); - PY_DICT_ADD_INT(GL_EDGE_FLAG); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_EMISSION); - PY_DICT_ADD_INT(GL_ENABLE_BIT); - PY_DICT_ADD_INT(GL_EVAL_BIT); - PY_DICT_ADD_INT(GL_EXP); - PY_DICT_ADD_INT(GL_EXP2); - PY_DICT_ADD_INT(GL_EYE_LINEAR); - PY_DICT_ADD_INT(GL_EYE_PLANE); - PY_DICT_ADD_INT(GL_FEEDBACK); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_POINTER); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_SIZE); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_TYPE); - PY_DICT_ADD_INT(GL_FLAT); - PY_DICT_ADD_INT(GL_FOG); - PY_DICT_ADD_INT(GL_FOG_BIT); - PY_DICT_ADD_INT(GL_FOG_COLOR); - PY_DICT_ADD_INT(GL_FOG_DENSITY); - PY_DICT_ADD_INT(GL_FOG_END); - PY_DICT_ADD_INT(GL_FOG_HINT); - PY_DICT_ADD_INT(GL_FOG_INDEX); - PY_DICT_ADD_INT(GL_FOG_MODE); - PY_DICT_ADD_INT(GL_FOG_START); - PY_DICT_ADD_INT(GL_GREEN_BIAS); - PY_DICT_ADD_INT(GL_GREEN_BITS); - PY_DICT_ADD_INT(GL_GREEN_SCALE); - PY_DICT_ADD_INT(GL_HINT_BIT); - PY_DICT_ADD_INT(GL_INDEX_ARRAY); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_INDEX_BITS); - PY_DICT_ADD_INT(GL_INDEX_CLEAR_VALUE); - PY_DICT_ADD_INT(GL_INDEX_LOGIC_OP); - PY_DICT_ADD_INT(GL_INDEX_MODE); - PY_DICT_ADD_INT(GL_INDEX_OFFSET); - PY_DICT_ADD_INT(GL_INDEX_SHIFT); - PY_DICT_ADD_INT(GL_INDEX_WRITEMASK); - PY_DICT_ADD_INT(GL_INTENSITY); - PY_DICT_ADD_INT(GL_INTENSITY12); - PY_DICT_ADD_INT(GL_INTENSITY16); - PY_DICT_ADD_INT(GL_INTENSITY4); - PY_DICT_ADD_INT(GL_INTENSITY8); - PY_DICT_ADD_INT(GL_LIGHT0); - PY_DICT_ADD_INT(GL_LIGHT1); - PY_DICT_ADD_INT(GL_LIGHT2); - PY_DICT_ADD_INT(GL_LIGHT3); - PY_DICT_ADD_INT(GL_LIGHT4); - PY_DICT_ADD_INT(GL_LIGHT5); - PY_DICT_ADD_INT(GL_LIGHT6); - PY_DICT_ADD_INT(GL_LIGHT7); - PY_DICT_ADD_INT(GL_LIGHTING); - PY_DICT_ADD_INT(GL_LIGHTING_BIT); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_AMBIENT); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_LOCAL_VIEWER); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_TWO_SIDE); - PY_DICT_ADD_INT(GL_LINEAR_ATTENUATION); - PY_DICT_ADD_INT(GL_LINE_BIT); - PY_DICT_ADD_INT(GL_LINE_RESET_TOKEN); - PY_DICT_ADD_INT(GL_LINE_STIPPLE); - PY_DICT_ADD_INT(GL_LINE_STIPPLE_PATTERN); - PY_DICT_ADD_INT(GL_LINE_STIPPLE_REPEAT); - PY_DICT_ADD_INT(GL_LINE_TOKEN); - PY_DICT_ADD_INT(GL_LIST_BASE); - PY_DICT_ADD_INT(GL_LIST_BIT); - PY_DICT_ADD_INT(GL_LIST_INDEX); - PY_DICT_ADD_INT(GL_LIST_MODE); - PY_DICT_ADD_INT(GL_LOAD); - PY_DICT_ADD_INT(GL_LOGIC_OP); - PY_DICT_ADD_INT(GL_LUMINANCE); - PY_DICT_ADD_INT(GL_LUMINANCE12); - PY_DICT_ADD_INT(GL_LUMINANCE12_ALPHA12); - PY_DICT_ADD_INT(GL_LUMINANCE12_ALPHA4); - PY_DICT_ADD_INT(GL_LUMINANCE16); - PY_DICT_ADD_INT(GL_LUMINANCE16_ALPHA16); - PY_DICT_ADD_INT(GL_LUMINANCE4); - PY_DICT_ADD_INT(GL_LUMINANCE4_ALPHA4); - PY_DICT_ADD_INT(GL_LUMINANCE6_ALPHA2); - PY_DICT_ADD_INT(GL_LUMINANCE8); - PY_DICT_ADD_INT(GL_LUMINANCE8_ALPHA8); - PY_DICT_ADD_INT(GL_LUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_MAP1_COLOR_4); - PY_DICT_ADD_INT(GL_MAP1_GRID_DOMAIN); - PY_DICT_ADD_INT(GL_MAP1_GRID_SEGMENTS); - PY_DICT_ADD_INT(GL_MAP1_INDEX); - PY_DICT_ADD_INT(GL_MAP1_NORMAL); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_1); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_2); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_3); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_4); - PY_DICT_ADD_INT(GL_MAP1_VERTEX_3); - PY_DICT_ADD_INT(GL_MAP1_VERTEX_4); - PY_DICT_ADD_INT(GL_MAP2_COLOR_4); - PY_DICT_ADD_INT(GL_MAP2_GRID_DOMAIN); - PY_DICT_ADD_INT(GL_MAP2_GRID_SEGMENTS); - PY_DICT_ADD_INT(GL_MAP2_INDEX); - PY_DICT_ADD_INT(GL_MAP2_NORMAL); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_1); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_2); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_3); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_4); - PY_DICT_ADD_INT(GL_MAP2_VERTEX_3); - PY_DICT_ADD_INT(GL_MAP2_VERTEX_4); - PY_DICT_ADD_INT(GL_MAP_COLOR); - PY_DICT_ADD_INT(GL_MAP_STENCIL); - PY_DICT_ADD_INT(GL_MATRIX_MODE); - PY_DICT_ADD_INT(GL_MAX_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_CLIP_PLANES); - PY_DICT_ADD_INT(GL_MAX_EVAL_ORDER); - PY_DICT_ADD_INT(GL_MAX_LIGHTS); - PY_DICT_ADD_INT(GL_MAX_LIST_NESTING); - PY_DICT_ADD_INT(GL_MAX_MODELVIEW_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_NAME_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_PIXEL_MAP_TABLE); - PY_DICT_ADD_INT(GL_MAX_PROJECTION_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MODELVIEW); - PY_DICT_ADD_INT(GL_MODELVIEW_MATRIX); - PY_DICT_ADD_INT(GL_MODELVIEW_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MODULATE); - PY_DICT_ADD_INT(GL_MULT); - PY_DICT_ADD_INT(GL_N3F_V3F); - PY_DICT_ADD_INT(GL_NAME_STACK_DEPTH); - PY_DICT_ADD_INT(GL_NORMALIZE); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_OBJECT_LINEAR); - PY_DICT_ADD_INT(GL_OBJECT_PLANE); - PY_DICT_ADD_INT(GL_ORDER); - PY_DICT_ADD_INT(GL_PASS_THROUGH_TOKEN); - PY_DICT_ADD_INT(GL_PERSPECTIVE_CORRECTION_HINT); - PY_DICT_ADD_INT(GL_PIXEL_MAP_A_TO_A); - PY_DICT_ADD_INT(GL_PIXEL_MAP_A_TO_A_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_B_TO_B); - PY_DICT_ADD_INT(GL_PIXEL_MAP_B_TO_B_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_G_TO_G); - PY_DICT_ADD_INT(GL_PIXEL_MAP_G_TO_G_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_A); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_A_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_B); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_B_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_G); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_G_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_I); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_I_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_R); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_R_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_R_TO_R); - PY_DICT_ADD_INT(GL_PIXEL_MAP_R_TO_R_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_S_TO_S); - PY_DICT_ADD_INT(GL_PIXEL_MAP_S_TO_S_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MODE_BIT); - PY_DICT_ADD_INT(GL_POINT_BIT); - PY_DICT_ADD_INT(GL_POINT_SMOOTH); - PY_DICT_ADD_INT(GL_POINT_SMOOTH_HINT); - PY_DICT_ADD_INT(GL_POINT_TOKEN); - PY_DICT_ADD_INT(GL_POLYGON); - PY_DICT_ADD_INT(GL_POLYGON_BIT); - PY_DICT_ADD_INT(GL_POLYGON_STIPPLE); - PY_DICT_ADD_INT(GL_POLYGON_STIPPLE_BIT); - PY_DICT_ADD_INT(GL_POLYGON_TOKEN); - PY_DICT_ADD_INT(GL_POSITION); - PY_DICT_ADD_INT(GL_PROJECTION); - PY_DICT_ADD_INT(GL_PROJECTION_MATRIX); - PY_DICT_ADD_INT(GL_PROJECTION_STACK_DEPTH); - PY_DICT_ADD_INT(GL_Q); - PY_DICT_ADD_INT(GL_QUADRATIC_ATTENUATION); - PY_DICT_ADD_INT(GL_QUADS); - PY_DICT_ADD_INT(GL_QUAD_STRIP); - PY_DICT_ADD_INT(GL_R); - PY_DICT_ADD_INT(GL_RED_BIAS); - PY_DICT_ADD_INT(GL_RED_BITS); - PY_DICT_ADD_INT(GL_RED_SCALE); - PY_DICT_ADD_INT(GL_RENDER); - PY_DICT_ADD_INT(GL_RENDER_MODE); - PY_DICT_ADD_INT(GL_RETURN); - PY_DICT_ADD_INT(GL_RGBA_MODE); - PY_DICT_ADD_INT(GL_S); - PY_DICT_ADD_INT(GL_SCISSOR_BIT); - PY_DICT_ADD_INT(GL_SELECT); - PY_DICT_ADD_INT(GL_SELECTION_BUFFER_POINTER); - PY_DICT_ADD_INT(GL_SELECTION_BUFFER_SIZE); - PY_DICT_ADD_INT(GL_SHADE_MODEL); - PY_DICT_ADD_INT(GL_SHININESS); - PY_DICT_ADD_INT(GL_SMOOTH); - PY_DICT_ADD_INT(GL_SPECULAR); - PY_DICT_ADD_INT(GL_SPHERE_MAP); - PY_DICT_ADD_INT(GL_SPOT_CUTOFF); - PY_DICT_ADD_INT(GL_SPOT_DIRECTION); - PY_DICT_ADD_INT(GL_SPOT_EXPONENT); - PY_DICT_ADD_INT(GL_STACK_OVERFLOW); - PY_DICT_ADD_INT(GL_STACK_UNDERFLOW); - PY_DICT_ADD_INT(GL_STENCIL_BITS); - PY_DICT_ADD_INT(GL_T); - PY_DICT_ADD_INT(GL_T2F_C3F_V3F); - PY_DICT_ADD_INT(GL_T2F_C4F_N3F_V3F); - PY_DICT_ADD_INT(GL_T2F_C4UB_V3F); - PY_DICT_ADD_INT(GL_T2F_N3F_V3F); - PY_DICT_ADD_INT(GL_T2F_V3F); - PY_DICT_ADD_INT(GL_T4F_C4F_N3F_V4F); - PY_DICT_ADD_INT(GL_T4F_V4F); - PY_DICT_ADD_INT(GL_TEXTURE_BIT); - PY_DICT_ADD_INT(GL_TEXTURE_BORDER); - PY_DICT_ADD_INT(GL_TEXTURE_COMPONENTS); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_ENV); - PY_DICT_ADD_INT(GL_TEXTURE_ENV_COLOR); - PY_DICT_ADD_INT(GL_TEXTURE_ENV_MODE); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_MODE); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_Q); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_R); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_S); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_T); - PY_DICT_ADD_INT(GL_TEXTURE_INTENSITY_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_LUMINANCE_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_MATRIX); - PY_DICT_ADD_INT(GL_TEXTURE_PRIORITY); - PY_DICT_ADD_INT(GL_TEXTURE_RESIDENT); - PY_DICT_ADD_INT(GL_TEXTURE_STACK_DEPTH); - PY_DICT_ADD_INT(GL_TRANSFORM_BIT); - PY_DICT_ADD_INT(GL_V2F); - PY_DICT_ADD_INT(GL_V3F); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_VIEWPORT_BIT); - PY_DICT_ADD_INT(GL_ZOOM_X); - PY_DICT_ADD_INT(GL_ZOOM_Y); - } - /* GL_VERSION_1_2 */ { @@ -2916,15 +2249,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_UNSIGNED_SHORT_5_6_5); PY_DICT_ADD_INT(GL_UNSIGNED_SHORT_5_6_5_REV); } - /* adding in GL_VERSION_1_2 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ALIASED_POINT_SIZE_RANGE); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_COLOR_CONTROL); - PY_DICT_ADD_INT(GL_RESCALE_NORMAL); - PY_DICT_ADD_INT(GL_SEPARATE_SPECULAR_COLOR); - PY_DICT_ADD_INT(GL_SINGLE_COLOR); - } - /* GL_VERSION_1_3 */ { @@ -2988,47 +2312,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y); PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z); } - /* adding in GL_VERSION_1_3 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ADD_SIGNED); - PY_DICT_ADD_INT(GL_CLIENT_ACTIVE_TEXTURE); - PY_DICT_ADD_INT(GL_COMBINE); - PY_DICT_ADD_INT(GL_COMBINE_ALPHA); - PY_DICT_ADD_INT(GL_COMBINE_RGB); - PY_DICT_ADD_INT(GL_COMPRESSED_ALPHA); - PY_DICT_ADD_INT(GL_COMPRESSED_INTENSITY); - PY_DICT_ADD_INT(GL_COMPRESSED_LUMINANCE); - PY_DICT_ADD_INT(GL_COMPRESSED_LUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_CONSTANT); - PY_DICT_ADD_INT(GL_DOT3_RGB); - PY_DICT_ADD_INT(GL_DOT3_RGBA); - PY_DICT_ADD_INT(GL_INTERPOLATE); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_UNITS); - PY_DICT_ADD_INT(GL_MULTISAMPLE_BIT); - PY_DICT_ADD_INT(GL_NORMAL_MAP); - PY_DICT_ADD_INT(GL_OPERAND0_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND0_RGB); - PY_DICT_ADD_INT(GL_OPERAND1_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND1_RGB); - PY_DICT_ADD_INT(GL_OPERAND2_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND2_RGB); - PY_DICT_ADD_INT(GL_PREVIOUS); - PY_DICT_ADD_INT(GL_PRIMARY_COLOR); - PY_DICT_ADD_INT(GL_REFLECTION_MAP); - PY_DICT_ADD_INT(GL_RGB_SCALE); - PY_DICT_ADD_INT(GL_SOURCE0_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE0_RGB); - PY_DICT_ADD_INT(GL_SOURCE1_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE1_RGB); - PY_DICT_ADD_INT(GL_SOURCE2_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE2_RGB); - PY_DICT_ADD_INT(GL_SUBTRACT); - PY_DICT_ADD_INT(GL_TRANSPOSE_COLOR_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_MODELVIEW_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_PROJECTION_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_TEXTURE_MATRIX); - } - /* GL_VERSION_1_4 */ { @@ -3058,33 +2341,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_TEXTURE_DEPTH_SIZE); PY_DICT_ADD_INT(GL_TEXTURE_LOD_BIAS); } - /* adding in GL_VERSION_1_4 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COLOR_SUM); - PY_DICT_ADD_INT(GL_COMPARE_R_TO_TEXTURE); - PY_DICT_ADD_INT(GL_CURRENT_FOG_COORDINATE); - PY_DICT_ADD_INT(GL_CURRENT_SECONDARY_COLOR); - PY_DICT_ADD_INT(GL_DEPTH_TEXTURE_MODE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_SOURCE); - PY_DICT_ADD_INT(GL_FRAGMENT_DEPTH); - PY_DICT_ADD_INT(GL_GENERATE_MIPMAP); - PY_DICT_ADD_INT(GL_GENERATE_MIPMAP_HINT); - PY_DICT_ADD_INT(GL_POINT_DISTANCE_ATTENUATION); - PY_DICT_ADD_INT(GL_POINT_SIZE_MAX); - PY_DICT_ADD_INT(GL_POINT_SIZE_MIN); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_FILTER_CONTROL); - } - /* GL_VERSION_1_5 */ { @@ -3117,32 +2373,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING); PY_DICT_ADD_INT(GL_WRITE_ONLY); } - /* adding in GL_VERSION_1_5 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COLOR_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_CURRENT_FOG_COORD); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_FOG_COORD_SRC); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_SRC0_ALPHA); - PY_DICT_ADD_INT(GL_SRC0_RGB); - PY_DICT_ADD_INT(GL_SRC1_RGB); - PY_DICT_ADD_INT(GL_SRC2_ALPHA); - PY_DICT_ADD_INT(GL_SRC2_RGB); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_WEIGHT_ARRAY_BUFFER_BINDING); - } - /* GL_VERSION_2_0 */ { @@ -3227,14 +2457,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_PROGRAM_POINT_SIZE); PY_DICT_ADD_INT(GL_VERTEX_SHADER); } - /* adding in GL_VERSION_2_0 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COORD_REPLACE); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_POINT_SPRITE); - PY_DICT_ADD_INT(GL_VERTEX_PROGRAM_TWO_SIDE); - } - /* GL_VERSION_2_1 */ { @@ -3255,16 +2477,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_SRGB8_ALPHA8); PY_DICT_ADD_INT(GL_SRGB_ALPHA); } - /* adding in GL_VERSION_2_1 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COMPRESSED_SLUMINANCE); - PY_DICT_ADD_INT(GL_COMPRESSED_SLUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_SECONDARY_COLOR); - PY_DICT_ADD_INT(GL_SLUMINANCE); - PY_DICT_ADD_INT(GL_SLUMINANCE8); - PY_DICT_ADD_INT(GL_SLUMINANCE8_ALPHA8); - PY_DICT_ADD_INT(GL_SLUMINANCE_ALPHA); - } /* GL_VERSION_3_0 */ { @@ -3505,14 +2717,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_ARRAY_BINDING); PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_INTEGER); } - /* adding in GL_VERSION_3_0 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ALPHA_INTEGER); - PY_DICT_ADD_INT(GL_CLAMP_FRAGMENT_COLOR); - PY_DICT_ADD_INT(GL_CLAMP_VERTEX_COLOR); - PY_DICT_ADD_INT(GL_TEXTURE_INTENSITY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_LUMINANCE_TYPE); - } /* GL_VERSION_3_1 */ { @@ -3579,7 +2783,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_BUFFER); } - /* GL_VERSION_3_2 */ { PY_DICT_ADD_INT(GL_ALREADY_SIGNALED); @@ -3685,4 +2888,4 @@ static PyObject *Method_ShaderSource(PyObject *UNUSED(self), PyObject *args) } -/** \} */
\ No newline at end of file +/** \} */ diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 69f1e297b43..02bd1fdbe39 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -114,6 +114,7 @@ static PyObject *py_blf_aspect(PyObject *UNUSED(self), PyObject *args) } +#if BLF_BLUR_ENABLE PyDoc_STRVAR(py_blf_blur_doc, ".. function:: blur(fontid, radius)\n" "\n" @@ -135,6 +136,7 @@ static PyObject *py_blf_blur(PyObject *UNUSED(self), PyObject *args) Py_RETURN_NONE; } +#endif PyDoc_STRVAR(py_blf_draw_doc, @@ -418,7 +420,9 @@ static PyObject *py_blf_unload(PyObject *UNUSED(self), PyObject *args) /*----------------------------MODULE INIT-------------------------*/ static PyMethodDef BLF_methods[] = { {"aspect", (PyCFunction) py_blf_aspect, METH_VARARGS, py_blf_aspect_doc}, +#if BLF_BLUR_ENABLE {"blur", (PyCFunction) py_blf_blur, METH_VARARGS, py_blf_blur_doc}, +#endif {"clipping", (PyCFunction) py_blf_clipping, METH_VARARGS, py_blf_clipping_doc}, {"word_wrap", (PyCFunction) py_blf_word_wrap, METH_VARARGS, py_blf_word_wrap_doc}, {"disable", (PyCFunction) py_blf_disable, METH_VARARGS, py_blf_disable_doc}, diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 1022aeeec66..6dbcf474e77 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -361,7 +361,6 @@ static void init_frame_smoke(VoxelData *vd, int cfra) #else // WITH_SMOKE (void)vd; - (void)cfra; vd->dataset = NULL; #endif diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index b6245a8c0d1..b5c19534b15 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -25,6 +25,8 @@ set(INC . + manipulators + manipulators/intern ../blenfont ../blenkernel ../blenlib @@ -68,6 +70,10 @@ set(SRC intern/wm_subwindow.c intern/wm_window.c intern/wm_stereo.c + manipulators/intern/wm_manipulator.c + manipulators/intern/wm_manipulatorgroup.c + manipulators/intern/wm_manipulatormap.c + manipulators/intern/manipulator_library/manipulator_library_utils.c WM_api.h WM_keymap.h @@ -80,6 +86,11 @@ set(SRC wm_files.h wm_subwindow.h wm_window.h + manipulators/WM_manipulator_api.h + manipulators/WM_manipulator_types.h + manipulators/wm_manipulator_wmapi.h + manipulators/intern/wm_manipulator_intern.h + manipulators/intern/manipulator_library/manipulator_library_intern.h ) if(WITH_AUDASPACE) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 2b82f1becb3..2809795268d 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -42,6 +42,9 @@ #include "WM_keymap.h" #include "BLI_compiler_attrs.h" +/* Include external manipulator API's */ +#include "manipulators/WM_manipulator_api.h" + #ifdef __cplusplus extern "C" { #endif @@ -64,12 +67,16 @@ struct wmDrag; struct ImBuf; struct ImageFormatData; struct ARegion; +struct ScrArea; #ifdef WITH_INPUT_NDOF struct wmNDOFMotionData; #endif typedef struct wmJob wmJob; +typedef struct wmManipulator wmManipulator; +typedef struct wmManipulatorMap wmManipulatorMap; +typedef struct wmManipulatorMapType wmManipulatorMapType; /* general API */ void WM_init_state_size_set (int stax, int stay, int sizx, int sizy); @@ -171,6 +178,9 @@ void WM_event_free_ui_handler_all( wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove); struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op); +void WM_event_modal_handler_area_replace(wmWindow *win, const struct ScrArea *old_area, struct ScrArea *new_area); +void WM_event_modal_handler_region_replace(wmWindow *win, const struct ARegion *old_region, struct ARegion *new_region); + void WM_event_remove_handlers(struct bContext *C, ListBase *handlers); /* handler flag */ diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index cd46e24264d..3bed4dac2cf 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -119,6 +119,7 @@ struct ImBuf; /* exported types for WM */ #include "wm_cursors.h" #include "wm_event_types.h" +#include "manipulators/WM_manipulator_types.h" /* ************** wmOperatorType ************************ */ @@ -568,6 +569,9 @@ typedef struct wmOperatorType { /* pointer to modal keymap, do not free! */ struct wmKeyMap *modalkeymap; + /* manipulator-group that is accessible while operator runs */ + wmManipulatorGroupType *mgrouptype; + /* python needs the operator type as well */ int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 3a53906a8e8..85a313b3f81 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -268,10 +268,10 @@ void wm_drags_check_ops(bContext *C, wmEvent *event) static void wm_drop_operator_draw(const char *name, int x, int y) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - const unsigned char fg[4] = {255, 255, 255, 255}; - const unsigned char bg[4] = {0, 0, 0, 50}; + const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; - UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg); + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg); } static const char *wm_drag_name(wmDrag *drag) diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 3825db14e93..0758fa84e20 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -59,6 +59,7 @@ #include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "RE_engine.h" @@ -79,6 +80,8 @@ #define WIN_FRONT_OK 2 #define WIN_BOTH_OK 3 +#define USE_TEXTURE_RECTANGLE 1 + /* ******************* drawing, overlays *************** */ @@ -128,7 +131,7 @@ static bool wm_area_test_invalid_backbuf(ScrArea *sa) if (sa->spacetype == SPACE_VIEW3D) return (((View3D *)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF) != 0; else - return 1; + return true; } static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion *ar) @@ -372,62 +375,55 @@ static void wm_draw_triple_fail(bContext *C, wmWindow *win) { wm_draw_window_clear(win); - win->drawfail = 1; + win->drawfail = true; wm_method_draw_overlap_all(C, win, 0); } -static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) +static bool wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) { - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); - - GLint maxsize; - /* compute texture sizes */ - if (GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) { - triple->target = GL_TEXTURE_RECTANGLE_ARB; - } - else { - triple->target = GL_TEXTURE_2D; - } - - triple->x = winsize_x; - triple->y = winsize_y; + triple->x = WM_window_pixels_x(win); + triple->y = WM_window_pixels_y(win); + +#if USE_TEXTURE_RECTANGLE + /* GL_TEXTURE_RECTANGLE is part of GL 3.1 so we can use it soon without runtime checks */ + triple->target = GL_TEXTURE_RECTANGLE; +#else + triple->target = GL_TEXTURE_2D; +#endif /* generate texture names */ glGenTextures(1, &triple->bind); - if (!triple->bind) { - /* not the typical failure case but we handle it anyway */ - printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n"); - return 0; - } - /* proxy texture is only guaranteed to test for the cases that * there is only one texture in use, which may not be the case */ - maxsize = GPU_max_texture_size(); + const GLint maxsize = GPU_max_texture_size(); if (triple->x > maxsize || triple->y > maxsize) { - glBindTexture(triple->target, 0); printf("WM: failed to allocate texture for triple buffer drawing " - "(texture too large for graphics card).\n"); - return 0; + "(texture too large for graphics card).\n"); + return false; } /* setup actual texture */ glBindTexture(triple->target, triple->bind); - glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + /* no mipmaps */ +#if USE_TEXTURE_RECTANGLE + /* already has no mipmaps */ +#else + glTexParameteri(triple->target, GL_TEXTURE_MAX_LEVEL, 0); + /* GL_TEXTURE_BASE_LEVEL = 0 by default */ +#endif + glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(triple->target, 0); - /* not sure if this works everywhere .. */ - if (glGetError() == GL_OUT_OF_MEMORY) { - printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n"); - return 0; - } + glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(triple->target, 0); - return 1; + return true; } void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) @@ -435,44 +431,60 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) const int sizex = WM_window_pixels_x(win); const int sizey = WM_window_pixels_y(win); - float halfx, halfy, ratiox, ratioy; - /* wmOrtho for the screen has this same offset */ - ratiox = sizex; - ratioy = sizey; - halfx = GLA_PIXEL_OFS; - halfy = GLA_PIXEL_OFS; + float ratiox = sizex; + float ratioy = sizey; + float halfx = GLA_PIXEL_OFS; + float halfy = GLA_PIXEL_OFS; +#if USE_TEXTURE_RECTANGLE /* texture rectangle has unnormalized coordinates */ - if (triple->target == GL_TEXTURE_2D) { - ratiox /= triple->x; - ratioy /= triple->y; - halfx /= triple->x; - halfy /= triple->y; - } +#else + ratiox /= triple->x; + ratioy /= triple->y; + halfx /= triple->x; + halfy /= triple->y; +#endif - GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT); + VertexFormat *format = immVertexFormat(); + unsigned texcoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + const int activeTex = 7; /* arbitrary */ + glActiveTexture(GL_TEXTURE0 + activeTex); glBindTexture(triple->target, triple->bind); - glColor4f(1.0f, 1.0f, 1.0f, alpha); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(0, 0); +#if USE_TEXTURE_RECTANGLE + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA); +#else + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + /* TODO: make pure 2D version + * and a 2D_IMAGE (replace, not modulate) version for when alpha = 1.0 + */ +#endif + immUniform1f("alpha", alpha); + immUniform1i("image", activeTex); - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(sizex, 0); + immBegin(GL_QUADS, 4); - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(sizex, sizey); + immAttrib2f(texcoord, halfx, halfy); + immVertex2f(pos, 0.0f, 0.0f); - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(0, sizey); - glEnd(); + immAttrib2f(texcoord, ratiox + halfx, halfy); + immVertex2f(pos, sizex, 0.0f); - glBindTexture(triple->target, 0); + immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy); + immVertex2f(pos, sizex, sizey); + + immAttrib2f(texcoord, halfx, ratioy + halfy); + immVertex2f(pos, 0.0f, sizey); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immEnd(); + immUnbindProgram(); + + glBindTexture(triple->target, 0); + if (activeTex != 0) + glActiveTexture(GL_TEXTURE0); } static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) @@ -481,8 +493,8 @@ static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) const int sizey = WM_window_pixels_y(win); glBindTexture(triple->target, triple->bind); + /* what is GL_READ_BUFFER right now? */ glCopyTexSubImage2D(triple->target, 0, 0, 0, 0, 0, sizex, sizey); - glBindTexture(triple->target, 0); } @@ -503,16 +515,17 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl static void wm_method_draw_triple(bContext *C, wmWindow *win) { wmWindowManager *wm = CTX_wm_manager(C); - wmDrawTriple *triple; wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first; bScreen *screen = win->screen; ScrArea *sa; ARegion *ar; - int copytex = false; + bool copytex = false; if (drawdata && drawdata->triple) { - glClearColor(0, 0, 0, 0); + #if 0 /* why do we need to clear before overwriting? */ + glClearColor(1, 1, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + #endif wmSubWindowSet(win, screen->mainwin); @@ -543,7 +556,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) MEM_freeN(dd); } - triple = drawdata->triple; + wmDrawTriple *triple = drawdata->triple; /* draw marked area regions */ for (sa = screen->areabase.first; sa; sa = sa->next) { @@ -551,7 +564,6 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid && ar->do_draw) { - if (ar->overlap == false) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); @@ -651,8 +663,10 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi if (drawdata && drawdata->triple) { if (id == 0) { + #if 0 /* why do we need to clear before overwriting? */ glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + #endif wmSubWindowSet(win, screen->mainwin); @@ -838,20 +852,20 @@ static bool wm_draw_update_test_window(wmWindow *win) } if (do_draw) - return 1; + return true; if (win->screen->do_refresh) - return 1; + return true; if (win->screen->do_draw) - return 1; + return true; if (win->screen->do_draw_gesture) - return 1; + return true; if (win->screen->do_draw_paintcursor) - return 1; + return true; if (win->screen->do_draw_drag) - return 1; + return true; - return 0; + return false; } static int wm_automatic_draw_method(wmWindow *win) @@ -905,7 +919,6 @@ void wm_draw_update(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; - int drawmethod; #ifdef WITH_OPENSUBDIV BKE_subsurf_free_unused_buffers(); @@ -941,7 +954,7 @@ void wm_draw_update(bContext *C) if (win->screen->do_refresh) ED_screen_refresh(wm, win); - drawmethod = wm_automatic_draw_method(win); + int drawmethod = wm_automatic_draw_method(win); if (win->drawfail) wm_method_draw_overlap_all(C, win, 0); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index d2b0acd836b..1a831846af7 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -68,8 +68,6 @@ #include "RNA_access.h" -#include "GPU_debug.h" - #include "UI_interface.h" #include "PIL_time.h" @@ -1677,7 +1675,12 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand wm_handler_op_context(C, handler, event); wm_region_mouse_co(C, event); wm_event_modalkeymap(C, op, event, &dbl_click_disabled); - + + /* attach manipulator-map to handler if not there yet */ + if (ot->mgrouptype && !handler->manipulator_map) { + wm_manipulatorgroup_attach_to_modal_handler(C, handler, ot->mgrouptype, op); + } + if (ot->flag & OPTYPE_UNDO) wm->op_undo_depth++; @@ -1726,6 +1729,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand CTX_wm_region_set(C, NULL); } + /* update manipulators during modal handlers */ + wm_manipulatormaps_handled_modal_update(C, event, handler, ot); + /* remove modal handler, operator itself should have been canceled and freed */ if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) { WM_cursor_grab_disable(CTX_wm_window(C), NULL); @@ -2098,6 +2104,71 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } } } + else if (handler->manipulator_map) { + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + wmManipulatorMap *mmap = handler->manipulator_map; + wmManipulator *manipulator = wm_manipulatormap_get_highlighted_manipulator(mmap); + unsigned char part; + + wm_manipulatormap_handler_context(C, handler); + wm_region_mouse_co(C, event); + + /* handle manipulator highlighting */ + if (event->type == MOUSEMOVE && !wm_manipulatormap_get_active_manipulator(mmap)) { + manipulator = wm_manipulatormap_find_highlighted_manipulator(mmap, C, event, &part); + wm_manipulatormap_set_highlighted_manipulator(mmap, C, manipulator, part); + } + /* handle user configurable manipulator-map keymap */ + else if (manipulator) { + /* get user customized keymap from default one */ + const wmManipulatorGroup *highlightgroup = wm_manipulator_get_parent_group(manipulator); + const wmKeyMap *keymap = WM_keymap_active(wm, highlightgroup->type->keymap); + wmKeyMapItem *kmi; + + PRINT("%s: checking '%s' ...", __func__, keymap->idname); + + if (!keymap->poll || keymap->poll(C)) { + PRINT("pass\n"); + for (kmi = keymap->items.first; kmi; kmi = kmi->next) { + if (wm_eventmatch(event, kmi)) { + wmOperator *op = handler->op; + + PRINT("%s: item matched '%s'\n", __func__, kmi->idname); + + /* weak, but allows interactive callback to not use rawkey */ + event->keymap_idname = kmi->idname; + + /* handler->op is called later, we want keymap op to be triggered here */ + handler->op = NULL; + action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); + handler->op = op; + + if (action & WM_HANDLER_BREAK) { + if (action & WM_HANDLER_HANDLED) { + if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) + printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname); + } + else { + PRINT("%s: un-handled '%s'\n", __func__, kmi->idname); + } + } + } + } + } + else { + PRINT("fail\n"); + } + } + + /* restore the area */ + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + + if (handler->op) { + action |= wm_handler_operator_call(C, handlers, handler, event, NULL); + } + } else { /* modal, swallows all */ action |= wm_handler_operator_call(C, handlers, handler, event, NULL); @@ -2540,8 +2611,6 @@ void wm_event_do_handlers(bContext *C) /* update key configuration after handling events */ WM_keyconfig_update(wm); - - GPU_ASSERT_NO_GL_ERRORS("wm_event_do_handlers"); } /* ********** filesector handling ************ */ @@ -2578,7 +2647,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) wmWindow *win = CTX_wm_window(C); /* only allow 1 file selector open per window */ - for (handler = win->modalhandlers.first; handler; handler = handlernext) { + for (handler = win->handlers.first; handler; handler = handlernext) { handlernext = handler->next; if (handler->type == WM_HANDLER_FILESELECT) { @@ -2592,7 +2661,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) if (sfile->op == handler->op) { CTX_wm_area_set(C, sa); - wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL); + wm_handler_fileselect_do(C, &win->handlers, handler, EVT_FILESELECT_CANCEL); break; } } @@ -2600,7 +2669,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) /* if not found we stop the handler without changing the screen */ if (!sa) - wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL); + wm_handler_fileselect_do(C, &win->handlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL); } } @@ -2611,7 +2680,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) handler->op_area = CTX_wm_area(C); handler->op_region = CTX_wm_region(C); - BLI_addhead(&win->modalhandlers, handler); + BLI_addhead(&win->handlers, handler); /* check props once before invoking if check is available * ensures initial properties are valid */ @@ -2654,6 +2723,33 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op) return handler; } +/** + * Modal handlers store a pointer to an area which might be freed while the handler runs. + * Use this function to NULL all handler pointers to \a old_area. + */ +void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area) +{ + for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) { + if (handler->op_area == old_area) { + handler->op_area = new_area; + } + } +} + +/** + * Modal handlers store a pointer to a region which might be freed while the handler runs. + * Use this function to NULL all handler pointers to \a old_region. + */ +void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region) +{ + for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) { + if (handler->op_region == old_region) { + handler->op_region = new_region; + handler->op_region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW; + } + } +} + wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap) { wmEventHandler *handler; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index c11c398c616..fbbde2a6d28 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -169,6 +169,7 @@ void WM_init(bContext *C, int argc, const char **argv) BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ + BKE_region_callback_free_manipulatormap_set(wm_manipulatormap_delete); /* screen.c */ BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ @@ -529,6 +530,9 @@ void WM_exit_ext(bContext *C, const bool do_python) ED_gpencil_strokes_copybuf_free(); BKE_node_clipboard_clear(); + /* free manipulator-maps after freeing blender, so no deleted data get accessed during cleaning up of areas */ + wm_manipulatormaptypes_free(); + BLF_exit(); #ifdef WITH_INTERNATIONAL diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index b9fd4d2e762..7c68a0ce438 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -98,6 +98,7 @@ #include "ED_view3d.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "RNA_access.h" #include "RNA_define.h" @@ -491,6 +492,9 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot) BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL); WM_keyconfig_update_operatortype(); + if (ot->mgrouptype) { + WM_manipulatorgrouptype_unregister(NULL, G.main, ot->mgrouptype); + } MEM_freeN(ot); } @@ -2985,8 +2989,8 @@ static void radial_control_set_tex(RadialControl *rc) if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data, rc->use_secondary_tex))) { glGenTextures(1, &rc->gltex); glBindTexture(GL_TEXTURE_2D, rc->gltex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, ibuf->x, ibuf->y, 0, - GL_ALPHA, GL_FLOAT, ibuf->rect_float); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, ibuf->x, ibuf->y, 0, + GL_RED, GL_FLOAT, ibuf->rect_float); MEM_freeN(ibuf->rect_float); MEM_freeN(ibuf); } @@ -3019,13 +3023,26 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph RNA_property_float_get_array(fill_ptr, fill_prop, col); } - glColor4f(col[0], col[1], col[2], alpha); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); if (rc->gltex) { + + unsigned texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + glBindTexture(GL_TEXTURE_2D, rc->gltex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + GLint swizzleMask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR); + + immUniform4f("color", col[0], col[1], col[2], alpha); + immUniform1i("image", GL_TEXTURE0); /* set up rotation if available */ if (rc->rot_prop) { @@ -3035,18 +3052,21 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph } /* draw textured quad */ - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex2f(-radius, -radius); - glTexCoord2f(1, 0); - glVertex2f(radius, -radius); - glTexCoord2f(1, 1); - glVertex2f(radius, radius); - glTexCoord2f(0, 1); - glVertex2f(-radius, radius); - glEnd(); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immBegin(GL_QUADS, 4); + + immAttrib2f(texCoord, 0, 0); + immVertex2f(pos, -radius, -radius); + + immAttrib2f(texCoord, 1, 0); + immVertex2f(pos, radius, -radius); + + immAttrib2f(texCoord, 1, 1); + immVertex2f(pos, radius, radius); + + immAttrib2f(texCoord, 0, 1); + immVertex2f(pos, -radius, radius); + + immEnd(); /* undo rotation */ if (rc->rot_prop) @@ -3054,8 +3074,12 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph } else { /* flat color if no texture available */ - glutil_draw_filled_arc(0, M_PI * 2, radius, 40); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fvAlpha(col, alpha); + imm_draw_filled_circle(pos, 0.0f, 0.0f, radius, 40); } + + immUnbindProgram(); } static void radial_control_paint_cursor(bContext *C, int x, int y, void *customdata) @@ -3131,24 +3155,38 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd /* set line color */ if (rc->col_prop) RNA_property_float_get_array(&rc->col_ptr, rc->col_prop, col); - glColor4f(col[0], col[1], col[2], 0.5); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fvAlpha(col, 0.5); if (rc->subtype == PROP_ANGLE) { glPushMatrix(); + /* draw original angle line */ glRotatef(RAD2DEGF(rc->initial_value), 0, 0, 1); - fdrawline((float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); + immBegin(GL_LINES, 2); + immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f); + immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); + immEnd(); + /* draw new angle line */ glRotatef(RAD2DEGF(rc->current_value - rc->initial_value), 0, 0, 1); - fdrawline((float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); + immBegin(GL_LINES, 2); + immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f); + immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); + immEnd(); + glPopMatrix(); } /* draw circles on top */ - glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), r1, 40); - glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), r2, 40); + imm_draw_lined_circle(pos, 0.0f, 0.0f, r1, 40); + imm_draw_lined_circle(pos, 0.0f, 0.0f, r2, 40); if (rmin > 0.0f) - glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), rmin, 40); + imm_draw_lined_circle(pos, 0.0, 0.0f, rmin, 40); BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi); BLF_enable(fontid, BLF_SHADOW); @@ -3164,6 +3202,8 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); + + immUnbindProgram(); } typedef enum { @@ -4170,6 +4210,10 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_previews_ensure); WM_operatortype_append(WM_OT_previews_clear); WM_operatortype_append(WM_OT_doc_view_manual_ui_context); + + /* manipulators */ + WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_select); + WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_tweak); } /* circleselect-like modal operators */ @@ -4475,6 +4519,7 @@ void wm_window_keymap(wmKeyConfig *keyconf) RNA_float_set(kmi->ptr, "value", 1.0f / 1.5f); #endif /* WITH_INPUT_NDOF */ + wm_manipulators_keymap(keyconf); gesture_circle_modal_keymap(keyconf); gesture_border_modal_keymap(keyconf); gesture_zoom_border_modal_keymap(keyconf); diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index 1c1c2ad35af..f625423caa8 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -54,6 +54,7 @@ #include "GPU_glew.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "WM_api.h" #include "WM_types.h" @@ -172,6 +173,10 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win) int soffx; bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0; + VertexFormat *format = immVertexFormat(); + unsigned texcoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + for (view = 0; view < 2; view ++) { drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); triple = drawdata->triple; @@ -203,26 +208,33 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win) halfy /= triple->y; } - glEnable(triple->target); + /* TODO: if target is always same for both eyes, bind program & set uniform before loop */ + immBindBuiltinProgram((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_3D_IMAGE_MODULATE_ALPHA : GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA); + glBindTexture(triple->target, triple->bind); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(soffx, 0); + immUniform1f("alpha", 1.0f); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GL_QUADS, 4); + + immAttrib2f(texcoord, halfx, halfy); + immVertex2f(pos, soffx, 0.0f); + + immAttrib2f(texcoord, ratiox + halfx, halfy); + immVertex2f(pos, soffx + (sizex * 0.5f), 0.0f); - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(soffx + (sizex * 0.5f), 0); + immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy); + immVertex2f(pos, soffx + (sizex * 0.5f), sizey); - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(soffx + (sizex * 0.5f), sizey); + immAttrib2f(texcoord, halfx, ratioy + halfy); + immVertex2f(pos, soffx, sizey); - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(soffx, sizey); - glEnd(); + immEnd(); + /* TODO: if target is always same for both eyes, unbind program & texture target after loop */ glBindTexture(triple->target, 0); - glDisable(triple->target); + immUnbindProgram(); } } @@ -234,6 +246,10 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win) int view; int soffy; + VertexFormat *format = immVertexFormat(); + unsigned texcoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT); + unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT); + for (view = 0; view < 2; view ++) { drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); triple = drawdata->triple; @@ -262,26 +278,33 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win) halfy /= triple->y; } - glEnable(triple->target); + /* TODO: if target is always same for both eyes, bind program & set uniforms before loop */ + immBindBuiltinProgram((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_3D_IMAGE_MODULATE_ALPHA : GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA); + glBindTexture(triple->target, triple->bind); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(0, soffy); + immUniform1f("alpha", 1.0f); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GL_QUADS, 4); + + immAttrib2f(texcoord, halfx, halfy); + immVertex2f(pos, 0.0f, soffy); + + immAttrib2f(texcoord, ratiox + halfx, halfy); + immVertex2f(pos, sizex, soffy); - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(sizex, soffy); + immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy); + immVertex2f(pos, sizex, soffy + (sizey * 0.5f)); - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(sizex, soffy + (sizey * 0.5f)); + immAttrib2f(texcoord, halfx, ratioy + halfy); + immVertex2f(pos, 0.0f, soffy + (sizey * 0.5f)); - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(0, soffy + (sizey * 0.5f)); - glEnd(); + immEnd(); + /* TODO: if target is always same for both eyes, unbind program & texture target after loop */ + immUnbindProgram(); glBindTexture(triple->target, 0); - glDisable(triple->target); } } @@ -310,9 +333,9 @@ void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win) static bool wm_stereo3d_quadbuffer_supported(void) { - int gl_stereo = 0; - glGetBooleanv(GL_STEREO, (GLboolean *)&gl_stereo); - return gl_stereo != 0; + GLboolean stereo = GL_FALSE; + glGetBooleanv(GL_STEREO, &stereo); + return stereo == GL_TRUE; } static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 2d43c47679d..e271225e437 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -51,6 +51,7 @@ #include "BKE_blender.h" #include "BKE_context.h" +#include "BKE_icons.h" #include "BKE_library.h" #include "BKE_global.h" #include "BKE_main.h" @@ -76,7 +77,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_init_exit.h" -#include "GPU_glew.h" +#include "GPU_immediate.h" /* for assert */ #ifndef NDEBUG @@ -827,13 +828,16 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) { if (win != wm->windrawable && win->ghostwin) { // win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */ - + wm->windrawable = win; if (G.debug & G_DEBUG_EVENTS) { printf("%s: set drawable %d\n", __func__, win->winid); } + + immDeactivate(); GHOST_ActivateWindowDrawingContext(win->ghostwin); - + immActivate(); + /* this can change per window */ U.pixelsize = wm_window_pixelsize(win); BKE_blender_userdef_refresh(); @@ -1102,6 +1106,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr wm_window_make_drawable(wm, win); wm_draw_window_clear(win); + BKE_icon_changed(win->screen->id.icon_id); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); @@ -1203,6 +1208,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr if (U.pixelsize != prev_pixelsize) { BKE_blender_userdef_refresh(); + BKE_icon_changed(win->screen->id.icon_id); // close all popups since they are positioned with the pixel // size baked in and it's difficult to correct them diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h new file mode 100644 index 00000000000..099ad7fd851 --- /dev/null +++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h @@ -0,0 +1,110 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/WM_manipulator_api.h + * \ingroup wm + * + * \name Manipulator API + * \brief API for external use of wmManipulator types. + * + * Only included in WM_api.h + */ + + +#ifndef __WM_MANIPULATOR_API_H__ +#define __WM_MANIPULATOR_API_H__ + +struct ARegion; +struct Main; +struct wmKeyConfig; +struct wmManipulatorGroupType; +struct wmManipulatorMap; +struct wmManipulatorMapType; +struct wmManipulatorMapType_Params; + +/* -------------------------------------------------------------------- */ +/* wmManipulator */ + +struct wmManipulator *WM_manipulator_new( + void (*draw)(const struct bContext *, struct wmManipulator *), + void (*render_3d_intersection)(const struct bContext *, struct wmManipulator *, int), + int (*intersect)(struct bContext *, const struct wmEvent *, struct wmManipulator *), + int (*handler)(struct bContext *, const struct wmEvent *, struct wmManipulator *, const int)); +void WM_manipulator_delete( + ListBase *manipulatorlist, struct wmManipulatorMap *mmap, struct wmManipulator *manipulator, + struct bContext *C); + +void WM_manipulator_set_property(struct wmManipulator *, int slot, struct PointerRNA *ptr, const char *propname); +struct PointerRNA *WM_manipulator_set_operator(struct wmManipulator *, const char *opname); +void WM_manipulator_set_func_select( + struct wmManipulator *manipulator, + void (*select)(struct bContext *, struct wmManipulator *, const int action)); /* wmManipulatorSelectFunc */ +void WM_manipulator_set_origin(struct wmManipulator *manipulator, const float origin[3]); +void WM_manipulator_set_offset(struct wmManipulator *manipulator, const float offset[3]); +void WM_manipulator_set_flag(struct wmManipulator *manipulator, const int flag, const bool enable); +void WM_manipulator_set_scale(struct wmManipulator *manipulator, float scale); +void WM_manipulator_set_line_width(struct wmManipulator *manipulator, const float line_width); +void WM_manipulator_set_colors(struct wmManipulator *manipulator, const float col[4], const float col_hi[4]); + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorGroup */ + +struct wmManipulatorGroupType *WM_manipulatorgrouptype_append( + struct wmManipulatorMapType *mmaptype, + void (*mgrouptype_func)(struct wmManipulatorGroupType *)); +struct wmManipulatorGroupType *WM_manipulatorgrouptype_append_runtime( + const struct Main *main, struct wmManipulatorMapType *mmaptype, + void (*mgrouptype_func)(struct wmManipulatorGroupType *)); +void WM_manipulatorgrouptype_init_runtime( + const struct Main *bmain, struct wmManipulatorMapType *mmaptype, + struct wmManipulatorGroupType *mgrouptype); +void WM_manipulatorgrouptype_unregister( + struct bContext *C, struct Main *bmain, struct wmManipulatorGroupType *mgroup); + +struct wmKeyMap *WM_manipulatorgroup_keymap_common( + const struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *config); +struct wmKeyMap *WM_manipulatorgroup_keymap_common_sel( + const struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *config); + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorMap */ + +struct wmManipulatorMapType *WM_manipulatormaptype_find( + const struct wmManipulatorMapType_Params *mmap_params); +struct wmManipulatorMapType *WM_manipulatormaptype_ensure( + const struct wmManipulatorMapType_Params *mmap_params); + +struct wmManipulatorMap *WM_manipulatormap_new_from_type( + const struct wmManipulatorMapType_Params *mmap_params); +void WM_manipulatormap_tag_refresh(struct wmManipulatorMap *mmap); +void WM_manipulatormap_draw(struct wmManipulatorMap *mmap, const struct bContext *C, const int drawstep); +void WM_manipulatormap_add_handlers(struct ARegion *ar, struct wmManipulatorMap *mmap); +bool WM_manipulatormap_select_all(struct bContext *C, struct wmManipulatorMap *mmap, const int action); +bool WM_manipulatormap_cursor_set(const struct wmManipulatorMap *mmap, struct wmWindow *win); + +#endif /* __WM_MANIPULATOR_API_H__ */ + diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h new file mode 100644 index 00000000000..284a3e9bd22 --- /dev/null +++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h @@ -0,0 +1,167 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/WM_manipulator_types.h + * \ingroup wm + * + * \name Manipulator Types + * \brief Manipulator defines for external use. + * + * Only included in WM_types.h and lower level files. + */ + + +#ifndef __WM_MANIPULATOR_TYPES_H__ +#define __WM_MANIPULATOR_TYPES_H__ + +#include "BLI_compiler_attrs.h" + +struct wmManipulatorGroupType; +struct wmManipulatorGroup; +struct wmKeyConfig; + +typedef bool (*wmManipulatorGroupPollFunc)(const struct bContext *, struct wmManipulatorGroupType *) ATTR_WARN_UNUSED_RESULT; +typedef void (*wmManipulatorGroupInitFunc)(const struct bContext *, struct wmManipulatorGroup *); +typedef void (*wmManipulatorGroupRefreshFunc)(const struct bContext *, struct wmManipulatorGroup *); +typedef void (*wmManipulatorGroupDrawPrepareFunc)(const struct bContext *, struct wmManipulatorGroup *); + + +/* -------------------------------------------------------------------- */ +/* wmManipulator */ + +/** + * Simple utility wrapper for storing a single manipulator as wmManipulatorGroup.customdata (which gets freed). + */ +typedef struct wmManipulatorWrapper { + struct wmManipulator *manipulator; +} wmManipulatorWrapper; + +/* wmManipulator.flag + * Flags for individual manipulators. */ +enum { + WM_MANIPULATOR_DRAW_HOVER = (1 << 0), /* draw *only* while hovering */ + WM_MANIPULATOR_DRAW_ACTIVE = (1 << 1), /* draw while dragging */ + WM_MANIPULATOR_DRAW_VALUE = (1 << 2), /* draw an indicator for the current value while dragging */ + WM_MANIPULATOR_HIDDEN = (1 << 3), +}; + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorGroup */ + +typedef struct wmManipulatorGroup { + struct wmManipulatorGroup *next, *prev; + + struct wmManipulatorGroupType *type; + ListBase manipulators; + + void *py_instance; /* python stores the class instance here */ + struct ReportList *reports; /* errors and warnings storage */ + + void *customdata; + void (*customdata_free)(void *); /* for freeing customdata from above */ + int flag; /* private */ + int pad; +} wmManipulatorGroup; + +/* factory class for a manipulator-group type, gets called every time a new area is spawned */ +typedef struct wmManipulatorGroupType { + struct wmManipulatorGroupType *next, *prev; + + char idname[64]; /* MAX_NAME */ + const char *name; /* manipulator-group name - displayed in UI (keymap editor) */ + + /* poll if manipulator-map should be visible */ + wmManipulatorGroupPollFunc poll; + /* initially create manipulators and set permanent data - stuff you only need to do once */ + wmManipulatorGroupInitFunc init; + /* refresh data, only called if recreate flag is set (WM_manipulatormap_tag_refresh) */ + wmManipulatorGroupRefreshFunc refresh; + /* refresh data for drawing, called before each redraw */ + wmManipulatorGroupDrawPrepareFunc draw_prepare; + + /* keymap init callback for this manipulator-group */ + struct wmKeyMap *(*keymap_init)(const struct wmManipulatorGroupType *, struct wmKeyConfig *); + /* keymap created with callback from above */ + struct wmKeyMap *keymap; + + /* rna for properties */ + struct StructRNA *srna; + + /* RNA integration */ + ExtensionRNA ext; + + int flag; + + /* if type is spawned from operator this is set here */ + void *op; + + /* same as manipulator-maps, so registering/unregistering goes to the correct region */ + short spaceid, regionid; + char mapidname[64]; +} wmManipulatorGroupType; + +/** + * wmManipulatorGroupType.flag + * Flags that influence the behavior of all manipulators in the group. + */ +enum { + /* Mark manipulator-group as being 3D */ + WM_MANIPULATORGROUPTYPE_IS_3D = (1 << 0), + /* Scale manipulators as 3D object that respects zoom (otherwise zoom independent draw size) */ + WM_MANIPULATORGROUPTYPE_SCALE_3D = (1 << 1), + /* Manipulators can be depth culled with scene objects (covered by other geometry - TODO) */ + WM_MANIPULATORGROUPTYPE_SCENE_DEPTH = (1 << 2), + /* Manipulators can be selected */ + WM_MANIPULATORGROUPTYPE_SELECTABLE = (1 << 3), + /* manipulator group is attached to operator, and is only accessible as long as this runs */ + WM_MANIPULATORGROUPTYPE_OP = (1 << 4), +}; + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorMap */ + +struct wmManipulatorMapType_Params { + const char *idname; + const int spaceid; + const int regionid; +}; + +/** + * Pass a value of this enum to #WM_manipulatormap_draw to tell it what to draw. + */ +enum { + /* Draw 2D manipulator-groups (ManipulatorGroupType.is_3d == false) */ + WM_MANIPULATORMAP_DRAWSTEP_2D = 0, + /* Draw 3D manipulator-groups (ManipulatorGroupType.is_3d == true) */ + WM_MANIPULATORMAP_DRAWSTEP_3D, + /* Draw only depth culled manipulators (WM_MANIPULATOR_SCENE_DEPTH flag). + * Note that these are expected to be 3D manipulators too. */ + WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE, +}; + +#endif /* __WM_MANIPULATOR_TYPES_H__ */ + diff --git a/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h b/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h new file mode 100644 index 00000000000..66598fa29d7 --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h @@ -0,0 +1,100 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_intern.h + * \ingroup wm + */ + + +#ifndef __MANIPULATOR_LIBRARY_INTERN_H__ +#define __MANIPULATOR_LIBRARY_INTERN_H__ + +/* distance around which manipulators respond to input (and get highlighted) */ +#define MANIPULATOR_HOTSPOT 14.0f + +/** + * Data for common interactions. Used in manipulator_library_utils.c functions. + */ +typedef struct ManipulatorCommonData { + int flag; + + float range_fac; /* factor for arrow min/max distance */ + float offset; + + /* property range for constrained manipulators */ + float range; + /* min/max value for constrained manipulators */ + float min, max; +} ManipulatorCommonData; + +typedef struct ManipulatorInteraction { + float init_value; /* initial property value */ + float init_origin[3]; + float init_mval[2]; + float init_offset; + float init_scale; + + /* offset of last handling step */ + float prev_offset; + /* Total offset added by precision tweaking. + * Needed to allow toggling precision on/off without causing jumps */ + float precision_offset; +} ManipulatorInteraction; + +/* ManipulatorCommonData->flag */ +enum { + MANIPULATOR_CUSTOM_RANGE_SET = (1 << 0), +}; + + +float manipulator_offset_from_value( + ManipulatorCommonData *data, const float value, + const bool constrained, const bool inverted); +float manipulator_value_from_offset( + ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset, + const bool constrained, const bool inverted, const bool use_precision); + +void manipulator_property_data_update( + wmManipulator *manipulator, ManipulatorCommonData *data, const int slot, + const bool constrained, const bool inverted); + +void manipulator_property_value_set( + bContext *C, const wmManipulator *manipulator, + const int slot, const float value); +float manipulator_property_value_get( + const wmManipulator *manipulator, const int slot); +void manipulator_property_value_reset( + bContext *C, const wmManipulator *manipulator, ManipulatorInteraction *inter, + const int slot); + + +/* -------------------------------------------------------------------- */ + +void manipulator_color_get( + const wmManipulator *manipulator, const bool highlight, + float r_col[]); + +#endif /* __MANIPULATOR_LIBRARY_INTERN_H__ */ + diff --git a/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c b/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c new file mode 100644 index 00000000000..0617e9e873b --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c @@ -0,0 +1,171 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/manipulator_library/manipulator_library_utils.c + * \ingroup wm + * + * \name Manipulator Library Utilities + * + * \brief This file contains functions for common behaviors of manipulators. + */ + +#include "BKE_context.h" + +#include "BLI_math.h" + +#include "RNA_access.h" + +#include "WM_api.h" + +/* own includes */ +#include "WM_manipulator_types.h" +#include "wm_manipulator_wmapi.h" +#include "wm_manipulator_intern.h" +#include "manipulator_library_intern.h" + +/* factor for precision tweaking */ +#define MANIPULATOR_PRECISION_FAC 0.05f + + +BLI_INLINE float manipulator_offset_from_value_constr( + const float range_fac, const float min, const float range, const float value, + const bool inverted) +{ + return inverted ? (range_fac * (min + range - value) / range) : (range_fac * (value / range)); +} + +BLI_INLINE float manipulator_value_from_offset_constr( + const float range_fac, const float min, const float range, const float value, + const bool inverted) +{ + return inverted ? (min + range - (value * range / range_fac)) : (value * range / range_fac); +} + +float manipulator_offset_from_value( + ManipulatorCommonData *data, const float value, const bool constrained, const bool inverted) +{ + if (constrained) + return manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted); + + return value; +} + +float manipulator_value_from_offset( + ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset, + const bool constrained, const bool inverted, const bool use_precision) +{ + const float max = data->min + data->range; + + if (use_precision) { + /* add delta offset of this step to total precision_offset */ + inter->precision_offset += offset - inter->prev_offset; + } + inter->prev_offset = offset; + + float ofs_new = inter->init_offset + offset - inter->precision_offset * (1.0f - MANIPULATOR_PRECISION_FAC); + float value; + + if (constrained) { + value = manipulator_value_from_offset_constr(data->range_fac, data->min, data->range, ofs_new, inverted); + } + else { + value = ofs_new; + } + + /* clamp to custom range */ + if (data->flag & MANIPULATOR_CUSTOM_RANGE_SET) { + CLAMP(value, data->min, max); + } + + return value; +} + +void manipulator_property_data_update( + wmManipulator *manipulator, ManipulatorCommonData *data, const int slot, + const bool constrained, const bool inverted) +{ + if (!manipulator->props[slot]) { + data->offset = 0.0f; + return; + } + + PointerRNA ptr = manipulator->ptr[slot]; + PropertyRNA *prop = manipulator->props[slot]; + float value = manipulator_property_value_get(manipulator, slot); + + if (constrained) { + if ((data->flag & MANIPULATOR_CUSTOM_RANGE_SET) == 0) { + float step, precision; + float min, max; + RNA_property_float_ui_range(&ptr, prop, &min, &max, &step, &precision); + data->range = max - min; + data->min = min; + } + data->offset = manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted); + } + else { + data->offset = value; + } +} + +void manipulator_property_value_set( + bContext *C, const wmManipulator *manipulator, + const int slot, const float value) +{ + PointerRNA ptr = manipulator->ptr[slot]; + PropertyRNA *prop = manipulator->props[slot]; + + /* reset property */ + RNA_property_float_set(&ptr, prop, value); + RNA_property_update(C, &ptr, prop); +} + +float manipulator_property_value_get(const wmManipulator *manipulator, const int slot) +{ + BLI_assert(RNA_property_type(manipulator->props[slot]) == PROP_FLOAT); + return RNA_property_float_get(&manipulator->ptr[slot], manipulator->props[slot]); +} + +void manipulator_property_value_reset( + bContext *C, const wmManipulator *manipulator, ManipulatorInteraction *inter, + const int slot) +{ + manipulator_property_value_set(C, manipulator, slot, inter->init_value); +} + + +/* -------------------------------------------------------------------- */ + +void manipulator_color_get( + const wmManipulator *manipulator, const bool highlight, + float r_col[4]) +{ + if (highlight && !(manipulator->flag & WM_MANIPULATOR_DRAW_HOVER)) { + copy_v4_v4(r_col, manipulator->col_hi); + } + else { + copy_v4_v4(r_col, manipulator->col); + } +} diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c new file mode 100644 index 00000000000..824141d1c40 --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c @@ -0,0 +1,404 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/wm_manipulator.c + * \ingroup wm + */ + +#include "BKE_context.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "GL/glew.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* own includes */ +#include "wm_manipulator_wmapi.h" +#include "wm_manipulator_intern.h" + + +/* Still unused */ +wmManipulator *WM_manipulator_new( + void (*draw)(const bContext *C, wmManipulator *customdata), + void (*render_3d_intersection)(const bContext *C, wmManipulator *customdata, int selectionbase), + int (*intersect)(bContext *C, const wmEvent *event, wmManipulator *manipulator), + int (*handler)(bContext *C, const wmEvent *event, wmManipulator *manipulator, const int flag)) +{ + wmManipulator *manipulator = MEM_callocN(sizeof(wmManipulator), "manipulator"); + + manipulator->draw = draw; + manipulator->handler = handler; + manipulator->intersect = intersect; + manipulator->render_3d_intersection = render_3d_intersection; + + /* XXX */ +// fix_linking_manipulator_arrow(); +// fix_linking_manipulator_arrow2d(); +// fix_linking_manipulator_cage(); +// fix_linking_manipulator_dial(); +// fix_linking_manipulator_facemap(); +// fix_linking_manipulator_primitive(); + + return manipulator; +} + +/** + * Assign an idname that is unique in \a mgroup to \a manipulator. + * + * \param rawname: Name used as basis to define final unique idname. + */ +static void manipulator_unique_idname_set(wmManipulatorGroup *mgroup, wmManipulator *manipulator, const char *rawname) +{ + if (mgroup->type->idname[0]) { + BLI_snprintf(manipulator->idname, sizeof(manipulator->idname), "%s_%s", mgroup->type->idname, rawname); + } + else { + BLI_strncpy(manipulator->idname, rawname, sizeof(manipulator->idname)); + } + + /* ensure name is unique, append '.001', '.002', etc if not */ + BLI_uniquename(&mgroup->manipulators, manipulator, "Manipulator", '.', + offsetof(wmManipulator, idname), sizeof(manipulator->idname)); +} + +/** + * Initialize default values and allocate needed memory for members. + */ +static void manipulator_init(wmManipulator *manipulator) +{ + const float col_default[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + manipulator->user_scale = 1.0f; + manipulator->line_width = 1.0f; + + /* defaults */ + copy_v4_v4(manipulator->col, col_default); + copy_v4_v4(manipulator->col_hi, col_default); + + /* create at least one property for interaction */ + if (manipulator->max_prop == 0) { + manipulator->max_prop = 1; + } + + manipulator->props = MEM_callocN(sizeof(PropertyRNA *) * manipulator->max_prop, "manipulator->props"); + manipulator->ptr = MEM_callocN(sizeof(PointerRNA) * manipulator->max_prop, "manipulator->ptr"); +} + +/** + * Register \a manipulator. + * + * \param name: name used to create a unique idname for \a manipulator in \a mgroup + */ +void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *manipulator, const char *name) +{ + manipulator_init(manipulator); + manipulator_unique_idname_set(mgroup, manipulator, name); + wm_manipulatorgroup_manipulator_register(mgroup, manipulator); +} + +/** + * Free \a manipulator and unlink from \a manipulatorlist. + * \a manipulatorlist is allowed to be NULL. + */ +void WM_manipulator_delete(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmManipulator *manipulator, bContext *C) +{ + if (manipulator->state & WM_MANIPULATOR_HIGHLIGHT) { + wm_manipulatormap_set_highlighted_manipulator(mmap, C, NULL, 0); + } + if (manipulator->state & WM_MANIPULATOR_ACTIVE) { + wm_manipulatormap_set_active_manipulator(mmap, C, NULL, NULL); + } + if (manipulator->state & WM_MANIPULATOR_SELECTED) { + wm_manipulator_deselect(mmap, manipulator); + } + + if (manipulator->opptr.data) { + WM_operator_properties_free(&manipulator->opptr); + } + MEM_freeN(manipulator->props); + MEM_freeN(manipulator->ptr); + + if (manipulatorlist) + BLI_remlink(manipulatorlist, manipulator); + MEM_freeN(manipulator); +} + +wmManipulatorGroup *wm_manipulator_get_parent_group(const wmManipulator *manipulator) +{ + return manipulator->mgroup; +} + + +/* -------------------------------------------------------------------- */ +/** \name Manipulator Creation API + * + * API for defining data on manipulator creation. + * + * \{ */ + +void WM_manipulator_set_property(wmManipulator *manipulator, const int slot, PointerRNA *ptr, const char *propname) +{ + if (slot < 0 || slot >= manipulator->max_prop) { + fprintf(stderr, "invalid index %d when binding property for manipulator type %s\n", slot, manipulator->idname); + return; + } + + /* if manipulator evokes an operator we cannot use it for property manipulation */ + manipulator->opname = NULL; + manipulator->ptr[slot] = *ptr; + manipulator->props[slot] = RNA_struct_find_property(ptr, propname); + + if (manipulator->prop_data_update) + manipulator->prop_data_update(manipulator, slot); +} + +PointerRNA *WM_manipulator_set_operator(wmManipulator *manipulator, const char *opname) +{ + wmOperatorType *ot = WM_operatortype_find(opname, 0); + + if (ot) { + manipulator->opname = opname; + + if (manipulator->opptr.data) { + WM_operator_properties_free(&manipulator->opptr); + } + WM_operator_properties_create_ptr(&manipulator->opptr, ot); + + return &manipulator->opptr; + } + else { + fprintf(stderr, "Error binding operator to manipulator: operator %s not found!\n", opname); + } + + return NULL; +} + +/** + * \brief Set manipulator select callback. + * + * Callback is called when manipulator gets selected/deselected. + */ +void WM_manipulator_set_func_select(wmManipulator *manipulator, wmManipulatorSelectFunc select) +{ + BLI_assert(manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECTABLE); + manipulator->select = select; +} + +void WM_manipulator_set_origin(wmManipulator *manipulator, const float origin[3]) +{ + copy_v3_v3(manipulator->origin, origin); +} + +void WM_manipulator_set_offset(wmManipulator *manipulator, const float offset[3]) +{ + copy_v3_v3(manipulator->offset, offset); +} + +void WM_manipulator_set_flag(wmManipulator *manipulator, const int flag, const bool enable) +{ + if (enable) { + manipulator->flag |= flag; + } + else { + manipulator->flag &= ~flag; + } +} + +void WM_manipulator_set_scale(wmManipulator *manipulator, const float scale) +{ + manipulator->user_scale = scale; +} + +void WM_manipulator_set_line_width(wmManipulator *manipulator, const float line_width) +{ + manipulator->line_width = line_width; +} + +/** + * Set manipulator rgba colors. + * + * \param col Normal state color. + * \param col_hi Highlighted state color. + */ +void WM_manipulator_set_colors(wmManipulator *manipulator, const float col[4], const float col_hi[4]) +{ + copy_v4_v4(manipulator->col, col); + copy_v4_v4(manipulator->col_hi, col_hi); +} + +/** \} */ // Manipulator Creation API + + +/* -------------------------------------------------------------------- */ + +/** + * Remove \a manipulator from selection. + * Reallocates memory for selected manipulators so better not call for selecting multiple ones. + * + * \return if the selection has changed. + */ +bool wm_manipulator_deselect(wmManipulatorMap *mmap, wmManipulator *manipulator) +{ + if (!mmap->mmap_context.selected_manipulator) + return false; + + wmManipulator ***sel = &mmap->mmap_context.selected_manipulator; + int *tot_selected = &mmap->mmap_context.tot_selected; + bool changed = false; + + /* caller should check! */ + BLI_assert(manipulator->state & WM_MANIPULATOR_SELECTED); + + /* remove manipulator from selected_manipulators array */ + for (int i = 0; i < (*tot_selected); i++) { + if ((*sel)[i] == manipulator) { + for (int j = i; j < ((*tot_selected) - 1); j++) { + (*sel)[j] = (*sel)[j + 1]; + } + changed = true; + break; + } + } + + /* update array data */ + if ((*tot_selected) <= 1) { + wm_manipulatormap_selected_delete(mmap); + } + else { + *sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_selected)); + (*tot_selected)--; + } + + manipulator->state &= ~WM_MANIPULATOR_SELECTED; + return changed; +} + +/** + * Add \a manipulator to selection. + * Reallocates memory for selected manipulators so better not call for selecting multiple ones. + * + * \return if the selection has changed. + */ +bool wm_manipulator_select(bContext *C, wmManipulatorMap *mmap, wmManipulator *manipulator) +{ + wmManipulator ***sel = &mmap->mmap_context.selected_manipulator; + int *tot_selected = &mmap->mmap_context.tot_selected; + + if (!manipulator || (manipulator->state & WM_MANIPULATOR_SELECTED)) + return false; + + (*tot_selected)++; + + *sel = MEM_reallocN(*sel, sizeof(wmManipulator *) * (*tot_selected)); + (*sel)[(*tot_selected) - 1] = manipulator; + + manipulator->state |= WM_MANIPULATOR_SELECTED; + if (manipulator->select) { + manipulator->select(C, manipulator, SEL_SELECT); + } + wm_manipulatormap_set_highlighted_manipulator(mmap, C, manipulator, manipulator->highlighted_part); + + return true; +} + +void wm_manipulator_calculate_scale(wmManipulator *manipulator, const bContext *C) +{ + const RegionView3D *rv3d = CTX_wm_region_view3d(C); + float scale = 1.0f; + + if (manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SCALE_3D) { + if (rv3d /*&& (U.manipulator_flag & V3D_3D_MANIPULATORS) == 0*/) { /* UserPref flag might be useful for later */ + if (manipulator->get_final_position) { + float position[3]; + + manipulator->get_final_position(manipulator, position); + scale = ED_view3d_pixel_size(rv3d, position) * (float)U.manipulator_scale; + } + else { + scale = ED_view3d_pixel_size(rv3d, manipulator->origin) * (float)U.manipulator_scale; + } + } + else { + scale = U.manipulator_scale * 0.02f; + } + } + + manipulator->scale = scale * manipulator->user_scale; +} + +static void manipulator_update_prop_data(wmManipulator *manipulator) +{ + /* manipulator property might have been changed, so update manipulator */ + if (manipulator->props && manipulator->prop_data_update) { + for (int i = 0; i < manipulator->max_prop; i++) { + if (manipulator->props[i]) { + manipulator->prop_data_update(manipulator, i); + } + } + } +} + +void wm_manipulator_update(wmManipulator *manipulator, const bContext *C, const bool refresh_map) +{ + if (refresh_map) { + manipulator_update_prop_data(manipulator); + } + wm_manipulator_calculate_scale(manipulator, C); +} + +bool wm_manipulator_is_visible(wmManipulator *manipulator) +{ + if (manipulator->flag & WM_MANIPULATOR_HIDDEN) { + return false; + } + if ((manipulator->state & WM_MANIPULATOR_ACTIVE) && + !(manipulator->flag & (WM_MANIPULATOR_DRAW_ACTIVE | WM_MANIPULATOR_DRAW_VALUE))) + { + /* don't draw while active (while dragging) */ + return false; + } + if ((manipulator->flag & WM_MANIPULATOR_DRAW_HOVER) && + !(manipulator->state & WM_MANIPULATOR_HIGHLIGHT) && + !(manipulator->state & WM_MANIPULATOR_SELECTED)) /* still draw selected manipulators */ + { + /* only draw on mouse hover */ + return false; + } + + return true; +} + diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h new file mode 100644 index 00000000000..1a9693a472b --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h @@ -0,0 +1,230 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/wm_manipulator_intern.h + * \ingroup wm + */ + + +#ifndef __WM_MANIPULATOR_INTERN_H__ +#define __WM_MANIPULATOR_INTERN_H__ + +struct wmKeyConfig; +struct wmManipulatorMap; + +/* -------------------------------------------------------------------- */ +/* wmManipulator */ + +/* manipulators are set per region by registering them on manipulator-maps */ +typedef struct wmManipulator { + struct wmManipulator *next, *prev; + + char idname[MAX_NAME + 4]; /* + 4 for unique '.001', '.002', etc suffix */ + /* pointer back to group this manipulator is in (just for quick access) */ + struct wmManipulatorGroup *mgroup; + + /* could become wmManipulatorType */ + /* draw manipulator */ + void (*draw)(const struct bContext *, struct wmManipulator *); + + /* determine if the mouse intersects with the manipulator. The calculation should be done in the callback itself */ + int (*intersect)(struct bContext *, const struct wmEvent *, struct wmManipulator *); + + /* determines 3d intersection by rendering the manipulator in a selection routine. */ + void (*render_3d_intersection)(const struct bContext *, struct wmManipulator *, int); + + /* handler used by the manipulator. Usually handles interaction tied to a manipulator type */ + int (*handler)(struct bContext *, const struct wmEvent *, struct wmManipulator *, const int); + + /* manipulator-specific handler to update manipulator attributes based on the property value */ + void (*prop_data_update)(struct wmManipulator *, int); + + /* returns the final position which may be different from the origin, depending on the manipulator. + * used in calculations of scale */ + void (*get_final_position)(struct wmManipulator *, float[]); + + /* activate a manipulator state when the user clicks on it */ + int (*invoke)(struct bContext *, const struct wmEvent *, struct wmManipulator *); + + /* called when manipulator tweaking is done - used to free data and reset property when cancelling */ + void (*exit)(struct bContext *, struct wmManipulator *, const bool ); + + int (*get_cursor)(struct wmManipulator *); + + /* called when manipulator selection state changes */ + wmManipulatorSelectFunc select; + + int flag; /* flags that influence the behavior or how the manipulators are drawn */ + short state; /* state flags (active, highlighted, selected) */ + + unsigned char highlighted_part; + + /* center of manipulator in space, 2d or 3d */ + float origin[3]; + /* custom offset from origin */ + float offset[3]; + /* runtime property, set the scale while drawing on the viewport */ + float scale; + /* user defined scale, in addition to the original one */ + float user_scale; + /* user defined width for line drawing */ + float line_width; + /* manipulator colors (uses default fallbacks if not defined) */ + float col[4], col_hi[4]; + + /* data used during interaction */ + void *interaction_data; + + /* name of operator to spawn when activating the manipulator */ + const char *opname; + /* operator properties if manipulator spawns and controls an operator, + * or owner pointer if manipulator spawns and controls a property */ + PointerRNA opptr; + + /* maximum number of properties attached to the manipulator */ + int max_prop; + /* arrays of properties attached to various manipulator parameters. As + * the manipulator is interacted with, those properties get updated */ + PointerRNA *ptr; + PropertyRNA **props; +} wmManipulator; + +/* wmManipulator.state */ +enum { + WM_MANIPULATOR_HIGHLIGHT = (1 << 0), /* while hovered */ + WM_MANIPULATOR_ACTIVE = (1 << 1), /* while dragging */ + WM_MANIPULATOR_SELECTED = (1 << 2), +}; + +/** + * \brief Manipulator tweak flag. + * Bitflag passed to manipulator while tweaking. + */ +enum { + /* drag with extra precision (shift) + * NOTE: Manipulators are responsible for handling this (manipulator->handler callback)! */ + WM_MANIPULATOR_TWEAK_PRECISE = (1 << 0), +}; + +void wm_manipulator_register(struct wmManipulatorGroup *mgroup, struct wmManipulator *manipulator, const char *name); + +bool wm_manipulator_deselect(struct wmManipulatorMap *mmap, struct wmManipulator *manipulator); +bool wm_manipulator_select(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulator *manipulator); + +void wm_manipulator_calculate_scale(struct wmManipulator *manipulator, const bContext *C); +void wm_manipulator_update(struct wmManipulator *manipulator, const bContext *C, const bool refresh_map); +bool wm_manipulator_is_visible(struct wmManipulator *manipulator); + +void fix_linking_manipulator_arrow(void); +void fix_linking_manipulator_arrow2d(void); +void fix_linking_manipulator_cage(void); +void fix_linking_manipulator_dial(void); +void fix_linking_manipulator_facemap(void); +void fix_linking_manipulator_primitive(void); + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorGroup */ + +enum { + TWEAK_MODAL_CANCEL = 1, + TWEAK_MODAL_CONFIRM, + TWEAK_MODAL_PRECISION_ON, + TWEAK_MODAL_PRECISION_OFF, +}; + +struct wmManipulatorGroup *wm_manipulatorgroup_new_from_type(struct wmManipulatorGroupType *mgrouptype); +void wm_manipulatorgroup_free(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulatorGroup *mgroup); +void wm_manipulatorgroup_manipulator_register(struct wmManipulatorGroup *mgroup, wmManipulator *manipulator); +wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator( + const struct wmManipulatorGroup *mgroup, struct bContext *C, const struct wmEvent *event, + unsigned char *part); +void wm_manipulatorgroup_intersectable_manipulators_to_list( + const struct wmManipulatorGroup *mgroup, struct ListBase *listbase); +void wm_manipulatorgroup_ensure_initialized(struct wmManipulatorGroup *mgroup, const struct bContext *C); +bool wm_manipulatorgroup_is_visible(const struct wmManipulatorGroup *mgroup, const struct bContext *C); +bool wm_manipulatorgroup_is_visible_in_drawstep(const struct wmManipulatorGroup *mgroup, const int drawstep); + +void wm_manipulatorgrouptype_keymap_init(struct wmManipulatorGroupType *mgrouptype, struct wmKeyConfig *keyconf); + + +/* -------------------------------------------------------------------- */ +/* wmManipulatorMap */ + +typedef struct wmManipulatorMap { + struct wmManipulatorMap *next, *prev; + + struct wmManipulatorMapType *type; + ListBase manipulator_groups; + + char update_flag; /* private, update tagging */ + + /** + * \brief Manipulator map runtime context + * + * Contains information about this manipulator-map. Currently + * highlighted manipulator, currently selected manipulators, ... + */ + struct { + /* we redraw the manipulator-map when this changes */ + struct wmManipulator *highlighted_manipulator; + /* user has clicked this manipulator and it gets all input */ + struct wmManipulator *active_manipulator; + /* array for all selected manipulators + * TODO check on using BLI_array */ + struct wmManipulator **selected_manipulator; + int tot_selected; + } mmap_context; +} wmManipulatorMap; + +/** + * This is a container for all manipulator types that can be instantiated in a region. + * (similar to dropboxes). + * + * \note There is only ever one of these for every (area, region) combination. + */ +typedef struct wmManipulatorMapType { + struct wmManipulatorMapType *next, *prev; + char idname[64]; + short spaceid, regionid; + /* types of manipulator-groups for this manipulator-map type */ + ListBase manipulator_grouptypes; +} wmManipulatorMapType; + +void wm_manipulatormap_selected_delete(wmManipulatorMap *mmap); +bool wm_manipulatormap_deselect_all(struct wmManipulatorMap *mmap, wmManipulator ***sel); + + +/* -------------------------------------------------------------------- */ +/* Manipulator drawing */ + +typedef struct ManipulatorGeometryInfo { + int nverts; + int ntris; + float (*verts)[3]; + float (*normals)[3]; + unsigned short *indices; + bool init; +} ManipulatorGeometryInfo; + +#endif /* __WM_MANIPULATOR_INTERN_H__ */ + diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c b/source/blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c new file mode 100644 index 00000000000..f9f46b0f71a --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c @@ -0,0 +1,588 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/wm_manipulatorgroup.c + * \ingroup wm + * + * \name Manipulator-Group + * + * Manipulator-groups store and manage groups of manipulators. They can be + * attached to modal handlers and have own keymaps. + */ + +#include <stdlib.h> + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "BPY_extern.h" + +#include "ED_screen.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm_event_system.h" + +/* own includes */ +#include "wm_manipulator_wmapi.h" +#include "wm_manipulator_intern.h" + + +/* -------------------------------------------------------------------- */ +/** \name wmManipulatorGroup + * + * \{ */ + +/* wmManipulatorGroup.flag */ +enum { + WM_MANIPULATORGROUP_INITIALIZED = (1 << 2), /* mgroup has been initialized */ +}; + +/** + * Create a new manipulator-group from \a mgrouptype. + */ +wmManipulatorGroup *wm_manipulatorgroup_new_from_type(wmManipulatorGroupType *mgrouptype) +{ + wmManipulatorGroup *mgroup = MEM_callocN(sizeof(*mgroup), "manipulator-group"); + mgroup->type = mgrouptype; + + return mgroup; +} + +void wm_manipulatorgroup_free(bContext *C, wmManipulatorMap *mmap, wmManipulatorGroup *mgroup) +{ + for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator;) { + wmManipulator *manipulator_next = manipulator->next; + WM_manipulator_delete(&mgroup->manipulators, mmap, manipulator, C); + manipulator = manipulator_next; + } + BLI_assert(BLI_listbase_is_empty(&mgroup->manipulators)); + +#ifdef WITH_PYTHON + if (mgroup->py_instance) { + /* do this first in case there are any __del__ functions or + * similar that use properties */ + BPY_DECREF_RNA_INVALIDATE(mgroup->py_instance); + } +#endif + + if (mgroup->reports && (mgroup->reports->flag & RPT_FREE)) { + BKE_reports_clear(mgroup->reports); + MEM_freeN(mgroup->reports); + } + + if (mgroup->customdata_free) { + mgroup->customdata_free(mgroup->customdata); + } + else { + MEM_SAFE_FREE(mgroup->customdata); + } + + BLI_remlink(&mmap->manipulator_groups, mgroup); + MEM_freeN(mgroup); +} + +/** + * Add \a manipulator to \a mgroup and make sure its name is unique within the group. + */ +void wm_manipulatorgroup_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *manipulator) +{ + BLI_assert(!BLI_findstring(&mgroup->manipulators, manipulator->idname, offsetof(wmManipulator, idname))); + BLI_addtail(&mgroup->manipulators, manipulator); + manipulator->mgroup = mgroup; +} + +void wm_manipulatorgroup_attach_to_modal_handler( + bContext *C, wmEventHandler *handler, + wmManipulatorGroupType *mgrouptype, wmOperator *op) +{ + /* maybe overly careful, but manipulator-grouptype could come from a failed creation */ + if (!mgrouptype) { + return; + } + + /* now instantiate the manipulator-map */ + mgrouptype->op = op; + + /* try to find map in handler region that contains mgrouptype */ + if (handler->op_region && handler->op_region->manipulator_map) { + handler->manipulator_map = handler->op_region->manipulator_map; + ED_region_tag_redraw(handler->op_region); + } + + WM_event_add_mousemove(C); +} + +wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator( + const wmManipulatorGroup *mgroup, bContext *C, const wmEvent *event, + unsigned char *part) +{ + for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) { + if (manipulator->intersect && (manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) { + if ((*part = manipulator->intersect(C, event, manipulator))) { + return manipulator; + } + } + } + + return NULL; +} + +/** + * Adds all manipulators of \a mgroup that can be selected to the head of \a listbase. Added items need freeing! + */ +void wm_manipulatorgroup_intersectable_manipulators_to_list(const wmManipulatorGroup *mgroup, ListBase *listbase) +{ + for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) { + if ((manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) { + if (((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) && manipulator->render_3d_intersection) || + ((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) == 0 && manipulator->intersect)) + { + BLI_addhead(listbase, BLI_genericNodeN(manipulator)); + } + } + } +} + +void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bContext *C) +{ + /* prepare for first draw */ + if (UNLIKELY((mgroup->flag & WM_MANIPULATORGROUP_INITIALIZED) == 0)) { + mgroup->type->init(C, mgroup); + mgroup->flag |= WM_MANIPULATORGROUP_INITIALIZED; + } +} + +bool wm_manipulatorgroup_is_visible(const wmManipulatorGroup *mgroup, const bContext *C) +{ + /* Check for poll function, if manipulator-group belongs to an operator, also check if the operator is running. */ + return ((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_OP) == 0 || mgroup->type->op) && + (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)); +} + +bool wm_manipulatorgroup_is_visible_in_drawstep(const wmManipulatorGroup *mgroup, const int drawstep) +{ + switch (drawstep) { + case WM_MANIPULATORMAP_DRAWSTEP_2D: + return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) == 0; + case WM_MANIPULATORMAP_DRAWSTEP_3D: + return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D); + case WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE: + return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SCENE_DEPTH); + default: + BLI_assert(0); + return false; + } +} + +/** \name Manipulator operators + * + * Basic operators for manipulator interaction with user configurable keymaps. + * + * \{ */ + +static int manipulator_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + ARegion *ar = CTX_wm_region(C); + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulator ***sel = &mmap->mmap_context.selected_manipulator; + wmManipulator *highlighted = mmap->mmap_context.highlighted_manipulator; + + bool extend = RNA_boolean_get(op->ptr, "extend"); + bool deselect = RNA_boolean_get(op->ptr, "deselect"); + bool toggle = RNA_boolean_get(op->ptr, "toggle"); + + /* deselect all first */ + if (extend == false && deselect == false && toggle == false) { + wm_manipulatormap_deselect_all(mmap, sel); + BLI_assert(*sel == NULL && mmap->mmap_context.tot_selected == 0); + } + + if (highlighted) { + const bool is_selected = (highlighted->state & WM_MANIPULATOR_SELECTED); + bool redraw = false; + + if (toggle) { + /* toggle: deselect if already selected, else select */ + deselect = is_selected; + } + + if (deselect) { + if (is_selected && wm_manipulator_deselect(mmap, highlighted)) { + redraw = true; + } + } + else if (wm_manipulator_select(C, mmap, highlighted)) { + redraw = true; + } + + if (redraw) { + ED_region_tag_redraw(ar); + } + + return OPERATOR_FINISHED; + } + else { + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + return OPERATOR_PASS_THROUGH; +} + +void MANIPULATORGROUP_OT_manipulator_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Manipulator Select"; + ot->description = "Select the currently highlighted manipulator"; + ot->idname = "MANIPULATORGROUP_OT_manipulator_select"; + + /* api callbacks */ + ot->invoke = manipulator_select_invoke; + + ot->flag = OPTYPE_UNDO; + + WM_operator_properties_mouse_select(ot); +} + +typedef struct ManipulatorTweakData { + wmManipulatorMap *mmap; + wmManipulator *active; + + int init_event; /* initial event type */ + int flag; /* tweak flags */ +} ManipulatorTweakData; + +static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel) +{ + ManipulatorTweakData *mtweak = op->customdata; + if (mtweak->active->exit) { + mtweak->active->exit(C, mtweak->active, cancel); + } + wm_manipulatormap_set_active_manipulator(mtweak->mmap, C, NULL, NULL); + MEM_freeN(mtweak); +} + +static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ManipulatorTweakData *mtweak = op->customdata; + wmManipulator *manipulator = mtweak->active; + + if (!manipulator) { + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if (event->type == mtweak->init_event && event->val == KM_RELEASE) { + manipulator_tweak_finish(C, op, false); + return OPERATOR_FINISHED; + } + + + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case TWEAK_MODAL_CANCEL: + manipulator_tweak_finish(C, op, true); + return OPERATOR_CANCELLED; + case TWEAK_MODAL_CONFIRM: + manipulator_tweak_finish(C, op, false); + return OPERATOR_FINISHED; + case TWEAK_MODAL_PRECISION_ON: + mtweak->flag |= WM_MANIPULATOR_TWEAK_PRECISE; + break; + case TWEAK_MODAL_PRECISION_OFF: + mtweak->flag &= ~WM_MANIPULATOR_TWEAK_PRECISE; + break; + } + } + + /* handle manipulator */ + if (manipulator->handler) { + manipulator->handler(C, event, manipulator, mtweak->flag); + } + + /* Ugly hack to send manipulator events */ + ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE; + + /* always return PASS_THROUGH so modal handlers + * with manipulators attached can update */ + return OPERATOR_PASS_THROUGH; +} + +static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulator *manipulator = mmap->mmap_context.highlighted_manipulator; + + if (!manipulator) { + /* wm_handlers_do_intern shouldn't let this happen */ + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + + /* activate highlighted manipulator */ + wm_manipulatormap_set_active_manipulator(mmap, C, event, manipulator); + + /* XXX temporary workaround for modal manipulator operator + * conflicting with modal operator attached to manipulator */ + if (manipulator->opname) { + wmOperatorType *ot = WM_operatortype_find(manipulator->opname, true); + if (ot->modal) { + return OPERATOR_FINISHED; + } + } + + + ManipulatorTweakData *mtweak = MEM_mallocN(sizeof(ManipulatorTweakData), __func__); + + mtweak->init_event = event->type; + mtweak->active = mmap->mmap_context.highlighted_manipulator; + mtweak->mmap = mmap; + mtweak->flag = 0; + + op->customdata = mtweak; + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +void MANIPULATORGROUP_OT_manipulator_tweak(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Manipulator Tweak"; + ot->description = "Tweak the active manipulator"; + ot->idname = "MANIPULATORGROUP_OT_manipulator_tweak"; + + /* api callbacks */ + ot->invoke = manipulator_tweak_invoke; + ot->modal = manipulator_tweak_modal; + + ot->flag = OPTYPE_UNDO; +} + +/** \} */ // Manipulator operators + + +static wmKeyMap *manipulatorgroup_tweak_modal_keymap(wmKeyConfig *keyconf, const char *mgroupname) +{ + wmKeyMap *keymap; + char name[KMAP_MAX_NAME]; + + static EnumPropertyItem modal_items[] = { + {TWEAK_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {TWEAK_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + {TWEAK_MODAL_PRECISION_ON, "PRECISION_ON", 0, "Enable Precision", ""}, + {TWEAK_MODAL_PRECISION_OFF, "PRECISION_OFF", 0, "Disable Precision", ""}, + {0, NULL, 0, NULL, NULL} + }; + + + BLI_snprintf(name, sizeof(name), "%s Tweak Modal Map", mgroupname); + keymap = WM_modalkeymap_get(keyconf, name); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) + return NULL; + + keymap = WM_modalkeymap_add(keyconf, name, modal_items); + + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL); + + WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM); + + WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON); + WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF); + + + WM_modalkeymap_assign(keymap, "MANIPULATORGROUP_OT_manipulator_tweak"); + + return keymap; +} + +/** + * Common default keymap for manipulator groups + */ +wmKeyMap *WM_manipulatorgroup_keymap_common(const struct wmManipulatorGroupType *mgrouptype, wmKeyConfig *config) +{ + /* Use area and region id since we might have multiple manipulators with the same name in different areas/regions */ + wmKeyMap *km = WM_keymap_find(config, mgrouptype->name, mgrouptype->spaceid, mgrouptype->regionid); + + WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0); + manipulatorgroup_tweak_modal_keymap(config, mgrouptype->name); + + return km; +} + +/** + * Variation of #WM_manipulatorgroup_keymap_common but with keymap items for selection + */ +wmKeyMap *WM_manipulatorgroup_keymap_common_sel(const struct wmManipulatorGroupType *mgrouptype, wmKeyConfig *config) +{ + /* Use area and region id since we might have multiple manipulators with the same name in different areas/regions */ + wmKeyMap *km = WM_keymap_find(config, mgrouptype->name, mgrouptype->spaceid, mgrouptype->regionid); + + WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0); + manipulatorgroup_tweak_modal_keymap(config, mgrouptype->name); + + wmKeyMapItem *kmi = WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_select", SELECTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "extend", false); + RNA_boolean_set(kmi->ptr, "deselect", false); + RNA_boolean_set(kmi->ptr, "toggle", false); + kmi = WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "extend", false); + RNA_boolean_set(kmi->ptr, "deselect", false); + RNA_boolean_set(kmi->ptr, "toggle", true); + + return km; +} + +/** \} */ /* wmManipulatorGroup */ + +/* -------------------------------------------------------------------- */ +/** \name wmManipulatorGroupType + * + * \{ */ + +/** + * Use this for registering manipulators on startup. For runtime, use #WM_manipulatorgrouptype_append_runtime. + */ +wmManipulatorGroupType *WM_manipulatorgrouptype_append( + wmManipulatorMapType *mmaptype, void (*mgrouptype_func)(wmManipulatorGroupType *)) +{ + wmManipulatorGroupType *mgrouptype = MEM_callocN(sizeof(wmManipulatorGroupType), "manipulator-group"); + + mgrouptype_func(mgrouptype); + mgrouptype->spaceid = mmaptype->spaceid; + mgrouptype->regionid = mmaptype->regionid; + BLI_strncpy(mgrouptype->mapidname, mmaptype->idname, MAX_NAME); + /* if not set, use default */ + if (!mgrouptype->keymap_init) { + mgrouptype->keymap_init = WM_manipulatorgroup_keymap_common; + } + + /* add the type for future created areas of the same type */ + BLI_addtail(&mmaptype->manipulator_grouptypes, mgrouptype); + return mgrouptype; +} + +/** + * Use this for registering manipulators on runtime. + */ +wmManipulatorGroupType *WM_manipulatorgrouptype_append_runtime( + const Main *main, wmManipulatorMapType *mmaptype, + void (*mgrouptype_func)(wmManipulatorGroupType *)) +{ + wmManipulatorGroupType *mgrouptype = WM_manipulatorgrouptype_append(mmaptype, mgrouptype_func); + + /* Main is missing on startup when we create new areas. + * So this is only called for manipulators initialized on runtime */ + WM_manipulatorgrouptype_init_runtime(main, mmaptype, mgrouptype); + + return mgrouptype; +} + +void WM_manipulatorgrouptype_init_runtime( + const Main *bmain, wmManipulatorMapType *mmaptype, + wmManipulatorGroupType *mgrouptype) +{ + /* init keymap - on startup there's an extra call to init keymaps for 'permanent' manipulator-groups */ + wm_manipulatorgrouptype_keymap_init(mgrouptype, ((wmWindowManager *)bmain->wm.first)->defaultconf); + + /* now create a manipulator for all existing areas */ + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + for (ARegion *ar = lb->first; ar; ar = ar->next) { + wmManipulatorMap *mmap = ar->manipulator_map; + if (mmap->type == mmaptype) { + wmManipulatorGroup *mgroup = wm_manipulatorgroup_new_from_type(mgrouptype); + + /* just add here, drawing will occur on next update */ + BLI_addtail(&mmap->manipulator_groups, mgroup); + wm_manipulatormap_set_highlighted_manipulator(mmap, NULL, NULL, 0); + ED_region_tag_redraw(ar); + } + } + } + } + } +} + +void WM_manipulatorgrouptype_unregister(bContext *C, Main *bmain, wmManipulatorGroupType *mgrouptype) +{ + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + for (ARegion *ar = lb->first; ar; ar = ar->next) { + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulatorGroup *mgroup, *mgroup_next; + + for (mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup_next) { + mgroup_next = mgroup->next; + if (mgroup->type == mgrouptype) { + wm_manipulatorgroup_free(C, mmap, mgroup); + ED_region_tag_redraw(ar); + } + } + } + } + } + } + + wmManipulatorMapType *mmaptype = WM_manipulatormaptype_find(&(const struct wmManipulatorMapType_Params) { + mgrouptype->mapidname, mgrouptype->spaceid, + mgrouptype->regionid}); + + BLI_remlink(&mmaptype->manipulator_grouptypes, mgrouptype); + mgrouptype->prev = mgrouptype->next = NULL; + + MEM_freeN(mgrouptype); +} + +void wm_manipulatorgrouptype_keymap_init(wmManipulatorGroupType *mgrouptype, wmKeyConfig *keyconf) +{ + mgrouptype->keymap = mgrouptype->keymap_init(mgrouptype, keyconf); +} + +/** \} */ /* wmManipulatorGroupType */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c b/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c new file mode 100644 index 00000000000..500092f5f2d --- /dev/null +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c @@ -0,0 +1,760 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/intern/wm_manipulatormap.c + * \ingroup wm + */ + +#include <string.h> + +#include "BKE_context.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_ghash.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "GPU_glew.h" +#include "GPU_select.h" + +#include "MEM_guardedalloc.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm_event_system.h" + +/* own includes */ +#include "wm_manipulator_wmapi.h" +#include "wm_manipulator_intern.h" + +/** + * Store all manipulator-maps here. Anyone who wants to register a manipulator for a certain + * area type can query the manipulator-map to do so. + */ +static ListBase manipulatormaptypes = {NULL, NULL}; + +/** + * Manipulator-map update tagging. + */ +enum eManipulatorMapUpdateFlags { + /* Tag manipulator-map for refresh. */ + MANIPULATORMAP_REFRESH = (1 << 0), +}; + + +/* -------------------------------------------------------------------- */ +/** \name wmManipulatorMap + * + * \{ */ + +/** + * Creates a manipulator-map with all registered manipulators for that type + */ +wmManipulatorMap *WM_manipulatormap_new_from_type(const struct wmManipulatorMapType_Params *mmap_params) +{ + wmManipulatorMapType *mmaptype = WM_manipulatormaptype_ensure(mmap_params); + wmManipulatorMap *mmap; + + mmap = MEM_callocN(sizeof(wmManipulatorMap), "ManipulatorMap"); + mmap->type = mmaptype; + mmap->update_flag = MANIPULATORMAP_REFRESH; + + /* create all manipulator-groups for this manipulator-map. We may create an empty one + * too in anticipation of manipulators from operators etc */ + for (wmManipulatorGroupType *mgrouptype = mmaptype->manipulator_grouptypes.first; + mgrouptype; + mgrouptype = mgrouptype->next) + { + wmManipulatorGroup *mgroup = wm_manipulatorgroup_new_from_type(mgrouptype); + BLI_addtail(&mmap->manipulator_groups, mgroup); + } + + return mmap; +} + +void wm_manipulatormap_selected_delete(wmManipulatorMap *mmap) +{ + MEM_SAFE_FREE(mmap->mmap_context.selected_manipulator); + mmap->mmap_context.tot_selected = 0; +} + +void wm_manipulatormap_delete(wmManipulatorMap *mmap) +{ + if (!mmap) + return; + + for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) { + mgroup_next = mgroup->next; + wm_manipulatorgroup_free(NULL, mmap, mgroup); + } + BLI_assert(BLI_listbase_is_empty(&mmap->manipulator_groups)); + + wm_manipulatormap_selected_delete(mmap); + + MEM_freeN(mmap); +} + +/** + * Creates and returns idname hash table for (visible) manipulators in \a mmap + * + * \param poll Polling function for excluding manipulators. + * \param data Custom data passed to \a poll + */ +static GHash *WM_manipulatormap_manipulator_hash_new( + const bContext *C, wmManipulatorMap *mmap, + bool (*poll)(const wmManipulator *, void *), + void *data, const bool include_hidden) +{ + GHash *hash = BLI_ghash_str_new(__func__); + + /* collect manipulators */ + for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) { + if (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)) { + for (wmManipulator *manipulator = mgroup->manipulators.first; + manipulator; + manipulator = manipulator->next) + { + if ((include_hidden || (manipulator->flag & WM_MANIPULATOR_HIDDEN) == 0) && + (!poll || poll(manipulator, data))) + { + BLI_ghash_insert(hash, manipulator->idname, manipulator); + } + } + } + } + + return hash; +} + +void WM_manipulatormap_tag_refresh(wmManipulatorMap *mmap) +{ + if (mmap) { + mmap->update_flag |= MANIPULATORMAP_REFRESH; + } +} + +static void manipulatormap_tag_updated(wmManipulatorMap *mmap) +{ + mmap->update_flag = 0; +} + +static bool manipulator_prepare_drawing( + wmManipulatorMap *mmap, wmManipulator *manipulator, + const bContext *C, ListBase *draw_manipulators) +{ + if (!wm_manipulator_is_visible(manipulator)) { + /* skip */ + } + else { + wm_manipulator_update(manipulator, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0); + BLI_addhead(draw_manipulators, BLI_genericNodeN(manipulator)); + return true; + } + + return false; +} + +/** + * Update manipulators of \a mmap to prepare for drawing. Adds all manipulators that + * should be drawn to list \a draw_manipulators, note that added items need freeing. + */ +static void manipulatormap_prepare_drawing( + wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators, const int drawstep) +{ + if (!mmap || BLI_listbase_is_empty(&mmap->manipulator_groups)) + return; + wmManipulator *active_manipulator = mmap->mmap_context.active_manipulator; + + /* only active manipulator needs updating */ + if (active_manipulator) { + if (manipulator_prepare_drawing(mmap, active_manipulator, C, draw_manipulators)) { + manipulatormap_tag_updated(mmap); + } + /* don't draw any other manipulators */ + return; + } + + for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) { + /* check group visibility - drawstep first to avoid unnecessary call of group poll callback */ + if (!wm_manipulatorgroup_is_visible_in_drawstep(mgroup, drawstep) || + !wm_manipulatorgroup_is_visible(mgroup, C)) + { + continue; + } + + /* needs to be initialized on first draw */ + wm_manipulatorgroup_ensure_initialized(mgroup, C); + /* update data if needed */ + /* XXX weak: Manipulator-group may skip refreshing if it's invisible (map gets untagged nevertheless) */ + if (mmap->update_flag & MANIPULATORMAP_REFRESH && mgroup->type->refresh) { + mgroup->type->refresh(C, mgroup); + } + /* prepare drawing */ + if (mgroup->type->draw_prepare) { + mgroup->type->draw_prepare(C, mgroup); + } + + for (wmManipulator *manipulator = mgroup->manipulators.first; manipulator; manipulator = manipulator->next) { + manipulator_prepare_drawing(mmap, manipulator, C, draw_manipulators); + } + } + + manipulatormap_tag_updated(mmap); +} + +/** + * Draw all visible manipulators in \a mmap. + * Uses global draw_manipulators listbase. + */ +static void manipulators_draw_list(const wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators) +{ + if (!mmap) + return; + BLI_assert(!BLI_listbase_is_empty(&mmap->manipulator_groups)); + + /* draw_manipulators contains all visible manipulators - draw them */ + for (LinkData *link = draw_manipulators->first, *link_next; link; link = link_next) { + wmManipulator *manipulator = link->data; + link_next = link->next; + + manipulator->draw(C, manipulator); + /* free/remove manipulator link after drawing */ + BLI_freelinkN(draw_manipulators, link); + } +} + +void WM_manipulatormap_draw(wmManipulatorMap *mmap, const bContext *C, const int drawstep) +{ + ListBase draw_manipulators = {NULL}; + + manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep); + manipulators_draw_list(mmap, C, &draw_manipulators); + BLI_assert(BLI_listbase_is_empty(&draw_manipulators)); +} + +static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible_manipulators) +{ + int selectionbase = 0; + wmManipulator *manipulator; + + for (LinkData *link = visible_manipulators->first; link; link = link->next) { + manipulator = link->data; + /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected manipulator part id */ + manipulator->render_3d_intersection(C, manipulator, selectionbase << 8); + + selectionbase++; + } +} + +static int manipulator_find_intersected_3D_intern( + ListBase *visible_manipulators, const bContext *C, const int co[2], + const float hotspot) +{ + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + rctf rect, selrect; + GLuint buffer[64]; // max 4 items per select, so large enuf + short hits; + const bool do_passes = GPU_select_query_check_active(); + + extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect); + + + rect.xmin = co[0] - hotspot; + rect.xmax = co[0] + hotspot; + rect.ymin = co[1] - hotspot; + rect.ymax = co[1] + hotspot; + + selrect = rect; + + view3d_winmatrix_set(ar, v3d, &rect); + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + + if (do_passes) + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + else + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_ALL, 0); + /* do the drawing */ + manipulator_find_active_3D_loop(C, visible_manipulators); + + hits = GPU_select_end(); + + if (do_passes) { + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + manipulator_find_active_3D_loop(C, visible_manipulators); + GPU_select_end(); + } + + view3d_winmatrix_set(ar, v3d, NULL); + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + + return hits > 0 ? buffer[3] : -1; +} + +/** + * Try to find a 3D manipulator at screen-space coordinate \a co. Uses OpenGL picking. + */ +static wmManipulator *manipulator_find_intersected_3D( + bContext *C, const int co[2], ListBase *visible_manipulators, + unsigned char *part) +{ + wmManipulator *result = NULL; + const float hotspot = 14.0f; + int ret; + + *part = 0; + /* set up view matrices */ + view3d_operator_needs_opengl(C); + + ret = manipulator_find_intersected_3D_intern(visible_manipulators, C, co, 0.5f * hotspot); + + if (ret != -1) { + LinkData *link; + int retsec; + retsec = manipulator_find_intersected_3D_intern(visible_manipulators, C, co, 0.2f * hotspot); + + if (retsec != -1) + ret = retsec; + + link = BLI_findlink(visible_manipulators, ret >> 8); + *part = ret & 255; + result = link->data; + } + + return result; +} + +/** + * Try to find a manipulator under the mouse position. 2D intersections have priority over + * 3D ones (could check for smallest screen-space distance but not needed right now). + */ +wmManipulator *wm_manipulatormap_find_highlighted_manipulator( + wmManipulatorMap *mmap, bContext *C, const wmEvent *event, + unsigned char *part) +{ + wmManipulator *manipulator = NULL; + ListBase visible_3d_manipulators = {NULL}; + + for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) { + if (wm_manipulatorgroup_is_visible(mgroup, C)) { + if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_IS_3D) { + wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators); + } + else if ((manipulator = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, part))) { + break; + } + } + } + + if (!BLI_listbase_is_empty(&visible_3d_manipulators)) { + manipulator = manipulator_find_intersected_3D(C, event->mval, &visible_3d_manipulators, part); + BLI_freelistN(&visible_3d_manipulators); + } + + return manipulator; +} + +void WM_manipulatormap_add_handlers(ARegion *ar, wmManipulatorMap *mmap) +{ + wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "manipulator handler"); + + BLI_assert(mmap == ar->manipulator_map); + handler->manipulator_map = mmap; + BLI_addtail(&ar->handlers, handler); +} + +void wm_manipulatormaps_handled_modal_update( + bContext *C, wmEvent *event, wmEventHandler *handler, + const wmOperatorType *ot) +{ + const bool modal_running = (handler->op != NULL); + + /* happens on render or when joining areas */ + if (!handler->op_region || !handler->op_region->manipulator_map) + return; + + /* hide operator manipulators */ + if (!modal_running && ot->mgrouptype) { + ot->mgrouptype->op = NULL; + } + + wmManipulatorMap *mmap = handler->op_region->manipulator_map; + wmManipulator *manipulator = wm_manipulatormap_get_active_manipulator(mmap); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + + wm_manipulatormap_handler_context(C, handler); + + /* regular update for running operator */ + if (modal_running) { + if (manipulator && manipulator->handler && manipulator->opname && + STREQ(manipulator->opname, handler->op->idname)) + { + manipulator->handler(C, event, manipulator, 0); + } + } + /* operator not running anymore */ + else { + wm_manipulatormap_set_highlighted_manipulator(mmap, C, NULL, 0); + wm_manipulatormap_set_active_manipulator(mmap, C, event, NULL); + } + + /* restore the area */ + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); +} + +/** + * Deselect all selected manipulators in \a mmap. + * \return if selection has changed. + */ +bool wm_manipulatormap_deselect_all(wmManipulatorMap *mmap, wmManipulator ***sel) +{ + if (*sel == NULL || mmap->mmap_context.tot_selected == 0) + return false; + + for (int i = 0; i < mmap->mmap_context.tot_selected; i++) { + (*sel)[i]->state &= ~WM_MANIPULATOR_SELECTED; + (*sel)[i] = NULL; + } + wm_manipulatormap_selected_delete(mmap); + + /* always return true, we already checked + * if there's anything to deselect */ + return true; +} + +BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *manipulator, void *UNUSED(data)) +{ + return (manipulator->mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECTABLE); +} + +/** + * Select all selectable manipulators in \a mmap. + * \return if selection has changed. + */ +static bool wm_manipulatormap_select_all_intern( + bContext *C, wmManipulatorMap *mmap, wmManipulator ***sel, + const int action) +{ + /* GHash is used here to avoid having to loop over all manipulators twice (once to + * get tot_sel for allocating, once for actually selecting). Instead we collect + * selectable manipulators in hash table and use this to get tot_sel and do selection */ + + GHash *hash = WM_manipulatormap_manipulator_hash_new(C, mmap, manipulator_selectable_poll, NULL, true); + GHashIterator gh_iter; + int i, *tot_sel = &mmap->mmap_context.tot_selected; + bool changed = false; + + *tot_sel = BLI_ghash_size(hash); + *sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_sel)); + + GHASH_ITER_INDEX (gh_iter, hash, i) { + wmManipulator *manipulator_iter = BLI_ghashIterator_getValue(&gh_iter); + + if ((manipulator_iter->state & WM_MANIPULATOR_SELECTED) == 0) { + changed = true; + } + manipulator_iter->state |= WM_MANIPULATOR_SELECTED; + if (manipulator_iter->select) { + manipulator_iter->select(C, manipulator_iter, action); + } + (*sel)[i] = manipulator_iter; + BLI_assert(i < (*tot_sel)); + } + /* highlight first manipulator */ + wm_manipulatormap_set_highlighted_manipulator(mmap, C, (*sel)[0], (*sel)[0]->highlighted_part); + + BLI_ghash_free(hash, NULL, NULL); + return changed; +} + +/** + * Select/Deselect all selectable manipulators in \a mmap. + * \return if selection has changed. + * + * TODO select all by type + */ +bool WM_manipulatormap_select_all(bContext *C, wmManipulatorMap *mmap, const int action) +{ + wmManipulator ***sel = &mmap->mmap_context.selected_manipulator; + bool changed = false; + + switch (action) { + case SEL_SELECT: + changed = wm_manipulatormap_select_all_intern(C, mmap, sel, action); + break; + case SEL_DESELECT: + changed = wm_manipulatormap_deselect_all(mmap, sel); + break; + default: + BLI_assert(0); + break; + } + + if (changed) + WM_event_add_mousemove(C); + + return changed; +} + +/** + * Prepare context for manipulator handling (but only if area/region is + * part of screen). Version of #wm_handler_op_context for manipulators. + */ +void wm_manipulatormap_handler_context(bContext *C, wmEventHandler *handler) +{ + bScreen *screen = CTX_wm_screen(C); + + if (screen) { + if (handler->op_area == NULL) { + /* do nothing in this context */ + } + else { + ScrArea *sa; + + for (sa = screen->areabase.first; sa; sa = sa->next) + if (sa == handler->op_area) + break; + if (sa == NULL) { + /* when changing screen layouts with running modal handlers (like render display), this + * is not an error to print */ + if (handler->manipulator_map == NULL) + printf("internal error: modal manipulator-map handler has invalid area\n"); + } + else { + ARegion *ar; + CTX_wm_area_set(C, sa); + for (ar = sa->regionbase.first; ar; ar = ar->next) + if (ar == handler->op_region) + break; + /* XXX no warning print here, after full-area and back regions are remade */ + if (ar) + CTX_wm_region_set(C, ar); + } + } + } +} + +bool WM_manipulatormap_cursor_set(const wmManipulatorMap *mmap, wmWindow *win) +{ + for (; mmap; mmap = mmap->next) { + wmManipulator *manipulator = mmap->mmap_context.highlighted_manipulator; + if (manipulator && manipulator->get_cursor) { + WM_cursor_set(win, manipulator->get_cursor(manipulator)); + return true; + } + } + + return false; +} + +void wm_manipulatormap_set_highlighted_manipulator( + wmManipulatorMap *mmap, const bContext *C, wmManipulator *manipulator, + unsigned char part) +{ + if ((manipulator != mmap->mmap_context.highlighted_manipulator) || + (manipulator && part != manipulator->highlighted_part)) + { + if (mmap->mmap_context.highlighted_manipulator) { + mmap->mmap_context.highlighted_manipulator->state &= ~WM_MANIPULATOR_HIGHLIGHT; + mmap->mmap_context.highlighted_manipulator->highlighted_part = 0; + } + + mmap->mmap_context.highlighted_manipulator = manipulator; + + if (manipulator) { + manipulator->state |= WM_MANIPULATOR_HIGHLIGHT; + manipulator->highlighted_part = part; + + if (C && manipulator->get_cursor) { + wmWindow *win = CTX_wm_window(C); + WM_cursor_set(win, manipulator->get_cursor(manipulator)); + } + } + else { + if (C) { + wmWindow *win = CTX_wm_window(C); + WM_cursor_set(win, CURSOR_STD); + } + } + + /* tag the region for redraw */ + if (C) { + ARegion *ar = CTX_wm_region(C); + ED_region_tag_redraw(ar); + } + } +} + +wmManipulator *wm_manipulatormap_get_highlighted_manipulator(wmManipulatorMap *mmap) +{ + return mmap->mmap_context.highlighted_manipulator; +} + +void wm_manipulatormap_set_active_manipulator( + wmManipulatorMap *mmap, bContext *C, const wmEvent *event, wmManipulator *manipulator) +{ + if (manipulator && C) { + manipulator->state |= WM_MANIPULATOR_ACTIVE; + mmap->mmap_context.active_manipulator = manipulator; + + if (manipulator->opname) { + wmOperatorType *ot = WM_operatortype_find(manipulator->opname, 0); + + if (ot) { + /* first activate the manipulator itself */ + if (manipulator->invoke && manipulator->handler) { + manipulator->invoke(C, event, manipulator); + } + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &manipulator->opptr); + + /* we failed to hook the manipulator to the operator handler or operator was cancelled, return */ + if (!mmap->mmap_context.active_manipulator) { + manipulator->state &= ~WM_MANIPULATOR_ACTIVE; + /* first activate the manipulator itself */ + if (manipulator->interaction_data) { + MEM_freeN(manipulator->interaction_data); + manipulator->interaction_data = NULL; + } + } + return; + } + else { + printf("Manipulator error: operator not found"); + mmap->mmap_context.active_manipulator = NULL; + return; + } + } + else { + if (manipulator->invoke && manipulator->handler) { + manipulator->invoke(C, event, manipulator); + } + } + WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL); + } + else { + manipulator = mmap->mmap_context.active_manipulator; + + + /* deactivate, manipulator but first take care of some stuff */ + if (manipulator) { + manipulator->state &= ~WM_MANIPULATOR_ACTIVE; + /* first activate the manipulator itself */ + if (manipulator->interaction_data) { + MEM_freeN(manipulator->interaction_data); + manipulator->interaction_data = NULL; + } + } + mmap->mmap_context.active_manipulator = NULL; + + if (C) { + WM_cursor_grab_disable(CTX_wm_window(C), NULL); + ED_region_tag_redraw(CTX_wm_region(C)); + WM_event_add_mousemove(C); + } + } +} + +wmManipulator *wm_manipulatormap_get_active_manipulator(wmManipulatorMap *mmap) +{ + return mmap->mmap_context.active_manipulator; +} + +/** \} */ /* wmManipulatorMap */ + + +/* -------------------------------------------------------------------- */ +/** \name wmManipulatorMapType + * + * \{ */ + +wmManipulatorMapType *WM_manipulatormaptype_find( + const struct wmManipulatorMapType_Params *mmap_params) +{ + for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) { + if (mmaptype->spaceid == mmap_params->spaceid && + mmaptype->regionid == mmap_params->regionid && + STREQ(mmaptype->idname, mmap_params->idname)) + { + return mmaptype; + } + } + + return NULL; +} + +wmManipulatorMapType *WM_manipulatormaptype_ensure( + const struct wmManipulatorMapType_Params *mmap_params) +{ + wmManipulatorMapType *mmaptype = WM_manipulatormaptype_find(mmap_params); + + if (mmaptype) { + return mmaptype; + } + + mmaptype = MEM_callocN(sizeof(wmManipulatorMapType), "manipulatortype list"); + mmaptype->spaceid = mmap_params->spaceid; + mmaptype->regionid = mmap_params->regionid; + BLI_strncpy(mmaptype->idname, mmap_params->idname, sizeof(mmaptype->idname)); + BLI_addhead(&manipulatormaptypes, mmaptype); + + return mmaptype; +} + +void wm_manipulatormaptypes_free(void) +{ + for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) { + BLI_freelistN(&mmaptype->manipulator_grouptypes); + } + BLI_freelistN(&manipulatormaptypes); +} + +/** + * Initialize keymaps for all existing manipulator-groups + */ +void wm_manipulators_keymap(wmKeyConfig *keyconf) +{ + wmManipulatorMapType *mmaptype; + wmManipulatorGroupType *mgrouptype; + + /* we add this item-less keymap once and use it to group manipulator-group keymaps into it */ + WM_keymap_find(keyconf, "Manipulators", 0, 0); + + for (mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) { + for (mgrouptype = mmaptype->manipulator_grouptypes.first; mgrouptype; mgrouptype = mgrouptype->next) { + wm_manipulatorgrouptype_keymap_init(mgrouptype, keyconf); + } + } +} + +/** \} */ /* wmManipulatorMapType */ + diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h b/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h new file mode 100644 index 00000000000..c5008cef896 --- /dev/null +++ b/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h @@ -0,0 +1,90 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/manipulators/wm_manipulator_wmapi.h + * \ingroup wm + * + * \name Manipulators Window Manager API + * API for usage in window manager code only. It should contain all functionality + * needed to hook up the manipulator system with Blender's window manager. It's + * mostly the event system that needs to communicate with manipulator code. + * + * Only included in wm.h and lower level files. + */ + + +#ifndef __WM_MANIPULATOR_WMAPI_H__ +#define __WM_MANIPULATOR_WMAPI_H__ + +struct wmEventHandler; +struct wmManipulatorMap; +struct wmOperatorType; +struct wmOperator; + + +/* -------------------------------------------------------------------- */ +/* wmManipulator */ + +typedef void (*wmManipulatorSelectFunc)(struct bContext *, struct wmManipulator *, const int); + +struct wmManipulatorGroup *wm_manipulator_get_parent_group(const struct wmManipulator *manipulator); + +/* -------------------------------------------------------------------- */ +/* wmManipulatorGroup */ + +void MANIPULATORGROUP_OT_manipulator_select(struct wmOperatorType *ot); +void MANIPULATORGROUP_OT_manipulator_tweak(struct wmOperatorType *ot); + +void wm_manipulatorgroup_attach_to_modal_handler( + struct bContext *C, struct wmEventHandler *handler, + struct wmManipulatorGroupType *mgrouptype, struct wmOperator *op); + +/* -------------------------------------------------------------------- */ +/* wmManipulatorMap */ + +void wm_manipulatormap_delete(struct wmManipulatorMap *mmap); +void wm_manipulatormaptypes_free(void); + +void wm_manipulators_keymap(struct wmKeyConfig *keyconf); + +void wm_manipulatormaps_handled_modal_update( + bContext *C, struct wmEvent *event, struct wmEventHandler *handler, + const struct wmOperatorType *ot); +void wm_manipulatormap_handler_context(bContext *C, struct wmEventHandler *handler); + +struct wmManipulator *wm_manipulatormap_find_highlighted_manipulator( + struct wmManipulatorMap *mmap, bContext *C, + const struct wmEvent *event, unsigned char *part); +void wm_manipulatormap_set_highlighted_manipulator( + struct wmManipulatorMap *mmap, const bContext *C, + struct wmManipulator *manipulator, unsigned char part); +struct wmManipulator *wm_manipulatormap_get_highlighted_manipulator(struct wmManipulatorMap *mmap); +void wm_manipulatormap_set_active_manipulator( + struct wmManipulatorMap *mmap, bContext *C, + const struct wmEvent *event, struct wmManipulator *manipulator); +struct wmManipulator *wm_manipulatormap_get_active_manipulator(struct wmManipulatorMap *mmap); + +#endif /* __WM_MANIPULATOR_WMAPI_H__ */ + diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 2f06ddab1e8..3dd294128e2 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -34,6 +34,8 @@ struct wmWindow; struct ReportList; +#include "manipulators/wm_manipulator_wmapi.h" + typedef struct wmPaintCursor { struct wmPaintCursor *next, *prev; diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index efc01b1f8a8..2f7ebbc1def 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -52,7 +52,7 @@ typedef struct wmEventHandler { wmKeyMap *keymap; /* pointer to builtin/custom keymaps */ const rcti *bblocal, *bbwin; /* optional local and windowspace bb */ - /* modal operator handler */ + /* modal operator handler and WM_HANDLER_FILESELECT */ wmOperator *op; /* for derived/modal handlers */ struct ScrArea *op_area; /* for derived/modal handlers */ struct ARegion *op_region; /* for derived/modal handlers */ @@ -68,7 +68,8 @@ typedef struct wmEventHandler { /* drop box handler */ ListBase *dropboxes; - + /* manipulator handler */ + struct wmManipulatorMap *manipulator_map; } wmEventHandler; /* custom types for handlers, for signalling, freeing */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 3085f138846..9d34bc24e6c 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -339,6 +339,8 @@ enum { EVT_DROP = 0x5023, EVT_BUT_CANCEL = 0x5024, + /* could become manipulator callback */ + EVT_MANIPULATOR_UPDATE = 0x5025, /* ********** End of Blender internal events. ********** */ }; diff --git a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt index 0e570e19258..d2c2129532a 100644 --- a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt +++ b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt @@ -35,11 +35,12 @@ set(INC ../../blender/blenloader ../../blender/makesdna ../../blender/makesrna + ../../../intern/glew-mx ../../../intern/guardedalloc ) set(INC_SYS - + ${GLEW_INCLUDE_PATH} ) set(SRC diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index a297dac0f55..6b615f5a121 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -178,6 +178,8 @@ struct wmWindowManager; #include "../blender/editors/include/UI_resources.h" #include "../blender/editors/include/UI_view2d.h" #include "../blender/freestyle/FRS_freestyle.h" +#include "../blender/gpu/GPU_immediate.h" +#include "../blender/gpu/GPU_matrix.h" #include "../blender/python/BPY_extern.h" #include "../blender/render/extern/include/RE_engine.h" #include "../blender/render/extern/include/RE_pipeline.h" @@ -779,4 +781,7 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende bool RE_RenderResult_is_stereo(RenderResult *res) RET_ZERO void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imfptr) RET_NONE +/* GPU */ +void immBindBuiltinProgram(GPUBuiltinShader shader_id) RET_NONE + #endif // WITH_GAMEENGINE diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 4eb72fb1619..06119b35e37 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1195,13 +1195,13 @@ static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(ar return 0; } -static const char arg_handle_basic_shader_glsl_use_new_doc[] = -"\n\tUse new GLSL basic shader" +static const char arg_handle_basic_shader_use_legacy_doc[] = +"\n\tUse legacy (non-GLSL) basic shader" ; -static int arg_handle_basic_shader_glsl_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) +static int arg_handle_basic_shader_use_legacy(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { - printf("Using new GLSL basic shader.\n"); - GPU_basic_shader_use_glsl_set(true); + printf("Using legacy (non-GLSL) basic shader.\n"); + GPU_basic_shader_use_glsl_set(false); return 0; } @@ -1841,7 +1841,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle) CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM); BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", CB(arg_handle_depsgraph_use_new), NULL); - BLI_argsAdd(ba, 1, NULL, "--enable-new-basic-shader-glsl", CB(arg_handle_basic_shader_glsl_use_new), NULL); + BLI_argsAdd(ba, 1, NULL, "--enable-legacy-basic-shader", CB(arg_handle_basic_shader_use_legacy), NULL); BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL); |