refactored plugin api; refactored callback library; added signals library
[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_brush = NULL;
50 }
51
52 DPatch::~DPatch()
53 {
54
55 }
56
57 void DPatch::SetTexture(const char *textureName)
58 {
59         strcpy(texture, textureName);
60 }
61
62 void CopyDrawVert(const drawVert_t* in, drawVert_t* out)
63 {
64         out->lightmap[0] = in->lightmap[0];
65         out->lightmap[1] = in->lightmap[1];
66         out->st[0] = in->st[0];
67         out->st[1] = in->st[1];
68         VectorCopy(in->normal, out->normal);
69         VectorCopy(in->xyz, out->xyz);
70 }
71
72 void DPatch::BuildInRadiant(scene::Node* entity)
73 {
74         NodeSmartReference node(GlobalPatchCreator().createPatch());
75
76         if(entity) {
77                 Node_getTraversable(*entity)->insert(node);
78         } else {
79                 Node_getTraversable(GlobalRadiant().getMapWorldEntity())->insert(node);
80         }
81 #if 0
82         int nIndex = g_FuncTable.m_pfnCreatePatchHandle();
83     //$ FIXME: m_pfnGetPatchHandle
84         patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex);
85
86   b->patchBrush = true;
87   b->pPatch = Patch_Alloc();
88         b->pPatch->setDims(width,height);
89
90         for(int x = 0; x < height; x++)
91   {
92                 for(int y = 0; y < width; y++)
93     {
94       float *p = b->pPatch->ctrlAt(ROW,x,y);
95       p[0] = points[x][y].xyz[0];
96       p[1] = points[x][y].xyz[1];
97       p[2] = points[x][y].xyz[2];
98       p[3] = points[x][y].st[0];
99       p[4] = points[x][y].st[1];
100     }
101   }
102
103         if(entity)
104                 g_FuncTable.m_pfnCommitBrushHandleToEntity(QER_brush, entity);
105         else
106                 g_FuncTable.m_pfnCommitBrushHandle(QER_brush);
107
108         for(int x = 0; x < width; x++)
109                 for(int y = 0; y < height; y++)
110                         CopyDrawVert(&points[x][y], &pm->ctrl[x][y]);
111
112         QER_patch = pm;
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::LoadFromBrush(scene::Node& brush)
142 {
143         QER_brush = &brush;
144
145 #if 0
146         SetTexture(brush->pPatch->GetShader());
147
148         width = brush->pPatch->getWidth();
149         height = brush->pPatch->getHeight();
150
151   for(int x = 0; x < height; x++)
152   {
153                 for(int y = 0; y < width; y++)
154     {
155       float *p = brush->pPatch->ctrlAt(ROW,x,y);
156       p[0] = points[x][y].xyz[0];
157       p[1] = points[x][y].xyz[1];
158       p[2] = points[x][y].xyz[2];
159       p[3] = points[x][y].st[0];
160       p[4] = points[x][y].st[1];
161     }
162   }
163 #endif
164 }
165
166 bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName)
167 {
168         if( !oldTextureName || !strcmp(texture, oldTextureName))
169         {
170                 strcpy(texture, newTextureName);
171                 return true;
172         }
173
174         return false;
175 }
176
177 void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], 
178                                   int startX, int startY, int number, bool horizontal, bool inverse)
179 {
180         int x = startX, y = startY, i, step;
181
182         if(inverse)
183                 step = -1;
184         else
185                 step = 1;
186
187         for(i = 0; i < number; i++)
188         {
189                 VectorCopy(points[x][y].xyz, array[i]);
190
191                 if(horizontal)
192                         x+=step;
193                 else
194                         y+=step;
195         }
196 }
197
198 void Print1dArray(vec3_t* array, int size)
199 {
200         for(int i = 0; i < size; i++)
201                 globalOutputStream() << "(" << array[i][0] << " " << array[i][1] << " " << array[i][2] << ")\t";
202         globalOutputStream() << "\n";
203 }
204
205 bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size)
206 {
207         int i;
208         bool equal = true;
209
210         for(i = 0; i < size; i++)
211         {
212                 if(!VectorCompare(a1[i], a2[size-i-1]))
213                 {
214                         equal = false;
215                         break;
216                 }
217         }
218         return equal;
219 }
220
221 patch_merge_t DPatch::IsMergable(DPatch *other)
222 {
223         int i, j;
224         vec3_t p1Array[4][MAX_PATCH_HEIGHT];
225         vec3_t p2Array[4][MAX_PATCH_HEIGHT];
226
227         int p1ArraySizes[4];
228         int p2ArraySizes[4];
229
230         patch_merge_t merge_info;
231
232         Build1dArray(p1Array[0], this->points, 0,                               0,                              this->width,    true,   false);
233         Build1dArray(p1Array[1], this->points, this->width-1,   0,                              this->height,   false,  false);
234         Build1dArray(p1Array[2], this->points, this->width-1,   this->height-1, this->width,    true,   true);
235         Build1dArray(p1Array[3], this->points, 0,                               this->height-1, this->height,   false,  true);
236
237         Build1dArray(p2Array[0], other->points, 0,                              0,                                      other->width,   true,   false);
238         Build1dArray(p2Array[1], other->points, other->width-1, 0,                                      other->height,  false,  false);
239         Build1dArray(p2Array[2], other->points, other->width-1, other->height-1,        other->width,   true,   true);
240         Build1dArray(p2Array[3], other->points, 0,                              other->height-1,        other->height,  false,  true);
241
242         p1ArraySizes[0] = this->width;
243         p1ArraySizes[1] = this->height;
244         p1ArraySizes[2] = this->width;
245         p1ArraySizes[3] = this->height;
246
247         p2ArraySizes[0] = other->width;
248         p2ArraySizes[1] = other->height;
249         p2ArraySizes[2] = other->width;
250         p2ArraySizes[3] = other->height;
251
252         for(i = 0; i < 4; i++)
253         {
254                 for(j = 0; j < 4; j++)
255                 {
256                         if(p1ArraySizes[i] == p2ArraySizes[j])
257                         {
258                                 if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i]))
259                                 {
260                                         merge_info.pos1 = i;
261                                         merge_info.pos2 = j;
262                                         merge_info.mergable = true;
263                                         return merge_info;
264                                 }
265                         }
266                 }
267         }
268         
269         merge_info.mergable = false;
270         return merge_info;
271 }
272
273 DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2)
274 {
275         while(merge_info.pos1 != 2)
276         {
277                 p1->Transpose();
278                 merge_info.pos1--;
279                 if(merge_info.pos1 < 0)
280                         merge_info.pos1 += 4;
281         }
282
283         while(merge_info.pos2 != 0)
284         {
285                 p2->Transpose();
286                 merge_info.pos2--;
287                 if(merge_info.pos2 < 0)
288                         merge_info.pos2 += 3;
289         }
290
291         int newHeight = p1->height + p2->height - 1;
292         if(newHeight > MAX_PATCH_HEIGHT)
293                 return NULL;
294
295         DPatch* newPatch = new DPatch();
296
297         newPatch->height        = newHeight;
298         newPatch->width         = p1->width;
299         newPatch->SetTexture(p1->texture);
300
301         int y = 0;
302         int i;
303         for(i = 0; i < p1->height; i++, y++)
304                 for(int x = 0; x < p1->width; x++)
305                         memcpy(&newPatch->points[x][y], &p1->points[x][i],      sizeof(drawVert_t));
306
307         for(i = 1; i < p2->height; i++, y++)
308                 for(int x = 0; x < p2->width; x++)
309                         memcpy(&newPatch->points[x][y], &p2->points[x][i],      sizeof(drawVert_t));
310
311 //      newPatch->Invert();
312
313         return newPatch;
314 }
315
316 void DPatch::Invert()
317 {
318         drawVert_t vertTemp;
319         int i, j;
320
321         for(i = 0 ; i < width ; i++ ) 
322         {
323                 for(j = 0; j < height / 2; j++)
324                 {
325                         memcpy(&vertTemp, &points[i][height - 1- j], sizeof (drawVert_t));
326                         memcpy(&points[i][height - 1 - j], &points[i][j], sizeof(drawVert_t));
327                         memcpy(&points[i][j], &vertTemp, sizeof(drawVert_t));
328                 }
329         }
330 }
331
332 void DPatch::Transpose()
333 {
334         int             i, j, w;
335         drawVert_t dv;
336
337         if ( width > height ) 
338         {
339                 for ( i = 0 ; i < height ; i++ ) 
340                 {
341                         for ( j = i + 1 ; j < width ; j++ ) 
342                         {
343                                 if ( j < height ) 
344                                 {
345                                         // swap the value
346                                         memcpy(&dv,                             &points[j][i],  sizeof(drawVert_t));
347                                         memcpy(&points[j][i],   &points[i][j],  sizeof(drawVert_t));
348                                         memcpy(&points[i][j],   &dv,                    sizeof(drawVert_t));
349                                 } 
350                                 else 
351                                 {
352                                 // just copy
353                                         memcpy(&points[i][j],   &points[j][i],  sizeof(drawVert_t));
354                         }
355                 }
356                  }
357         } 
358         else 
359         {
360                 for ( i = 0 ; i < width ; i++ ) 
361         {
362                         for ( j = i + 1 ; j < height ; j++ ) 
363                         {
364                         if ( j < width ) 
365                                 {
366                                         // swap the value
367                                         memcpy(&dv,                             &points[i][j],  sizeof(drawVert_t));
368                                         memcpy(&points[i][j],   &points[j][i],  sizeof(drawVert_t));
369                                 memcpy(&points[j][i],   &dv,                    sizeof(drawVert_t));
370                         } 
371                                 else 
372                                 {
373                                 // just copy
374                                         memcpy(&points[j][i],   &points[i][j],  sizeof(drawVert_t));
375                         }
376                 }
377         }
378     }
379
380         w = width;
381         width = height;
382         height = w;
383
384         Invert();
385 }
386
387 std::list<DPatch> DPatch::Split(bool rows, bool cols)
388 {
389         std::list<DPatch> patchList;
390         int i;
391         int x, y;
392
393         if(rows && height >= 5)
394         {
395                 for(i = 0; i < (height-1)/2; i++)
396                 {
397                         DPatch p;
398
399                         p.width = width;
400                         p.height = 3;
401                         p.SetTexture(texture);
402
403                         for(y = 0; y < 3; y++)
404                         {
405                                 for(x = 0; x < p.width; x++)
406                                 {
407                                         memcpy(&p.points[x][y], &points[x][(i*2)+y],    sizeof(drawVert_t));
408                                 }
409                         }
410                         patchList.push_back(p);
411                 }
412
413                 if(cols && width >= 5)
414                 {
415                         std::list<DPatch> patchList2;
416
417                         for(std::list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++)
418                         {
419                                 std::list<DPatch> patchList3 = (*patches).Split(false, true);
420                                 
421                                 for(std::list<DPatch>::iterator patches2 = patchList3.begin(); patches2 != patchList3.end(); patches2++)
422                                         patchList2.push_front(*patches2);
423                         }
424
425                         return patchList2;
426                 }
427         }
428         else if(cols && width >= 5)
429         {
430                 for(i = 0; i < (width-1)/2; i++)
431                 {
432                         DPatch p;
433
434                         p.height = height;
435                         p.width = 3;
436                         p.SetTexture(texture);
437
438                         for(x = 0; x < 3; x++)
439                         {
440                                 for(y = 0; y < p.height; y++)
441                                 {
442                                         memcpy(&p.points[x][y], &points[(i*2)+x][y],    sizeof(drawVert_t));
443                                 }
444                         }
445
446                         patchList.push_back(p);
447                 }
448         }
449
450         return patchList;
451 }