1 // OpenCSG - library for image-based CSG rendering for OpenGL 2 // Copyright (C) 2002-2016, Florian Kirsch, 3 // Hasso-Plattner-Institute at the University of Potsdam, Germany 4 // 5 // This library is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU General Public License, 7 // Version 2, as published by the Free Software Foundation. 8 // As a special exception, you have permission to link this library 9 // with the CGAL library and distribute executables. 10 // 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program; if not, write to the Free Software Foundation, 18 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 20 // 21 // stencilManager.cpp 22 // 23 24 #include "opencsgConfig.h" 25 #include <GL/glew.h> 26 #ifdef _WIN32 27 #include <GL/wglew.h> 28 #elif !defined(__APPLE__) 29 #include <GL/glxew.h> 30 #endif 31 #include "area.h" 32 #include "openglHelper.h" 33 #include "stencilManager.h" 34 #include <vector> 35 36 namespace OpenCSG { 37 38 namespace OpenGL { 39 StencilManager(const PCArea & area)40 StencilManager::StencilManager(const PCArea& area) : mArea(area), mSaved(false) {} 41 // Do not save the stencil buffer at all. 42 // This is, currently, used always. 43 ~StencilManager()44 StencilManager::~StencilManager() { } 45 getArea() const46 const PCArea& StencilManager::getArea() const { 47 return mArea; 48 } 49 clear()50 void StencilManager::clear() { 51 if (!mSaved) { 52 save(); 53 mSaved = true; 54 } 55 glStencilMask(OpenGL::stencilMask); 56 glClear(GL_STENCIL_BUFFER_BIT); 57 } 58 alreadySaved() const59 bool StencilManager::alreadySaved() const { 60 return mSaved; 61 } 62 save()63 void StencilManager::save() { 64 // implemented empty. will not save the stencil buffer 65 } 66 restore()67 void StencilManager::restore() { 68 // implemented empty. will not restore the stencil buffer 69 } 70 71 72 73 74 75 class StencilManagerGL10 : public StencilManager { 76 public: StencilManagerGL10(const PCArea & area)77 StencilManagerGL10(const PCArea& area) : StencilManager(area) {}; 78 // Saves and restores the stencil buffer by copying it from 79 // graphics memory to main memory and back. 80 81 // Warning: There appears to be a bug in this implementation. 82 // Saving and restoring does not work at all. 83 84 virtual void save(); 85 virtual void restore(); 86 }; 87 88 namespace { 89 std::vector<GLubyte>* buf = 0; 90 int dx, dy; 91 } 92 save()93 void StencilManagerGL10::save() { 94 95 const PCArea& area = getArea(); 96 dx = area.maxx - area.minx; 97 dy = area.maxy - area.miny; 98 99 unsigned int size = (8+dx)*dy; // 8 needed due to possible alignment (?) 100 if (!buf) { 101 buf = new std::vector<GLubyte>(size); 102 } else if (buf->size() < size) { 103 buf->resize(size); 104 } 105 106 glReadPixels(area.minx, area.miny, dx, dy, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &((*buf)[0])); 107 } 108 restore()109 void StencilManagerGL10::restore() { 110 111 if (!alreadySaved()) return; // stencil buffer was never changed, restore nothing 112 113 glMatrixMode(GL_PROJECTION); 114 glPushMatrix(); 115 glLoadIdentity(); 116 glMatrixMode(GL_MODELVIEW); 117 glPushMatrix(); 118 glLoadIdentity(); 119 120 glRasterPos2i(-1, -1); 121 glDrawPixels(dx, dy, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &((*buf)[0])); 122 123 glMatrixMode(GL_PROJECTION); 124 glPopMatrix(); 125 glMatrixMode(GL_MODELVIEW); 126 glPopMatrix(); 127 } 128 129 130 131 132 #ifdef _WIN32 133 class StencilManagerARBBufferRegionW32 : public StencilManager { 134 public: StencilManagerARBBufferRegionW32(const PCArea & area)135 StencilManagerARBBufferRegionW32(const PCArea& area) : StencilManager(area) {}; 136 // Uses the ARB_buffer_region extension for saving and restoring the 137 // stencil buffer. If this extension is available, this works well 138 // and is reasonably fast. 139 140 virtual void save(); 141 virtual void restore(); 142 private: 143 HDC hdc; 144 HANDLE handle; 145 }; 146 save()147 void StencilManagerARBBufferRegionW32::save() { 148 149 const PCArea& area = getArea(); 150 dx = area.maxx - area.minx; 151 dy = area.maxy - area.miny; 152 153 hdc = wglGetCurrentDC(); 154 handle = wglCreateBufferRegionARB(hdc, 1, WGL_STENCIL_BUFFER_BIT_ARB); 155 if (handle == 0) { 156 return; 157 } 158 int result = wglSaveBufferRegionARB(handle, area.minx, area.miny, dx, dy); 159 160 } 161 restore()162 void StencilManagerARBBufferRegionW32::restore() { 163 164 if (!alreadySaved()) return; // stencil buffer was never changed, restore nothing 165 166 const PCArea& area = getArea(); 167 dx = area.maxx - area.minx; 168 dy = area.maxy - area.miny; 169 170 wglRestoreBufferRegionARB(handle, area.minx, area.miny, dx, dy, 0, 0); 171 wglDeleteBufferRegionARB(handle); 172 } 173 174 #endif // _WIN32 175 176 177 getStencilManager(const PCArea & area)178 StencilManager* getStencilManager(const PCArea& area) { 179 #ifdef _WIN32 180 /* 181 // uncomment for possibility of saving the stencil buffer under windows 182 if (WGLEW_ARB_buffer_region) { 183 return new StencilManagerARBBufferRegionW32(area); 184 } 185 */ 186 #endif // _WIN32 187 188 /* 189 // this option has a bug unfortunately and is not usable 190 return new StencilManagerGL10(area); 191 */ 192 return new StencilManager(area); 193 } 194 195 } // namespace OpenGL 196 197 } // namespace OpenCSG 198 199 200