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