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