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