]> git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/bobtoolz/DPatch.cpp
bobtoolz fixes to patch merging
[xonotic/netradiant.git] / contrib / bobtoolz / DPatch.cpp
1 /*
2 BobToolz plugin for GtkRadiant
3 Copyright (C) 2001 Gordon Biggans
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 // DPatch.cpp: implementation of the DPatch class.
21 //
22 //////////////////////////////////////////////////////////////////////
23
24 #include "DPatch.h"
25
26 #include <list>
27 #include "str.h"
28 #include "scenelib.h"
29
30 #include "ipatch.h"
31
32 #include "misc.h"
33 #include "./dialogs/dialogs-gtk.h"
34
35 //////////////////////////////////////////////////////////////////////
36 // Construction/Destruction
37 //////////////////////////////////////////////////////////////////////
38
39 //              Added patch merging, wahey!
40
41 //
42 //              problem is, you cant put patches into entities as yet :(
43 //
44
45 DPatch::DPatch()
46 {
47         width = MIN_PATCH_WIDTH;
48         height = MIN_PATCH_HEIGHT;
49         QER_entity = NULL;
50         QER_brush = NULL;
51 }
52
53 DPatch::~DPatch()
54 {
55
56 }
57
58 void DPatch::SetTexture(const char *textureName)
59 {
60         strcpy(texture, textureName);
61 }
62
63 void CopyDrawVert(const drawVert_t* in, drawVert_t* out)
64 {
65         out->lightmap[0] = in->lightmap[0];
66         out->lightmap[1] = in->lightmap[1];
67         out->st[0] = in->st[0];
68         out->st[1] = in->st[1];
69         VectorCopy(in->normal, out->normal);
70         VectorCopy(in->xyz, out->xyz);
71 }
72
73 void DPatch::BuildInRadiant(scene::Node* entity)
74 {
75         NodeSmartReference patch(GlobalPatchCreator().createPatch());
76
77   scene::Node& parent = entity != 0 ? *entity : GlobalRadiant().getMapWorldEntity();
78   Node_getTraversable(parent)->insert(patch);
79
80   GlobalPatchCreator().Patch_setShader(patch, texture);
81   GlobalPatchCreator().Patch_resize(patch, height, width);
82   PatchControlMatrix matrix = GlobalPatchCreator().Patch_getControlPoints(patch);
83         for(int x = 0; x < width; x++)
84   {
85                 for(int y = 0; y < height; y++)
86     {
87       PatchControl& p = matrix(x, y);
88       p.m_vertex[0] = points[x][y].xyz[0];
89       p.m_vertex[1] = points[x][y].xyz[1];
90       p.m_vertex[2] = points[x][y].xyz[2];
91       p.m_texcoord[0] = points[x][y].st[0];
92       p.m_texcoord[1] = points[x][y].st[1];
93     }
94   }
95   GlobalPatchCreator().Patch_controlPointsChanged(patch);
96   
97   QER_entity = entity;
98         QER_brush = patch.get_pointer();
99
100
101 #if 0
102         int nIndex = g_FuncTable.m_pfnCreatePatchHandle();
103     //$ FIXME: m_pfnGetPatchHandle
104         patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex);
105
106   b->patchBrush = true;
107   b->pPatch = Patch_Alloc();
108         b->pPatch->setDims(width,height);
109
110         for(int x = 0; x < width; x++)
111                 for(int y = 0; y < height; y++)
112                         CopyDrawVert(&points[x][y], &pm->ctrl[x][y]);
113
114 /*      if(entity)
115         {
116 //              strcpy(pm->d_texture->name, texture);
117
118                 brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();
119                 brush->patchBrush = true;
120                 brush->pPatch = pm;             
121
122                 pm->pSymbiot = brush;
123                 pm->bSelected = false;
124                 pm->bOverlay = false;   // bleh, f*cks up, just have to wait for a proper function
125                 pm->bDirty = true;              // or get my own patch out....
126                 pm->nListID = -1;
127
128                 g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity);
129         }
130         else*/  // patch to entity just plain dont work atm
131
132   if(entity)
133     g_FuncTable.m_pfnCommitPatchHandleToEntity(nIndex, pm, texture, entity);
134   else
135                 g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, texture);
136
137         QER_brush = pm->pSymbiot;
138 #endif
139 }
140
141 void DPatch::LoadFromPatch(scene::Instance& patch)
142 {
143   QER_entity = patch.path().parent().get_pointer();
144         QER_brush = patch.path().top().get_pointer();
145
146   PatchControlMatrix matrix = GlobalPatchCreator().Patch_getControlPoints(patch.path().top());
147
148   width = static_cast<int>(matrix.x());
149         height = static_cast<int>(matrix.y());
150
151   for(int x = 0; x < width; x++)
152   {
153                 for(int y = 0; y < height; y++)
154     {
155       PatchControl& p = matrix(x, y);
156       points[x][y].xyz[0] = p.m_vertex[0];
157       points[x][y].xyz[1] = p.m_vertex[1];
158       points[x][y].xyz[2] = p.m_vertex[2];
159       points[x][y].st[0] = p.m_texcoord[0];
160       points[x][y].st[1] = p.m_texcoord[1];
161     }
162   }
163         SetTexture(GlobalPatchCreator().Patch_getShader(patch.path().top()));
164
165 #if 0
166         SetTexture(brush->pPatch->GetShader());
167
168         width = brush->pPatch->getWidth();
169         height = brush->pPatch->getHeight();
170
171   for(int x = 0; x < height; x++)
172   {
173                 for(int y = 0; y < width; y++)
174     {
175       float *p = brush->pPatch->ctrlAt(ROW,x,y);
176       p[0] = points[x][y].xyz[0];
177       p[1] = points[x][y].xyz[1];
178       p[2] = points[x][y].xyz[2];
179       p[3] = points[x][y].st[0];
180       p[4] = points[x][y].st[1];
181     }
182   }
183 #endif
184 }
185
186 bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName)
187 {
188         if( !oldTextureName || !strcmp(texture, oldTextureName))
189         {
190                 strcpy(texture, newTextureName);
191                 return true;
192         }
193
194         return false;
195 }
196
197 void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], 
198                                   int startX, int startY, int number, bool horizontal, bool inverse)
199 {
200         int x = startX, y = startY, i, step;
201
202         if(inverse)
203                 step = -1;
204         else
205                 step = 1;
206
207         for(i = 0; i < number; i++)
208         {
209                 VectorCopy(points[x][y].xyz, array[i]);
210
211                 if(horizontal)
212                         x+=step;
213                 else
214                         y+=step;
215         }
216 }
217
218 void Print1dArray(vec3_t* array, int size)
219 {
220         for(int i = 0; i < size; i++)
221                 globalOutputStream() << "(" << array[i][0] << " " << array[i][1] << " " << array[i][2] << ")\t";
222         globalOutputStream() << "\n";
223 }
224
225 bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size)
226 {
227         int i;
228         bool equal = true;
229
230         for(i = 0; i < size; i++)
231         {
232                 if(!VectorCompare(a1[i], a2[size-i-1]))
233                 {
234                         equal = false;
235                         break;
236                 }
237         }
238         return equal;
239 }
240
241 patch_merge_t DPatch::IsMergable(DPatch *other)
242 {
243         int i, j;
244         vec3_t p1Array[4][MAX_PATCH_HEIGHT];
245         vec3_t p2Array[4][MAX_PATCH_HEIGHT];
246
247         int p1ArraySizes[4];
248         int p2ArraySizes[4];
249
250         patch_merge_t merge_info;
251
252         Build1dArray(p1Array[0], this->points, 0,                               0,                              this->width,    true,   false);
253         Build1dArray(p1Array[1], this->points, this->width-1,   0,                              this->height,   false,  false);
254         Build1dArray(p1Array[2], this->points, this->width-1,   this->height-1, this->width,    true,   true);
255         Build1dArray(p1Array[3], this->points, 0,                               this->height-1, this->height,   false,  true);
256
257         Build1dArray(p2Array[0], other->points, 0,                              0,                                      other->width,   true,   false);
258         Build1dArray(p2Array[1], other->points, other->width-1, 0,                                      other->height,  false,  false);
259         Build1dArray(p2Array[2], other->points, other->width-1, other->height-1,        other->width,   true,   true);
260         Build1dArray(p2Array[3], other->points, 0,                              other->height-1,        other->height,  false,  true);
261
262         p1ArraySizes[0] = this->width;
263         p1ArraySizes[1] = this->height;
264         p1ArraySizes[2] = this->width;
265         p1ArraySizes[3] = this->height;
266
267         p2ArraySizes[0] = other->width;
268         p2ArraySizes[1] = other->height;
269         p2ArraySizes[2] = other->width;
270         p2ArraySizes[3] = other->height;
271
272         for(i = 0; i < 4; i++)
273         {
274                 for(j = 0; j < 4; j++)
275                 {
276                         if(p1ArraySizes[i] == p2ArraySizes[j])
277                         {
278                                 if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i]))
279                                 {
280                                         merge_info.pos1 = i;
281                                         merge_info.pos2 = j;
282                                         merge_info.mergable = true;
283                                         return merge_info;
284                                 }
285                         }
286                 }
287         }
288         
289         merge_info.mergable = false;
290         return merge_info;
291 }
292
293 DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2)
294 {
295         while(merge_info.pos1 != 2)
296         {
297                 p1->Transpose();
298                 merge_info.pos1--;
299                 if(merge_info.pos1 < 0)
300                         merge_info.pos1 += 4;
301         }
302
303         while(merge_info.pos2 != 0)
304         {
305                 p2->Transpose();
306                 merge_info.pos2--;
307                 if(merge_info.pos2 < 0)
308                         merge_info.pos2 += 3;
309         }
310
311         int newHeight = p1->height + p2->height - 1; 
312         if(newHeight > MAX_PATCH_HEIGHT)
313                 return false;
314
315         DPatch* newPatch = new DPatch();
316
317         newPatch->height        = newHeight;
318         newPatch->width         = p1->width;
319         newPatch->SetTexture(p1->texture);
320
321         for(int y = 0; y < p1->height; y++)
322                 for(int x = 0; x < p1->width; x++)
323                         newPatch->points[x][y] = p1->points[x][y];
324         
325         for(int y = 1; y < p2->height; y++)
326                 for(int x = 0; x < p2->width; x++)
327                         newPatch->points[x][(y + p1->height - 1)] = p2->points[x][y];
328         
329 //      newPatch->Invert();
330         return newPatch;
331 }
332
333 void DPatch::Invert()
334 {
335         int i, j;
336
337         for(i = 0 ; i < width ; i++ ) 
338         {
339                 for(j = 0; j < height / 2; j++)
340                 {
341       std::swap(points[i][height - 1- j], points[i][j]);
342                 }
343         }
344 }
345 /*
346 //Was used for debugging, obsolete function
347 DPatch* DPatch::TransposePatch(DPatch *p1)
348 {
349         globalOutputStream() << "Source patch ";
350     p1->DebugPrint();
351     p1->Transpose();
352     globalOutputStream() << "Transposed";
353     p1->DebugPrint();
354   
355     DPatch* newPatch = new DPatch();
356         newPatch->height        = p1->height;
357         newPatch->width         = p1->width;
358         newPatch->SetTexture(p1->texture);
359     
360         for(int x = 0; x < p1->height; x++)
361         {
362                 for(int y = 0; y < p1->width; y++)
363                 {
364             newPatch->points[x][y] = p1->points[x][y];
365         }
366     }
367         return newPatch;
368 }
369
370 //Function to figure out what is actually going wrong.
371 void DPatch::DebugPrint()
372 {
373     globalOutputStream() << "width: " << width << "\theight: " << height << "\n";
374     for(int x = 0; x < height; x++)
375         {
376                 for(int y = 0; y < width; y++)
377                 {
378             globalOutputStream() << "\t(" << points[x][y].xyz[0] << " " << points[x][y].xyz[1] << " " << points[x][y].xyz[2] << ")\t";
379         }
380         globalOutputStream() << "\n";
381     }
382 }
383  */
384
385 void DPatch::Transpose()
386 {
387         int             i, j, w;
388
389         if ( width > height ) 
390         {
391                 for ( i = 0 ; i < height ; i++ ) 
392                 {
393                         for ( j = i + 1 ; j < width ; j++ ) 
394                         {
395                                 if ( j < height ) 
396                                 {
397                                         // swap the value
398           std::swap(points[j][i], points[i][j]);
399                                 } 
400                                 else 
401                                 {
402                                 // just copy
403                                         points[i][j] = points[j][i];
404                         }
405                 }
406                  }
407         } 
408         else 
409         {
410                 for ( i = 0 ; i < width ; i++ ) 
411         {
412                         for ( j = i + 1 ; j < height ; j++ ) 
413                         {
414                         if ( j < width ) 
415                                 {
416                                         // swap the value
417           std::swap(points[i][j], points[j][i]);
418                         } 
419                                 else 
420                                 {
421                                 // just copy
422                                         points[j][i] = points[i][j];
423                         }
424                 }
425         }
426     }
427
428         w = width;
429         width = height;
430         height = w;
431
432         Invert();
433 }
434
435 std::list<DPatch> DPatch::SplitCols()
436 {
437         std::list<DPatch> patchList;
438         int i;
439         int x, y;
440
441         if(height >= 5)
442         {
443                 for(i = 0; i < (height-1)/2; i++)
444                 {
445                         DPatch p;
446
447                         p.width = width;
448                         p.height = MIN_PATCH_HEIGHT;
449                         p.SetTexture(texture);
450                         for(x = 0; x < p.width; x++)
451                         {
452                                 for(y = 0; y < MIN_PATCH_HEIGHT; y++)
453                                 {
454                                         p.points[x][y] = points[x][(i*2)+y];
455                                 }
456                         }                       
457                         patchList.push_back(p);
458                 }
459         } else {
460         //globalErrorStream() << "bobToolz SplitPatchRows: Patch has not enough rows for splitting.\n";
461                 patchList.push_back(*this);
462                         }
463         return patchList;
464 }
465
466 std::list<DPatch> DPatch::SplitRows()
467 {
468         std::list<DPatch> patchList;
469         int i;
470         int x, y;
471         
472         if(width >= 5)
473         {
474                 for(i = 0; i < (width-1)/2; i++)
475                 {
476                         DPatch p;
477                         
478                         p.width = MIN_PATCH_WIDTH;
479                         p.height = height;
480                         p.SetTexture(texture);
481                         
482                         for(x = 0; x < MIN_PATCH_WIDTH; x++)
483                         {
484                                 for(y = 0; y < p.height; y++)
485                                 {
486                                         p.points[x][y] = points[(i*2)+x][y];
487                                 }
488                         }
489                         patchList.push_back(p);
490                 }
491         } else 
492         {
493                 patchList.push_back(*this);
494                         }
495         return patchList;
496 }
497
498 std::list<DPatch> DPatch::Split()
499 {
500         std::list<DPatch> patchList;
501         int i;
502         int x, y;
503         
504         if(width >= 5)
505         {
506                 std::list<DPatch> patchColList = SplitCols();
507         for(std::list<DPatch>::iterator patchesCol = patchColList.begin(); patchesCol != patchColList.end(); patchesCol++)
508                 {
509                    std::list<DPatch> patchRowList = (*patchesCol).SplitRows();
510                for(std::list<DPatch>::iterator patchesRow = patchRowList.begin(); patchesRow != patchRowList.end(); patchesRow++)
511                         {
512               patchList.push_front(*patchesRow);
513                                 }
514                         }
515         } else  if(height >= 5) 
516         {
517                 std::list<DPatch> patchRowList = SplitRows();
518         for(std::list<DPatch>::iterator patchesRow = patchRowList.begin(); patchesRow != patchRowList.end(); patchesRow++)
519                 {
520            patchList.push_front(*patchesRow);
521                                 }
522         } else 
523         {
524         //globalErrorStream() << "bobToolz SplitPatchRows: Patch has not enough rows for splitting.\n";
525                 patchList.push_back(*this);
526                         }
527         return patchList;
528 }