Ghost Context Refactor
[blender-staging.git] / source / gameengine / Rasterizer / RAS_OpenGLRasterizer / RAS_ListRasterizer.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
22  *  \ingroup bgerastogl
23  */
24
25 #include <iostream>
26
27 #include "RAS_ListRasterizer.h"
28
29 #ifdef WIN32
30 #include <windows.h>
31 #endif // WIN32
32
33 #include "glew-mx.h"
34
35 #include "RAS_MaterialBucket.h"
36 #include "RAS_TexVert.h"
37 #include "MT_assert.h"
38
39 //#if defined(DEBUG)
40 //#ifdef WIN32
41 //#define spit(x) std::cout << x << std::endl;
42 //#endif //WIN32
43 //#else
44 #define spit(x)
45 //#endif
46
47 RAS_ListSlot::RAS_ListSlot(RAS_ListRasterizer* rasty)
48 :       KX_ListSlot(),
49         m_list(0),
50         m_flag(LIST_MODIFY|LIST_CREATE),
51         m_matnr(0),
52         m_rasty(rasty)
53 {
54 }
55
56 int RAS_ListSlot::Release()
57 {
58         if (--m_refcount > 0)
59                 return m_refcount;
60         m_rasty->RemoveListSlot(this);
61         delete this;
62         return 0;
63 }
64
65 RAS_ListSlot::~RAS_ListSlot()
66 {
67         RemoveList();
68 }
69
70
71 void RAS_ListSlot::RemoveList()
72 {
73         if (m_list != 0) {
74                 spit("Releasing display list (" << m_list << ")");
75                 glDeleteLists((GLuint)m_list, 1);
76                 m_list =0;
77         }
78 }
79
80 void RAS_ListSlot::DrawList()
81 {
82         if (m_flag &LIST_STREAM || m_flag& LIST_NOCREATE) {
83                 RemoveList();
84                 return;
85         }
86         if (m_flag &LIST_MODIFY) {
87                 if (m_flag &LIST_CREATE) {
88                         if (m_list == 0) {
89                                 m_list = (unsigned int)glGenLists(1);
90                                 m_flag =  m_flag &~ LIST_CREATE;
91                                 spit("Created display list (" << m_list << ")");
92                         }
93                 }
94                 if (m_list != 0)
95                         glNewList((GLuint)m_list, GL_COMPILE);
96         
97                 m_flag |= LIST_BEGIN;
98                 return;
99         }
100         glCallList(m_list);
101 }
102
103 void RAS_ListSlot::EndList()
104 {
105         if (m_flag & LIST_BEGIN) {
106                 glEndList();
107                 m_flag = m_flag &~(LIST_BEGIN|LIST_MODIFY);
108                 m_flag |= LIST_END;
109                 glCallList(m_list);
110         }
111 }
112
113 void RAS_ListSlot::SetModified(bool mod)
114 {
115         if (mod && !(m_flag & LIST_MODIFY)) {
116                 spit("Modifying list (" << m_list << ")");
117                 m_flag = m_flag &~ LIST_END;
118                 m_flag |= LIST_STREAM;
119         }
120 }
121
122 bool RAS_ListSlot::End()
123 {
124         return (m_flag &LIST_END)!=0;
125 }
126
127
128
129 RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, int storage)
130 :       RAS_OpenGLRasterizer(canvas, storage)
131 {
132 }
133
134 RAS_ListRasterizer::~RAS_ListRasterizer() 
135 {
136         ReleaseAlloc();
137 }
138
139 void RAS_ListRasterizer::RemoveListSlot(RAS_ListSlot* list)
140 {
141         if (list->m_flag & LIST_DERIVEDMESH) {
142                 RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.begin();
143                 while (it != mDerivedMeshLists.end()) {
144                         RAS_ListSlots *slots = it->second;
145                         if (slots->size() > list->m_matnr && slots->at(list->m_matnr) == list) {
146                                 (*slots)[list->m_matnr] = NULL;
147                                 // check if all slots are NULL and if yes, delete the entry
148                                 int i;
149                                 for (i=slots->size(); i-- > 0; ) {
150                                         if (slots->at(i) != NULL)
151                                                 break;
152                                 }
153                                 if (i < 0) {
154                                         slots->clear();
155                                         delete slots;
156                                         mDerivedMeshLists.erase(it);
157                                 }
158                                 break;
159                         }
160                         ++it;
161                 }
162         } else {
163                 RAS_ArrayLists::iterator it = mArrayLists.begin();
164                 while (it != mArrayLists.end()) {
165                         if (it->second == list) {
166                                 mArrayLists.erase(it);
167                                 break;
168                         }
169                         it++;
170                 }
171         }
172 }
173
174 RAS_ListSlot* RAS_ListRasterizer::FindOrAdd(RAS_MeshSlot& ms)
175 {
176         /*
177          * Keep a copy of constant lists submitted for rendering,
178          * this guards against (replicated)new...delete every frame,
179          * and we can reuse lists!
180          * :: sorted by mesh slot
181          */
182         RAS_ListSlot* localSlot = (RAS_ListSlot*)ms.m_DisplayList;
183         if (!localSlot) {
184                 if (ms.m_pDerivedMesh) {
185                         // that means that we draw based on derived mesh, a display list is possible
186                         // Note that we come here only for static derived mesh
187                         int matnr = ms.m_bucket->GetPolyMaterial()->GetMaterialIndex();
188                         RAS_ListSlot* nullSlot = NULL;
189                         RAS_ListSlots *listVector;
190                         RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.find(ms.m_pDerivedMesh);
191                         if (it == mDerivedMeshLists.end()) {
192                                 listVector = new RAS_ListSlots(matnr+4, nullSlot);
193                                 localSlot = new RAS_ListSlot(this);
194                                 localSlot->m_flag |= LIST_DERIVEDMESH;
195                                 localSlot->m_matnr = matnr;
196                                 listVector->at(matnr) = localSlot;
197                                 mDerivedMeshLists.insert(std::pair<DerivedMesh*, RAS_ListSlots*>(ms.m_pDerivedMesh, listVector));
198                         } else {
199                                 listVector = it->second;
200                                 if (listVector->size() <= matnr)
201                                         listVector->resize(matnr+4, nullSlot);
202                                 if ((localSlot = listVector->at(matnr)) == NULL) {
203                                         localSlot = new RAS_ListSlot(this);
204                                         localSlot->m_flag |= LIST_DERIVEDMESH;
205                                         localSlot->m_matnr = matnr;
206                                         listVector->at(matnr) = localSlot;
207                                 } else {
208                                         localSlot->AddRef();
209                                 }
210                         }
211                 } else {
212                         RAS_ArrayLists::iterator it = mArrayLists.find(ms.m_displayArrays);
213                         if (it == mArrayLists.end()) {
214                                 localSlot = new RAS_ListSlot(this);
215                                 mArrayLists.insert(std::pair<RAS_DisplayArrayList, RAS_ListSlot*>(ms.m_displayArrays, localSlot));
216                         } else {
217                                 localSlot = static_cast<RAS_ListSlot*>(it->second->AddRef());
218                         }
219                 }
220         }
221         MT_assert(localSlot);
222         return localSlot;
223 }
224
225 void RAS_ListRasterizer::ReleaseAlloc()
226 {
227         for (RAS_ArrayLists::iterator it = mArrayLists.begin();it != mArrayLists.end();++it)
228                 delete it->second;
229         mArrayLists.clear();
230         for (RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.begin();it != mDerivedMeshLists.end();++it) {
231                 RAS_ListSlots* slots = it->second;
232                 for (int i=slots->size(); i-- > 0; ) {
233                         RAS_ListSlot* slot = slots->at(i);
234                         if (slot)
235                                 delete slot;
236                 }
237                 slots->clear();
238                 delete slots;
239         }
240         mDerivedMeshLists.clear();
241 }
242
243 void RAS_ListRasterizer::IndexPrimitives(RAS_MeshSlot& ms)
244 {
245         RAS_ListSlot* localSlot =0;
246
247         if (ms.m_bDisplayList) {
248                 localSlot = FindOrAdd(ms);
249                 localSlot->DrawList();
250                 if (localSlot->End()) {
251                         // save slot here too, needed for replicas and object using same mesh
252                         // => they have the same vertexarray but different mesh slot
253                         ms.m_DisplayList = localSlot;
254                         return;
255                 }
256         }
257         
258         RAS_OpenGLRasterizer::IndexPrimitives(ms);
259
260         if (ms.m_bDisplayList) {
261                 localSlot->EndList();
262                 ms.m_DisplayList = localSlot;
263         }
264 }
265
266
267 void RAS_ListRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms)
268 {
269         RAS_ListSlot* localSlot =0;
270
271         if (ms.m_bDisplayList) {
272                 localSlot = FindOrAdd(ms);
273                 localSlot->DrawList();
274
275                 if (localSlot->End()) {
276                         // save slot here too, needed for replicas and object using same mesh
277                         // => they have the same vertexarray but different mesh slot
278                         ms.m_DisplayList = localSlot;
279                         return;
280                 }
281         }
282
283         RAS_OpenGLRasterizer::IndexPrimitivesMulti(ms);
284
285         if (ms.m_bDisplayList) {
286                 localSlot->EndList();
287                 ms.m_DisplayList = localSlot;
288         }
289 }
290
291 bool RAS_ListRasterizer::Init(void)
292 {
293         return RAS_OpenGLRasterizer::Init();
294 }
295
296 void RAS_ListRasterizer::SetDrawingMode(int drawingmode)
297 {
298         RAS_OpenGLRasterizer::SetDrawingMode(drawingmode);
299 }
300
301 void RAS_ListRasterizer::Exit()
302 {
303         RAS_OpenGLRasterizer::Exit();
304 }
305
306 // eof