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
DPatch()45 DPatch::DPatch(){
46 width = MIN_PATCH_WIDTH;
47 height = MIN_PATCH_HEIGHT;
48 QER_entity = NULL;
49 QER_brush = NULL;
50 }
51
~DPatch()52 DPatch::~DPatch(){
53
54 }
55
SetTexture(const char * textureName)56 void DPatch::SetTexture( const char *textureName ){
57 strcpy( texture, textureName );
58 }
59
CopyDrawVert(const drawVert_t * in,drawVert_t * out)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
BuildInRadiant(scene::Node * entity)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
LoadFromPatch(scene::Instance & patch)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
ResetTextures(const char * oldTextureName,const char * newTextureName)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
Build1dArray(vec3_t * array,drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT],int startX,int startY,int number,bool horizontal,bool inverse)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
Print1dArray(vec3_t * array,int size)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
Compare1dArrays(vec3_t * a1,vec3_t * a2,int size)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
IsMergable(DPatch * other)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
MergePatches(patch_merge_t merge_info,DPatch * p1,DPatch * p2)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 NULL;
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
Invert()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
Transpose()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
SplitCols()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
SplitRows()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
Split()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 }
514