fixed warnings
[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 < height; x++)
84   {
85                 for(int y = 0; y < width; y++)
86     {
87       PatchControl& p = matrix(y, x);
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 < height; x++)
152   {
153                 for(int y = 0; y < width; y++)
154     {
155       PatchControl& p = matrix(y, x);
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 NULL;
314
315         DPatch* newPatch = new DPatch();
316
317         newPatch->height        = newHeight;
318         newPatch->width         = p1->width;
319         newPatch->SetTexture(p1->texture);
320
321         int y = 0;
322         int i;
323         for(i = 0; i < p1->height; i++, y++)
324                 for(int x = 0; x < p1->width; x++)
325                         newPatch->points[x][y] = p1->points[x][i];
326
327         for(i = 1; i < p2->height; i++, y++)
328                 for(int x = 0; x < p2->width; x++)
329                         newPatch->points[x][y] = p2->points[x][i];
330
331 //      newPatch->Invert();
332
333         return newPatch;
334 }
335
336 void DPatch::Invert()
337 {
338         int i, j;
339
340         for(i = 0 ; i < width ; i++ ) 
341         {
342                 for(j = 0; j < height / 2; j++)
343                 {
344       std::swap(points[i][height - 1- j], points[i][j]);
345                 }
346         }
347 }
348
349 void DPatch::Transpose()
350 {
351         int             i, j, w;
352
353         if ( width > height ) 
354         {
355                 for ( i = 0 ; i < height ; i++ ) 
356                 {
357                         for ( j = i + 1 ; j < width ; j++ ) 
358                         {
359                                 if ( j < height ) 
360                                 {
361                                         // swap the value
362           std::swap(points[j][i], points[i][j]);
363                                 } 
364                                 else 
365                                 {
366                                 // just copy
367                                         points[i][j] = points[j][i];
368                         }
369                 }
370                  }
371         } 
372         else 
373         {
374                 for ( i = 0 ; i < width ; i++ ) 
375         {
376                         for ( j = i + 1 ; j < height ; j++ ) 
377                         {
378                         if ( j < width ) 
379                                 {
380                                         // swap the value
381           std::swap(points[i][j], points[j][i]);
382                         } 
383                                 else 
384                                 {
385                                 // just copy
386                                         points[j][i] = points[i][j];
387                         }
388                 }
389         }
390     }
391
392         w = width;
393         width = height;
394         height = w;
395
396         Invert();
397 }
398
399 std::list<DPatch> DPatch::Split(bool rows, bool cols)
400 {
401         std::list<DPatch> patchList;
402         int i;
403         int x, y;
404
405         if(rows && height >= 5)
406         {
407                 for(i = 0; i < (height-1)/2; i++)
408                 {
409                         DPatch p;
410
411                         p.width = width;
412                         p.height = 3;
413                         p.SetTexture(texture);
414
415                         for(y = 0; y < 3; y++)
416                         {
417                                 for(x = 0; x < p.width; x++)
418                                 {
419                                         p.points[x][y] = points[x][(i*2)+y];
420                                 }
421                         }
422                         patchList.push_back(p);
423                 }
424
425                 if(cols && width >= 5)
426                 {
427                         std::list<DPatch> patchList2;
428
429                         for(std::list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++)
430                         {
431                                 std::list<DPatch> patchList3 = (*patches).Split(false, true);
432                                 
433                                 for(std::list<DPatch>::iterator patches2 = patchList3.begin(); patches2 != patchList3.end(); patches2++)
434                                         patchList2.push_front(*patches2);
435                         }
436
437                         return patchList2;
438                 }
439         }
440         else if(cols && width >= 5)
441         {
442                 for(i = 0; i < (width-1)/2; i++)
443                 {
444                         DPatch p;
445
446                         p.height = height;
447                         p.width = 3;
448                         p.SetTexture(texture);
449
450                         for(x = 0; x < 3; x++)
451                         {
452                                 for(y = 0; y < p.height; y++)
453                                 {
454                                         p.points[x][y] = points[(i*2)+x][y];
455                                 }
456                         }
457
458                         patchList.push_back(p);
459                 }
460         }
461
462         return patchList;
463 }