161420f368a6e8a5ae17b9c7451dd607c127e408
[xonotic/netradiant.git] / contrib / bobtoolz / DPatch.cpp
1 /*\r
2 BobToolz plugin for GtkRadiant\r
3 Copyright (C) 2001 Gordon Biggans\r
4 \r
5 This library is free software; you can redistribute it and/or\r
6 modify it under the terms of the GNU Lesser General Public\r
7 License as published by the Free Software Foundation; either\r
8 version 2.1 of the License, or (at your option) any later version.\r
9 \r
10 This library is distributed in the hope that it will be useful,\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
13 Lesser General Public License for more details.\r
14 \r
15 You should have received a copy of the GNU Lesser General Public\r
16 License along with this library; if not, write to the Free Software\r
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
18 */\r
19 \r
20 // DPatch.cpp: implementation of the DPatch class.\r
21 //\r
22 //////////////////////////////////////////////////////////////////////\r
23 \r
24 #include "StdAfx.h"\r
25 #include "DPatch.h"\r
26 #include "misc.h"\r
27 #include "./dialogs/dialogs-gtk.h"\r
28 \r
29 //////////////////////////////////////////////////////////////////////\r
30 // Construction/Destruction\r
31 //////////////////////////////////////////////////////////////////////\r
32 \r
33 //              Added patch merging, wahey!\r
34 \r
35 //\r
36 //              problem is, you cant put patches into entities as yet :(\r
37 //\r
38 \r
39 DPatch::DPatch()\r
40 {\r
41         width = MIN_PATCH_WIDTH;\r
42         height = MIN_PATCH_HEIGHT;\r
43         QER_patch = NULL;\r
44         QER_brush = NULL;\r
45 }\r
46 \r
47 DPatch::~DPatch()\r
48 {\r
49 \r
50 }\r
51 \r
52 void DPatch::SetTexture(const char *textureName)\r
53 {\r
54         strcpy(texture, textureName);\r
55 }\r
56 \r
57 void CopyDrawVert(const drawVert_t* in, drawVert_t* out)\r
58 {\r
59         out->lightmap[0] = in->lightmap[0];\r
60         out->lightmap[1] = in->lightmap[1];\r
61         out->st[0] = in->st[0];\r
62         out->st[1] = in->st[1];\r
63         VectorCopy(in->normal, out->normal);\r
64         VectorCopy(in->xyz, out->xyz);\r
65 }\r
66 \r
67 void DPatch::BuildInRadiant(void* entity)\r
68 {\r
69         int nIndex = g_FuncTable.m_pfnCreatePatchHandle();\r
70     //$ FIXME: m_pfnGetPatchHandle\r
71         patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex);\r
72 \r
73         pm->height = height;\r
74         pm->width = width;\r
75 \r
76         for(int x = 0; x < width; x++)\r
77                 for(int y = 0; y < height; y++)\r
78                         CopyDrawVert(&points[x][y], &pm->ctrl[x][y]);\r
79 \r
80         QER_patch = pm;\r
81 \r
82 /*      if(entity)\r
83         {\r
84 //              strcpy(pm->d_texture->name, texture);\r
85 \r
86                 brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();\r
87                 brush->patchBrush = TRUE;\r
88                 brush->pPatch = pm;             \r
89 \r
90                 pm->pSymbiot = brush;\r
91                 pm->bSelected = false;\r
92                 pm->bOverlay = false;   // bleh, f*cks up, just have to wait for a proper function\r
93                 pm->bDirty = true;              // or get my own patch out....\r
94                 pm->nListID = -1;\r
95 \r
96                 g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity);\r
97         }\r
98         else*/  // patch to entity just plain dont work atm\r
99 \r
100   if(entity)\r
101     g_FuncTable.m_pfnCommitPatchHandleToEntity(nIndex, pm, texture, entity);\r
102   else\r
103                 g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, texture);\r
104 \r
105         QER_brush = pm->pSymbiot;\r
106 }\r
107 \r
108 void DPatch::LoadFromBrush_t(brush_t* brush)\r
109 {\r
110         QER_brush = brush;\r
111         QER_patch = brush->pPatch;\r
112 \r
113         SetTexture(QER_patch->pShader->getName());\r
114 \r
115         for(int x = 0; x < QER_patch->width; x++)\r
116                 for(int y = 0; y < QER_patch->height; y++)\r
117                         CopyDrawVert(&QER_patch->ctrl[x][y], &points[x][y]);\r
118 \r
119         width = QER_patch->width;\r
120         height = QER_patch->height;\r
121 }\r
122 \r
123 void DPatch::RemoveFromRadiant()\r
124 {\r
125         if(QER_brush)\r
126                 g_FuncTable.m_pfnDeleteBrushHandle(QER_brush);\r
127 }\r
128 \r
129 bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName)\r
130 {\r
131         if( !oldTextureName || !strcmp(texture, oldTextureName))\r
132         {\r
133                 strcpy(texture, newTextureName);\r
134                 return TRUE;\r
135         }\r
136 \r
137         return FALSE;\r
138 }\r
139 \r
140 void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], \r
141                                   int startX, int startY, int number, bool horizontal, bool inverse)\r
142 {\r
143         int x = startX, y = startY, i, step;\r
144 \r
145         if(inverse)\r
146                 step = -1;\r
147         else\r
148                 step = 1;\r
149 \r
150         for(i = 0; i < number; i++)\r
151         {\r
152                 VectorCopy(points[x][y].xyz, array[i]);\r
153 \r
154                 if(horizontal)\r
155                         x+=step;\r
156                 else\r
157                         y+=step;\r
158         }\r
159 }\r
160 \r
161 void Print1dArray(vec3_t* array, int size)\r
162 {\r
163         for(int i = 0; i < size; i++)\r
164                 Sys_Printf("(%.0f %.0f %.0f)\t", array[i][0], array[i][1], array[i][2]);\r
165         Sys_Printf("\n");\r
166 }\r
167 \r
168 bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size)\r
169 {\r
170         int i;\r
171         bool equal = true;\r
172 \r
173         for(i = 0; i < size; i++)\r
174         {\r
175                 if(!VectorCompare(a1[i], a2[size-i-1]))\r
176                 {\r
177                         equal = false;\r
178                         break;\r
179                 }\r
180         }\r
181         return equal;\r
182 }\r
183 \r
184 patch_merge_t DPatch::IsMergable(DPatch *other)\r
185 {\r
186         int i, j;\r
187         vec3_t p1Array[4][MAX_PATCH_HEIGHT];\r
188         vec3_t p2Array[4][MAX_PATCH_HEIGHT];\r
189 \r
190         int p1ArraySizes[4];\r
191         int p2ArraySizes[4];\r
192 \r
193         patch_merge_t merge_info;\r
194 \r
195         Build1dArray(p1Array[0], this->points, 0,                               0,                              this->width,    true,   false);\r
196         Build1dArray(p1Array[1], this->points, this->width-1,   0,                              this->height,   false,  false);\r
197         Build1dArray(p1Array[2], this->points, this->width-1,   this->height-1, this->width,    true,   true);\r
198         Build1dArray(p1Array[3], this->points, 0,                               this->height-1, this->height,   false,  true);\r
199 \r
200         Build1dArray(p2Array[0], other->points, 0,                              0,                                      other->width,   true,   false);\r
201         Build1dArray(p2Array[1], other->points, other->width-1, 0,                                      other->height,  false,  false);\r
202         Build1dArray(p2Array[2], other->points, other->width-1, other->height-1,        other->width,   true,   true);\r
203         Build1dArray(p2Array[3], other->points, 0,                              other->height-1,        other->height,  false,  true);\r
204 \r
205         p1ArraySizes[0] = this->width;\r
206         p1ArraySizes[1] = this->height;\r
207         p1ArraySizes[2] = this->width;\r
208         p1ArraySizes[3] = this->height;\r
209 \r
210         p2ArraySizes[0] = other->width;\r
211         p2ArraySizes[1] = other->height;\r
212         p2ArraySizes[2] = other->width;\r
213         p2ArraySizes[3] = other->height;\r
214 \r
215         for(i = 0; i < 4; i++)\r
216         {\r
217                 for(j = 0; j < 4; j++)\r
218                 {\r
219                         if(p1ArraySizes[i] == p2ArraySizes[j])\r
220                         {\r
221                                 if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i]))\r
222                                 {\r
223                                         merge_info.pos1 = i;\r
224                                         merge_info.pos2 = j;\r
225                                         merge_info.mergable = true;\r
226                                         return merge_info;\r
227                                 }\r
228                         }\r
229                 }\r
230         }\r
231         \r
232         merge_info.mergable = false;\r
233         return merge_info;\r
234 }\r
235 \r
236 DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2)\r
237 {\r
238         while(merge_info.pos1 != 2)\r
239         {\r
240                 p1->Transpose();\r
241                 merge_info.pos1--;\r
242                 if(merge_info.pos1 < 0)\r
243                         merge_info.pos1 += 4;\r
244         }\r
245 \r
246         while(merge_info.pos2 != 0)\r
247         {\r
248                 p2->Transpose();\r
249                 merge_info.pos2--;\r
250                 if(merge_info.pos2 < 0)\r
251                         merge_info.pos2 += 3;\r
252         }\r
253 \r
254         int newHeight = p1->height + p2->height - 1;\r
255         if(newHeight > MAX_PATCH_HEIGHT)\r
256                 return NULL;\r
257 \r
258         DPatch* newPatch = new DPatch();\r
259 \r
260         newPatch->height        = newHeight;\r
261         newPatch->width         = p1->width;\r
262         newPatch->SetTexture(p1->texture);\r
263 \r
264         int y = 0;\r
265         int i;\r
266         for(i = 0; i < p1->height; i++, y++)\r
267                 for(int x = 0; x < p1->width; x++)\r
268                         memcpy(&newPatch->points[x][y], &p1->points[x][i],      sizeof(drawVert_t));\r
269 \r
270         for(i = 1; i < p2->height; i++, y++)\r
271                 for(int x = 0; x < p2->width; x++)\r
272                         memcpy(&newPatch->points[x][y], &p2->points[x][i],      sizeof(drawVert_t));\r
273 \r
274 //      newPatch->Invert();\r
275 \r
276         return newPatch;\r
277 }\r
278 \r
279 void DPatch::Invert()\r
280 {\r
281         drawVert_t vertTemp;\r
282         int i, j;\r
283 \r
284         for(i = 0 ; i < width ; i++ ) \r
285         {\r
286                 for(j = 0; j < height / 2; j++)\r
287                 {\r
288                         memcpy(&vertTemp, &points[i][height - 1- j], sizeof (drawVert_t));\r
289                         memcpy(&points[i][height - 1 - j], &points[i][j], sizeof(drawVert_t));\r
290                         memcpy(&points[i][j], &vertTemp, sizeof(drawVert_t));\r
291                 }\r
292         }\r
293 }\r
294 \r
295 void DPatch::Transpose()\r
296 {\r
297         int             i, j, w;\r
298         drawVert_t dv;\r
299 \r
300         if ( width > height ) \r
301         {\r
302                 for ( i = 0 ; i < height ; i++ ) \r
303                 {\r
304                         for ( j = i + 1 ; j < width ; j++ ) \r
305                         {\r
306                                 if ( j < height ) \r
307                                 {\r
308                                         // swap the value\r
309                                         memcpy(&dv,                             &points[j][i],  sizeof(drawVert_t));\r
310                                         memcpy(&points[j][i],   &points[i][j],  sizeof(drawVert_t));\r
311                                         memcpy(&points[i][j],   &dv,                    sizeof(drawVert_t));\r
312                                 } \r
313                                 else \r
314                                 {\r
315                                 // just copy\r
316                                         memcpy(&points[i][j],   &points[j][i],  sizeof(drawVert_t));\r
317                         }\r
318                 }\r
319                  }\r
320         } \r
321         else \r
322         {\r
323                 for ( i = 0 ; i < width ; i++ ) \r
324         {\r
325                         for ( j = i + 1 ; j < height ; j++ ) \r
326                         {\r
327                         if ( j < width ) \r
328                                 {\r
329                                         // swap the value\r
330                                         memcpy(&dv,                             &points[i][j],  sizeof(drawVert_t));\r
331                                         memcpy(&points[i][j],   &points[j][i],  sizeof(drawVert_t));\r
332                                 memcpy(&points[j][i],   &dv,                    sizeof(drawVert_t));\r
333                         } \r
334                                 else \r
335                                 {\r
336                                 // just copy\r
337                                         memcpy(&points[j][i],   &points[i][j],  sizeof(drawVert_t));\r
338                         }\r
339                 }\r
340         }\r
341     }\r
342 \r
343         w = width;\r
344         width = height;\r
345         height = w;\r
346 \r
347         Invert();\r
348 }\r
349 \r
350 list<DPatch> DPatch::Split(bool rows, bool cols)\r
351 {\r
352         list<DPatch> patchList;\r
353         int i;\r
354         int x, y;\r
355 \r
356         if(rows && height >= 5)\r
357         {\r
358                 for(i = 0; i < (height-1)/2; i++)\r
359                 {\r
360                         DPatch p;\r
361 \r
362                         p.width = width;\r
363                         p.height = 3;\r
364                         p.SetTexture(texture);\r
365 \r
366                         for(y = 0; y < 3; y++)\r
367                         {\r
368                                 for(x = 0; x < p.width; x++)\r
369                                 {\r
370                                         memcpy(&p.points[x][y], &points[x][(i*2)+y],    sizeof(drawVert_t));\r
371                                 }\r
372                         }\r
373                         patchList.push_back(p);\r
374                 }\r
375 \r
376                 if(cols && width >= 5)\r
377                 {\r
378                         list<DPatch> patchList2;\r
379 \r
380                         for(list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++)\r
381                         {\r
382                                 list<DPatch> patchList3 = (*patches).Split(false, true);\r
383                                 \r
384                                 for(list<DPatch>::iterator patches2 = patchList3.begin(); patches2 != patchList3.end(); patches2++)\r
385                                         patchList2.push_front(*patches2);\r
386                         }\r
387 \r
388                         return patchList2;\r
389                 }\r
390         }\r
391         else if(cols && width >= 5)\r
392         {\r
393                 for(i = 0; i < (width-1)/2; i++)\r
394                 {\r
395                         DPatch p;\r
396 \r
397                         p.height = height;\r
398                         p.width = 3;\r
399                         p.SetTexture(texture);\r
400 \r
401                         for(x = 0; x < 3; x++)\r
402                         {\r
403                                 for(y = 0; y < p.height; y++)\r
404                                 {\r
405                                         memcpy(&p.points[x][y], &points[(i*2)+x][y],    sizeof(drawVert_t));\r
406                                 }\r
407                         }\r
408 \r
409                         patchList.push_back(p);\r
410                 }\r
411         }\r
412 \r
413         return patchList;\r
414 }\r