1c0ee385d184628b69d121148242d894e1371a39
[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 "StdAfx.h"
25
26 #include "gtkr_list.h"
27 #include "str.h"
28
29 //#include "DPoint.h"
30 //#include "DPlane.h"
31 //#include "DBrush.h"
32 //#include "DEPair.h"
33 #include "DPatch.h"
34 //#include "DEntity.h"
35
36 #include "misc.h"
37 #include "./dialogs/dialogs-gtk.h"
38
39 //////////////////////////////////////////////////////////////////////
40 // Construction/Destruction
41 //////////////////////////////////////////////////////////////////////
42
43 //              Added patch merging, wahey!
44
45 //
46 //              problem is, you cant put patches into entities as yet :(
47 //
48
49 DPatch::DPatch()
50 {
51         width = MIN_PATCH_WIDTH;
52         height = MIN_PATCH_HEIGHT;
53         QER_brush = NULL;
54 }
55
56 DPatch::~DPatch()
57 {
58
59 }
60
61 void DPatch::SetTexture(const char *textureName)
62 {
63         strcpy(texture, textureName);
64 }
65
66 void CopyDrawVert(const drawVert_t* in, drawVert_t* out)
67 {
68         out->lightmap[0] = in->lightmap[0];
69         out->lightmap[1] = in->lightmap[1];
70         out->st[0] = in->st[0];
71         out->st[1] = in->st[1];
72         VectorCopy(in->normal, out->normal);
73         VectorCopy(in->xyz, out->xyz);
74 }
75
76 void DPatch::BuildInRadiant(void* entity)
77 {
78 #if 0
79         int nIndex = g_FuncTable.m_pfnCreatePatchHandle();
80     //$ FIXME: m_pfnGetPatchHandle
81         patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex);
82
83   b->patchBrush = true;
84   b->pPatch = Patch_Alloc();
85         b->pPatch->setDims(width,height);
86
87         for(int x = 0; x < height; x++)
88   {
89                 for(int y = 0; y < width; y++)
90     {
91       float *p = b->pPatch->ctrlAt(ROW,x,y);
92       p[0] = points[x][y].xyz[0];
93       p[1] = points[x][y].xyz[1];
94       p[2] = points[x][y].xyz[2];
95       p[3] = points[x][y].st[0];
96       p[4] = points[x][y].st[1];
97     }
98   }
99
100         if(entity)
101                 g_FuncTable.m_pfnCommitBrushHandleToEntity(QER_brush, entity);
102         else
103                 g_FuncTable.m_pfnCommitBrushHandle(QER_brush);
104
105         for(int x = 0; x < width; x++)
106                 for(int y = 0; y < height; y++)
107                         CopyDrawVert(&points[x][y], &pm->ctrl[x][y]);
108
109         QER_patch = pm;
110
111 /*      if(entity)
112         {
113 //              strcpy(pm->d_texture->name, texture);
114
115                 brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();
116                 brush->patchBrush = TRUE;
117                 brush->pPatch = pm;             
118
119                 pm->pSymbiot = brush;
120                 pm->bSelected = false;
121                 pm->bOverlay = false;   // bleh, f*cks up, just have to wait for a proper function
122                 pm->bDirty = true;              // or get my own patch out....
123                 pm->nListID = -1;
124
125                 g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity);
126         }
127         else*/  // patch to entity just plain dont work atm
128
129   if(entity)
130     g_FuncTable.m_pfnCommitPatchHandleToEntity(nIndex, pm, texture, entity);
131   else
132                 g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, texture);
133
134         QER_brush = pm->pSymbiot;
135 #endif
136 }
137
138 void DPatch::LoadFromBrush(scene::Node* brush)
139 {
140         QER_brush = brush;
141
142 #if 0
143         SetTexture(brush->pPatch->GetShader());
144
145         width = brush->pPatch->getWidth();
146         height = brush->pPatch->getHeight();
147
148   for(int x = 0; x < height; x++)
149   {
150                 for(int y = 0; y < width; y++)
151     {
152       float *p = brush->pPatch->ctrlAt(ROW,x,y);
153       p[0] = points[x][y].xyz[0];
154       p[1] = points[x][y].xyz[1];
155       p[2] = points[x][y].xyz[2];
156       p[3] = points[x][y].st[0];
157       p[4] = points[x][y].st[1];
158     }
159   }
160 #endif
161 }
162
163 void DPatch::RemoveFromRadiant()
164 {
165         if(QER_brush)
166   {
167 #if 0
168                 g_FuncTable.m_pfnDeleteBrushHandle(QER_brush);
169 #endif
170   }
171 }
172
173 bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName)
174 {
175         if( !oldTextureName || !strcmp(texture, oldTextureName))
176         {
177                 strcpy(texture, newTextureName);
178                 return TRUE;
179         }
180
181         return FALSE;
182 }
183
184 void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], 
185                                   int startX, int startY, int number, bool horizontal, bool inverse)
186 {
187         int x = startX, y = startY, i, step;
188
189         if(inverse)
190                 step = -1;
191         else
192                 step = 1;
193
194         for(i = 0; i < number; i++)
195         {
196                 VectorCopy(points[x][y].xyz, array[i]);
197
198                 if(horizontal)
199                         x+=step;
200                 else
201                         y+=step;
202         }
203 }
204
205 void Print1dArray(vec3_t* array, int size)
206 {
207         for(int i = 0; i < size; i++)
208                 Sys_Printf("(%.0f %.0f %.0f)\t", array[i][0], array[i][1], array[i][2]);
209         Sys_Printf("\n");
210 }
211
212 bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size)
213 {
214         int i;
215         bool equal = true;
216
217         for(i = 0; i < size; i++)
218         {
219                 if(!VectorCompare(a1[i], a2[size-i-1]))
220                 {
221                         equal = false;
222                         break;
223                 }
224         }
225         return equal;
226 }
227
228 patch_merge_t DPatch::IsMergable(DPatch *other)
229 {
230         int i, j;
231         vec3_t p1Array[4][MAX_PATCH_HEIGHT];
232         vec3_t p2Array[4][MAX_PATCH_HEIGHT];
233
234         int p1ArraySizes[4];
235         int p2ArraySizes[4];
236
237         patch_merge_t merge_info;
238
239         Build1dArray(p1Array[0], this->points, 0,                               0,                              this->width,    true,   false);
240         Build1dArray(p1Array[1], this->points, this->width-1,   0,                              this->height,   false,  false);
241         Build1dArray(p1Array[2], this->points, this->width-1,   this->height-1, this->width,    true,   true);
242         Build1dArray(p1Array[3], this->points, 0,                               this->height-1, this->height,   false,  true);
243
244         Build1dArray(p2Array[0], other->points, 0,                              0,                                      other->width,   true,   false);
245         Build1dArray(p2Array[1], other->points, other->width-1, 0,                                      other->height,  false,  false);
246         Build1dArray(p2Array[2], other->points, other->width-1, other->height-1,        other->width,   true,   true);
247         Build1dArray(p2Array[3], other->points, 0,                              other->height-1,        other->height,  false,  true);
248
249         p1ArraySizes[0] = this->width;
250         p1ArraySizes[1] = this->height;
251         p1ArraySizes[2] = this->width;
252         p1ArraySizes[3] = this->height;
253
254         p2ArraySizes[0] = other->width;
255         p2ArraySizes[1] = other->height;
256         p2ArraySizes[2] = other->width;
257         p2ArraySizes[3] = other->height;
258
259         for(i = 0; i < 4; i++)
260         {
261                 for(j = 0; j < 4; j++)
262                 {
263                         if(p1ArraySizes[i] == p2ArraySizes[j])
264                         {
265                                 if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i]))
266                                 {
267                                         merge_info.pos1 = i;
268                                         merge_info.pos2 = j;
269                                         merge_info.mergable = true;
270                                         return merge_info;
271                                 }
272                         }
273                 }
274         }
275         
276         merge_info.mergable = false;
277         return merge_info;
278 }
279
280 DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2)
281 {
282         while(merge_info.pos1 != 2)
283         {
284                 p1->Transpose();
285                 merge_info.pos1--;
286                 if(merge_info.pos1 < 0)
287                         merge_info.pos1 += 4;
288         }
289
290         while(merge_info.pos2 != 0)
291         {
292                 p2->Transpose();
293                 merge_info.pos2--;
294                 if(merge_info.pos2 < 0)
295                         merge_info.pos2 += 3;
296         }
297
298         int newHeight = p1->height + p2->height - 1;
299         if(newHeight > MAX_PATCH_HEIGHT)
300                 return NULL;
301
302         DPatch* newPatch = new DPatch();
303
304         newPatch->height        = newHeight;
305         newPatch->width         = p1->width;
306         newPatch->SetTexture(p1->texture);
307
308         int y = 0;
309         int i;
310         for(i = 0; i < p1->height; i++, y++)
311                 for(int x = 0; x < p1->width; x++)
312                         memcpy(&newPatch->points[x][y], &p1->points[x][i],      sizeof(drawVert_t));
313
314         for(i = 1; i < p2->height; i++, y++)
315                 for(int x = 0; x < p2->width; x++)
316                         memcpy(&newPatch->points[x][y], &p2->points[x][i],      sizeof(drawVert_t));
317
318 //      newPatch->Invert();
319
320         return newPatch;
321 }
322
323 void DPatch::Invert()
324 {
325         drawVert_t vertTemp;
326         int i, j;
327
328         for(i = 0 ; i < width ; i++ ) 
329         {
330                 for(j = 0; j < height / 2; j++)
331                 {
332                         memcpy(&vertTemp, &points[i][height - 1- j], sizeof (drawVert_t));
333                         memcpy(&points[i][height - 1 - j], &points[i][j], sizeof(drawVert_t));
334                         memcpy(&points[i][j], &vertTemp, sizeof(drawVert_t));
335                 }
336         }
337 }
338
339 void DPatch::Transpose()
340 {
341         int             i, j, w;
342         drawVert_t dv;
343
344         if ( width > height ) 
345         {
346                 for ( i = 0 ; i < height ; i++ ) 
347                 {
348                         for ( j = i + 1 ; j < width ; j++ ) 
349                         {
350                                 if ( j < height ) 
351                                 {
352                                         // swap the value
353                                         memcpy(&dv,                             &points[j][i],  sizeof(drawVert_t));
354                                         memcpy(&points[j][i],   &points[i][j],  sizeof(drawVert_t));
355                                         memcpy(&points[i][j],   &dv,                    sizeof(drawVert_t));
356                                 } 
357                                 else 
358                                 {
359                                 // just copy
360                                         memcpy(&points[i][j],   &points[j][i],  sizeof(drawVert_t));
361                         }
362                 }
363                  }
364         } 
365         else 
366         {
367                 for ( i = 0 ; i < width ; i++ ) 
368         {
369                         for ( j = i + 1 ; j < height ; j++ ) 
370                         {
371                         if ( j < width ) 
372                                 {
373                                         // swap the value
374                                         memcpy(&dv,                             &points[i][j],  sizeof(drawVert_t));
375                                         memcpy(&points[i][j],   &points[j][i],  sizeof(drawVert_t));
376                                 memcpy(&points[j][i],   &dv,                    sizeof(drawVert_t));
377                         } 
378                                 else 
379                                 {
380                                 // just copy
381                                         memcpy(&points[j][i],   &points[i][j],  sizeof(drawVert_t));
382                         }
383                 }
384         }
385     }
386
387         w = width;
388         width = height;
389         height = w;
390
391         Invert();
392 }
393
394 list<DPatch> DPatch::Split(bool rows, bool cols)
395 {
396         list<DPatch> patchList;
397         int i;
398         int x, y;
399
400         if(rows && height >= 5)
401         {
402                 for(i = 0; i < (height-1)/2; i++)
403                 {
404                         DPatch p;
405
406                         p.width = width;
407                         p.height = 3;
408                         p.SetTexture(texture);
409
410                         for(y = 0; y < 3; y++)
411                         {
412                                 for(x = 0; x < p.width; x++)
413                                 {
414                                         memcpy(&p.points[x][y], &points[x][(i*2)+y],    sizeof(drawVert_t));
415                                 }
416                         }
417                         patchList.push_back(p);
418                 }
419
420                 if(cols && width >= 5)
421                 {
422                         list<DPatch> patchList2;
423
424                         for(list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++)
425                         {
426                                 list<DPatch> patchList3 = (*patches).Split(false, true);
427                                 
428                                 for(list<DPatch>::iterator patches2 = patchList3.begin(); patches2 != patchList3.end(); patches2++)
429                                         patchList2.push_front(*patches2);
430                         }
431
432                         return patchList2;
433                 }
434         }
435         else if(cols && width >= 5)
436         {
437                 for(i = 0; i < (width-1)/2; i++)
438                 {
439                         DPatch p;
440
441                         p.height = height;
442                         p.width = 3;
443                         p.SetTexture(texture);
444
445                         for(x = 0; x < 3; x++)
446                         {
447                                 for(y = 0; y < p.height; y++)
448                                 {
449                                         memcpy(&p.points[x][y], &points[(i*2)+x][y],    sizeof(drawVert_t));
450                                 }
451                         }
452
453                         patchList.push_back(p);
454                 }
455         }
456
457         return patchList;
458 }