]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/bobtoolz/DPatch.cpp
reformat code! now the code is only ugly on the *inside*
[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         for (int y = 0; y < height; y++) {
85             PatchControl &p = matrix(x, y);
86             p.m_vertex[0] = points[x][y].xyz[0];
87             p.m_vertex[1] = points[x][y].xyz[1];
88             p.m_vertex[2] = points[x][y].xyz[2];
89             p.m_texcoord[0] = points[x][y].st[0];
90             p.m_texcoord[1] = points[x][y].st[1];
91         }
92     }
93     GlobalPatchCreator().Patch_controlPointsChanged(patch);
94
95     QER_entity = entity;
96     QER_brush = patch.get_pointer();
97
98
99 #if 0
100     int nIndex = g_FuncTable.m_pfnCreatePatchHandle();
101     //$ FIXME: m_pfnGetPatchHandle
102     patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData( nIndex );
103
104     b->patchBrush = true;
105     b->pPatch = Patch_Alloc();
106     b->pPatch->setDims( width,height );
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 /*      if(entity)
113     {
114    //           strcpy(pm->d_texture->name, texture);
115
116         brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();
117         brush->patchBrush = true;
118         brush->pPatch = pm;
119
120         pm->pSymbiot = brush;
121         pm->bSelected = false;
122         pm->bOverlay = false;   // bleh, f*cks up, just have to wait for a proper function
123         pm->bDirty = true;              // or get my own patch out....
124         pm->nListID = -1;
125
126         g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity);
127     }
128     else*/                                                                                                                                                                                                                                                                                                                                                                                                                                                                // patch to entity just plain dont work atm
129
130     if ( entity ) {
131         g_FuncTable.m_pfnCommitPatchHandleToEntity( nIndex, pm, texture, entity );
132     }
133     else{
134         g_FuncTable.m_pfnCommitPatchHandleToMap( nIndex, pm, texture );
135     }
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         for (int y = 0; y < height; y++) {
153             PatchControl &p = matrix(x, y);
154             points[x][y].xyz[0] = p.m_vertex[0];
155             points[x][y].xyz[1] = p.m_vertex[1];
156             points[x][y].xyz[2] = p.m_vertex[2];
157             points[x][y].st[0] = p.m_texcoord[0];
158             points[x][y].st[1] = p.m_texcoord[1];
159         }
160     }
161     SetTexture(GlobalPatchCreator().Patch_getShader(patch.path().top()));
162
163 #if 0
164     SetTexture( brush->pPatch->GetShader() );
165
166     width = brush->pPatch->getWidth();
167     height = brush->pPatch->getHeight();
168
169     for ( int x = 0; x < height; x++ )
170     {
171         for ( int y = 0; y < width; y++ )
172         {
173             float *p = brush->pPatch->ctrlAt( ROW,x,y );
174             p[0] = points[x][y].xyz[0];
175             p[1] = points[x][y].xyz[1];
176             p[2] = points[x][y].xyz[2];
177             p[3] = points[x][y].st[0];
178             p[4] = points[x][y].st[1];
179         }
180     }
181 #endif
182 }
183
184 bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName)
185 {
186     if (!oldTextureName || !strcmp(texture, oldTextureName)) {
187         strcpy(texture, newTextureName);
188         return true;
189     }
190
191     return false;
192 }
193
194 void Build1dArray(vec3_t *array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT],
195                   int startX, int startY, int number, bool horizontal, bool inverse)
196 {
197     int x = startX, y = startY, i, step;
198
199     if (inverse) {
200         step = -1;
201     } else {
202         step = 1;
203     }
204
205     for (i = 0; i < number; i++) {
206         VectorCopy(points[x][y].xyz, array[i]);
207
208         if (horizontal) {
209             x += step;
210         } else {
211             y += step;
212         }
213     }
214 }
215
216 void Print1dArray(vec3_t *array, int size)
217 {
218     for (int i = 0; i < size; i++) {
219         globalOutputStream() << "(" << array[i][0] << " " << array[i][1] << " " << array[i][2] << ")\t";
220     }
221     globalOutputStream() << "\n";
222 }
223
224 bool Compare1dArrays(vec3_t *a1, vec3_t *a2, int size)
225 {
226     int i;
227     bool equal = true;
228
229     for (i = 0; i < size; i++) {
230         if (!VectorCompare(a1[i], a2[size - i - 1])) {
231             equal = false;
232             break;
233         }
234     }
235     return equal;
236 }
237
238 patch_merge_t DPatch::IsMergable(DPatch *other)
239 {
240     int i, j;
241     vec3_t p1Array[4][MAX_PATCH_HEIGHT];
242     vec3_t p2Array[4][MAX_PATCH_HEIGHT];
243
244     int p1ArraySizes[4];
245     int p2ArraySizes[4];
246
247     patch_merge_t merge_info;
248
249     Build1dArray(p1Array[0], this->points, 0, 0, this->width, true, false);
250     Build1dArray(p1Array[1], this->points, this->width - 1, 0, this->height, false, false);
251     Build1dArray(p1Array[2], this->points, this->width - 1, this->height - 1, this->width, true, true);
252     Build1dArray(p1Array[3], this->points, 0, this->height - 1, this->height, false, true);
253
254     Build1dArray(p2Array[0], other->points, 0, 0, other->width, true, false);
255     Build1dArray(p2Array[1], other->points, other->width - 1, 0, other->height, false, false);
256     Build1dArray(p2Array[2], other->points, other->width - 1, other->height - 1, other->width, true, true);
257     Build1dArray(p2Array[3], other->points, 0, other->height - 1, other->height, false, true);
258
259     p1ArraySizes[0] = this->width;
260     p1ArraySizes[1] = this->height;
261     p1ArraySizes[2] = this->width;
262     p1ArraySizes[3] = this->height;
263
264     p2ArraySizes[0] = other->width;
265     p2ArraySizes[1] = other->height;
266     p2ArraySizes[2] = other->width;
267     p2ArraySizes[3] = other->height;
268
269     for (i = 0; i < 4; i++) {
270         for (j = 0; j < 4; j++) {
271             if (p1ArraySizes[i] == p2ArraySizes[j]) {
272                 if (Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i])) {
273                     merge_info.pos1 = i;
274                     merge_info.pos2 = j;
275                     merge_info.mergable = true;
276                     return merge_info;
277                 }
278             }
279         }
280     }
281
282     merge_info.mergable = false;
283     return merge_info;
284 }
285
286 DPatch *DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2)
287 {
288     while (merge_info.pos1 != 2) {
289         p1->Transpose();
290         merge_info.pos1--;
291         if (merge_info.pos1 < 0) {
292             merge_info.pos1 += 4;
293         }
294     }
295
296     while (merge_info.pos2 != 0) {
297         p2->Transpose();
298         merge_info.pos2--;
299         if (merge_info.pos2 < 0) {
300             merge_info.pos2 += 3;
301         }
302     }
303
304     int newHeight = p1->height + p2->height - 1;
305     if (newHeight > MAX_PATCH_HEIGHT) {
306         return NULL;
307     }
308
309     DPatch *newPatch = new DPatch();
310
311     newPatch->height = newHeight;
312     newPatch->width = p1->width;
313     newPatch->SetTexture(p1->texture);
314
315     for (int y = 0; y < p1->height; y++) {
316         for (int x = 0; x < p1->width; x++) {
317             newPatch->points[x][y] = p1->points[x][y];
318         }
319     }
320
321     for (int y = 1; y < p2->height; y++) {
322         for (int x = 0; x < p2->width; x++) {
323             newPatch->points[x][(y + p1->height - 1)] = p2->points[x][y];
324         }
325     }
326
327 //      newPatch->Invert();
328     return newPatch;
329 }
330
331 void DPatch::Invert()
332 {
333     int i, j;
334
335     for (i = 0; i < width; i++) {
336         for (j = 0; j < height / 2; j++) {
337             std::swap(points[i][height - 1 - j], points[i][j]);
338         }
339     }
340 }
341
342 /*
343    //Was used for debugging, obsolete function
344    DPatch* DPatch::TransposePatch(DPatch *p1)
345    {
346     globalOutputStream() << "Source patch ";
347     p1->DebugPrint();
348     p1->Transpose();
349     globalOutputStream() << "Transposed";
350     p1->DebugPrint();
351
352     DPatch* newPatch = new DPatch();
353     newPatch->height    = p1->height;
354     newPatch->width             = p1->width;
355     newPatch->SetTexture(p1->texture);
356
357     for(int x = 0; x < p1->height; x++)
358     {
359         for(int y = 0; y < p1->width; y++)
360         {
361             newPatch->points[x][y] = p1->points[x][y];
362         }
363     }
364     return newPatch;
365    }
366
367    //Function to figure out what is actually going wrong.
368    void DPatch::DebugPrint()
369    {
370     globalOutputStream() << "width: " << width << "\theight: " << height << "\n";
371     for(int x = 0; x < height; x++)
372     {
373         for(int y = 0; y < width; y++)
374         {
375             globalOutputStream() << "\t(" << points[x][y].xyz[0] << " " << points[x][y].xyz[1] << " " << points[x][y].xyz[2] << ")\t";
376         }
377         globalOutputStream() << "\n";
378     }
379    }
380  */
381
382 void DPatch::Transpose()
383 {
384     int i, j, w;
385
386     if (width > height) {
387         for (i = 0; i < height; i++) {
388             for (j = i + 1; j < width; j++) {
389                 if (j < height) {
390                     // swap the value
391                     std::swap(points[j][i], points[i][j]);
392                 } else {
393                     // just copy
394                     points[i][j] = points[j][i];
395                 }
396             }
397         }
398     } else {
399         for (i = 0; i < width; i++) {
400             for (j = i + 1; j < height; j++) {
401                 if (j < width) {
402                     // swap the value
403                     std::swap(points[i][j], points[j][i]);
404                 } else {
405                     // just copy
406                     points[j][i] = points[i][j];
407                 }
408             }
409         }
410     }
411
412     w = width;
413     width = height;
414     height = w;
415
416     Invert();
417 }
418
419 std::list<DPatch> DPatch::SplitCols()
420 {
421     std::list<DPatch> patchList;
422     int i;
423     int x, y;
424
425     if (height >= 5) {
426         for (i = 0; i < (height - 1) / 2; i++) {
427             DPatch p;
428
429             p.width = width;
430             p.height = MIN_PATCH_HEIGHT;
431             p.SetTexture(texture);
432             for (x = 0; x < p.width; x++) {
433                 for (y = 0; y < MIN_PATCH_HEIGHT; y++) {
434                     p.points[x][y] = points[x][(i * 2) + y];
435                 }
436             }
437             patchList.push_back(p);
438         }
439     } else {
440         //globalErrorStream() << "bobToolz SplitPatchRows: Patch has not enough rows for splitting.\n";
441         patchList.push_back(*this);
442     }
443     return patchList;
444 }
445
446 std::list<DPatch> DPatch::SplitRows()
447 {
448     std::list<DPatch> patchList;
449     int i;
450     int x, y;
451
452     if (width >= 5) {
453         for (i = 0; i < (width - 1) / 2; i++) {
454             DPatch p;
455
456             p.width = MIN_PATCH_WIDTH;
457             p.height = height;
458             p.SetTexture(texture);
459
460             for (x = 0; x < MIN_PATCH_WIDTH; x++) {
461                 for (y = 0; y < p.height; y++) {
462                     p.points[x][y] = points[(i * 2) + x][y];
463                 }
464             }
465             patchList.push_back(p);
466         }
467     } else {
468         patchList.push_back(*this);
469     }
470     return patchList;
471 }
472
473 std::list<DPatch> DPatch::Split()
474 {
475     std::list<DPatch> patchList;
476     int i;
477     int x, y;
478
479     if (width >= 5) {
480         std::list<DPatch> patchColList = SplitCols();
481         for (std::list<DPatch>::iterator patchesCol = patchColList.begin();
482              patchesCol != patchColList.end(); patchesCol++) {
483             std::list<DPatch> patchRowList = (*patchesCol).SplitRows();
484             for (std::list<DPatch>::iterator patchesRow = patchRowList.begin();
485                  patchesRow != patchRowList.end(); patchesRow++) {
486                 patchList.push_front(*patchesRow);
487             }
488         }
489     } else if (height >= 5) {
490         std::list<DPatch> patchRowList = SplitRows();
491         for (std::list<DPatch>::iterator patchesRow = patchRowList.begin();
492              patchesRow != patchRowList.end(); patchesRow++) {
493             patchList.push_front(*patchesRow);
494         }
495     } else {
496         //globalErrorStream() << "bobToolz SplitPatchRows: Patch has not enough rows for splitting.\n";
497         patchList.push_back(*this);
498     }
499     return patchList;
500 }