]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/brush.cpp
create a branch for AB sync
[xonotic/netradiant.git] / radiant / brush.cpp
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 #include "stdafx.h"\r
23 #include <assert.h>\r
24 #include "winding.h"\r
25 #include <limits.h>\r
26 #include "filters.h"\r
27 \r
28 extern MainFrame* g_pParentWnd;\r
29 extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...);\r
30 \r
31 // globals\r
32 \r
33 int g_nBrushId = 0;\r
34 \r
35 #ifdef ENABLE_GROUPS\r
36 const char* Brush_Name(brush_t *b)\r
37 {\r
38   static char cBuff[1024];\r
39         b->numberId = g_nBrushId++;\r
40         if (g_qeglobals.m_bBrushPrimitMode)\r
41   {\r
42     sprintf(cBuff, "Brush %i", b->numberId);\r
43     Brush_SetEpair(b, "Name", cBuff);\r
44   }\r
45   return cBuff;\r
46 }\r
47 #endif\r
48 \r
49 brush_t *Brush_Alloc()\r
50 {\r
51   brush_t *b = (brush_t*)qmalloc(sizeof(brush_t));\r
52   return b;\r
53 }\r
54 /*\r
55 void Brush_Free(brush_t *b)\r
56 {\r
57   free(b);\r
58 }\r
59 */\r
60 void PrintWinding (winding_t *w)\r
61 {\r
62   int i;\r
63 \r
64   Sys_Printf ("-------------\n");\r
65   for (i=0 ; i<w->numpoints ; i++)\r
66     Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]\r
67             , w->points[i][1], w->points[i][2]);\r
68 }\r
69 \r
70 void PrintPlane (plane_t *p)\r
71 {\r
72   Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n",  p->normal[0],  p->normal[1], \r
73   p->normal[2],  p->dist);\r
74 }\r
75 \r
76 void PrintVector (vec3_t v)\r
77 {\r
78   Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n",  v[0],  v[1], v[2]);\r
79 }\r
80 \r
81 \r
82 /*\r
83 =============================================================================\r
84 \r
85                         TEXTURE COORDINATES\r
86 \r
87 =============================================================================\r
88 */\r
89 \r
90 \r
91 /*\r
92 ==================\r
93 textureAxisFromPlane\r
94 ==================\r
95 */\r
96 vec3_t  baseaxis[18] =\r
97 {\r
98 {0,0,1}, {1,0,0}, {0,-1,0},                     // floor\r
99 {0,0,-1}, {1,0,0}, {0,-1,0},            // ceiling\r
100 {1,0,0}, {0,1,0}, {0,0,-1},                     // west wall\r
101 {-1,0,0}, {0,1,0}, {0,0,-1},            // east wall\r
102 {0,1,0}, {1,0,0}, {0,0,-1},                     // south wall\r
103 {0,-1,0}, {1,0,0}, {0,0,-1}                     // north wall\r
104 };\r
105 \r
106 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)\r
107 {\r
108         int             bestaxis;\r
109         float   dot,best;\r
110         int             i;\r
111         \r
112         best = 0;\r
113         bestaxis = 0;\r
114         \r
115         for (i=0 ; i<6 ; i++)\r
116         {\r
117                 dot = DotProduct (pln->normal, baseaxis[i*3]);\r
118     if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best)\r
119                 {\r
120                         best = dot;\r
121                         bestaxis = i;\r
122                 }\r
123         }\r
124         \r
125         VectorCopy (baseaxis[bestaxis*3+1], xv);\r
126         VectorCopy (baseaxis[bestaxis*3+2], yv);\r
127 }\r
128 \r
129 \r
130 \r
131 float   lightaxis[3] = {0.6f, 0.8f, 1.0f};\r
132 /*\r
133 ================\r
134 SetShadeForPlane\r
135 \r
136 Light different planes differently to\r
137 improve recognition\r
138 ================\r
139 */\r
140 extern float ShadeForNormal(vec3_t normal);\r
141 \r
142 float SetShadeForPlane (plane_t *p)\r
143 {\r
144         //return ShadeForNormal(p->normal);\r
145 \r
146         \r
147         int             i;\r
148         float   f;\r
149 \r
150         // axial plane\r
151         for (i=0 ; i<3 ; i++)\r
152                 if (fabs(p->normal[i]) > 0.9)\r
153                 {\r
154                         f = lightaxis[i];\r
155                         return f;\r
156                 }\r
157 \r
158         // between two axial planes\r
159         for (i=0 ; i<3 ; i++)\r
160                 if (fabs(p->normal[i]) < 0.1)\r
161                 {\r
162                         f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;\r
163                         return f;\r
164                 }\r
165 \r
166         // other\r
167         f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;\r
168         return f;\r
169         \r
170 }\r
171 \r
172 vec3_t  vecs[2];\r
173 float   shift[2];\r
174 \r
175 /*\r
176 ================\r
177 Face_Alloc\r
178 ================\r
179 */\r
180 face_t *Face_Alloc( void )\r
181 {\r
182         face_t *f = (face_t*)qmalloc( sizeof( *f ) );\r
183         return f;\r
184 }\r
185 \r
186 /*\r
187 ================\r
188 Face_Free\r
189 ================\r
190 */\r
191 void Face_Free( face_t *f )\r
192 {\r
193         assert( f != 0 );\r
194 \r
195         if ( f->face_winding )\r
196         {\r
197                 free( f->face_winding );\r
198                 f->face_winding = 0;\r
199         }\r
200         f->texdef.~texdef_t();;\r
201 \r
202         free( f );\r
203 }\r
204 \r
205 /*\r
206 ================\r
207 Face_Clone\r
208 ================\r
209 */\r
210 face_t  *Face_Clone (face_t *f)\r
211 {\r
212         face_t  *n;\r
213 \r
214         n = Face_Alloc();\r
215         n->texdef = f->texdef;\r
216   n->brushprimit_texdef = f->brushprimit_texdef;\r
217 \r
218         memcpy (n->planepts, f->planepts, sizeof(n->planepts));\r
219 \r
220         // all other fields are derived, and will be set by Brush_Build\r
221   // FIXME: maybe not, for example n->pData!\r
222         return n;\r
223 }\r
224 \r
225 /*\r
226 ================\r
227 Face_FullClone\r
228 \r
229 makes an exact copy of the face\r
230 ================\r
231 */\r
232 face_t  *Face_FullClone (face_t *f)\r
233 {\r
234         face_t  *n;\r
235 \r
236         n = Face_Alloc();\r
237         n->texdef = f->texdef;\r
238   n->brushprimit_texdef = f->brushprimit_texdef;\r
239         memcpy(n->planepts, f->planepts, sizeof(n->planepts));\r
240         memcpy(&n->plane, &f->plane, sizeof(plane_t));\r
241         if (f->face_winding)\r
242                 n->face_winding = Winding_Clone(f->face_winding);\r
243         else\r
244                 n->face_winding = NULL;\r
245         n->pShader = f->pShader;\r
246         n->pShader->IncRef();\r
247         n->d_texture = n->pShader->getTexture();\r
248         return n;\r
249 }\r
250 \r
251 void Face_SetShader(face_t *face, const char *name)\r
252 {\r
253   if(face->pShader != NULL)\r
254     face->pShader->DecRef();\r
255   face->texdef.SetName(name);\r
256   face->pShader = QERApp_Shader_ForName(name);\r
257   face->pShader->IncRef();\r
258   face->d_texture = face->pShader->getTexture();\r
259   face->texdef.flags = face->pShader->getFlags();\r
260 }\r
261 \r
262 void Face_SetShader(face_t *face, IShader *shader)\r
263 {\r
264   if(face->pShader != NULL)\r
265     face->pShader->DecRef();\r
266   face->texdef.SetName(shader->getName());\r
267   face->d_texture = shader->getTexture();\r
268   face->texdef.flags = shader->getFlags();\r
269   face->pShader = shader;\r
270   face->pShader->IncRef();\r
271 }\r
272 \r
273 /*\r
274 ================\r
275 Clamp\r
276 ================\r
277 */\r
278 void Clamp(float& f, int nClamp)\r
279 {\r
280   float fFrac = f - static_cast<int>(f);\r
281   f = static_cast<int>(f) % nClamp;\r
282   f += fFrac;\r
283 }\r
284 \r
285 /*\r
286 ================\r
287 Face_MoveTexture\r
288 ================\r
289 */\r
290 void Face_MoveTexture(face_t *f, vec3_t delta)\r
291 {\r
292         vec3_t vX, vY;\r
293 \r
294         if (g_qeglobals.m_bBrushPrimitMode)\r
295                 ShiftTextureGeometric_BrushPrimit( f, delta );\r
296         else\r
297         {\r
298                 TextureAxisFromPlane(&f->plane, vX, vY);\r
299 \r
300                 vec3_t vDP, vShift;\r
301                 vDP[0] = DotProduct(delta, vX);\r
302                 vDP[1] = DotProduct(delta, vY);\r
303 \r
304                 double fAngle = f->texdef.rotate  / 180 * Q_PI;\r
305                 double c = cos(fAngle);\r
306                 double s = sin(fAngle);\r
307 \r
308                 vShift[0] = vDP[0] * c - vDP[1] * s;\r
309                 vShift[1] = vDP[0] * s + vDP[1] * c;\r
310 \r
311                 if (!f->texdef.scale[0])\r
312                         f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale;\r
313                 if (!f->texdef.scale[1])\r
314                         f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale;\r
315 \r
316                 f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];\r
317                 f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];\r
318   \r
319                 // clamp the shifts\r
320                 Clamp(f->texdef.shift[0], f->d_texture->width);\r
321                 Clamp(f->texdef.shift[1], f->d_texture->height);\r
322         }\r
323 }\r
324 \r
325 /*\r
326 ================\r
327 Face_SetColor\r
328 ================\r
329 */\r
330 /*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/\r
331 void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) \r
332 {\r
333         // set shading for face\r
334   f->d_shade = SetShadeForPlane (&f->plane);\r
335         f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade;\r
336   f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade;\r
337         f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade;\r
338 }\r
339 \r
340 /*\r
341 ================\r
342 Face_TextureVectors\r
343 ================\r
344 */\r
345 void Face_TextureVectors (face_t *f, float STfromXYZ[2][4])\r
346 {\r
347         vec3_t          pvecs[2];\r
348         int                     sv, tv;\r
349         float           ang, sinv, cosv;\r
350         float           ns, nt;\r
351         int                     i,j;\r
352         qtexture_t *q;\r
353         texdef_t        *td;\r
354 \r
355 #ifdef _DEBUG\r
356         // this code is not supposed to be used while in BP mode, warning here can help spot the problem\r
357         if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert)\r
358                 Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");\r
359 #endif\r
360 \r
361         td = &f->texdef;\r
362         q = f->d_texture;\r
363 \r
364         memset (STfromXYZ, 0, 8*sizeof(float));\r
365 \r
366         if (!td->scale[0])\r
367                 td->scale[0] = g_pGameDescription->mTextureDefaultScale;\r
368         if (!td->scale[1])\r
369                 td->scale[1] = g_pGameDescription->mTextureDefaultScale;\r
370 \r
371         // get natural texture axis\r
372         TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);\r
373 \r
374         // rotate axis\r
375         if (td->rotate == 0)\r
376                 { sinv = 0 ; cosv = 1; }\r
377         else if (td->rotate == 90)\r
378                 { sinv = 1 ; cosv = 0; }\r
379         else if (td->rotate == 180)\r
380                 { sinv = 0 ; cosv = -1; }\r
381         else if (td->rotate == 270)\r
382                 { sinv = -1 ; cosv = 0; }\r
383         else\r
384         {       \r
385                 ang = td->rotate / 180 * Q_PI;\r
386                 sinv = sin(ang);\r
387                 cosv = cos(ang);\r
388         }\r
389 \r
390         if (pvecs[0][0])\r
391                 sv = 0;\r
392         else if (pvecs[0][1])\r
393                 sv = 1;\r
394         else\r
395                 sv = 2;\r
396                                 \r
397         if (pvecs[1][0])\r
398                 tv = 0;\r
399         else if (pvecs[1][1])\r
400                 tv = 1;\r
401         else\r
402                 tv = 2;\r
403                                         \r
404         for (i=0 ; i<2 ; i++) {\r
405                 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];\r
406                 nt = sinv * pvecs[i][sv] +  cosv * pvecs[i][tv];\r
407                 STfromXYZ[i][sv] = ns;\r
408                 STfromXYZ[i][tv] = nt;\r
409         }\r
410 \r
411         // scale\r
412         for (i=0 ; i<2 ; i++)\r
413                 for (j=0 ; j<3 ; j++)\r
414                         STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];\r
415 \r
416         // shift\r
417         STfromXYZ[0][3] = td->shift[0];\r
418         STfromXYZ[1][3] = td->shift[1];\r
419 \r
420         for (j=0 ; j<4 ; j++) {\r
421                 STfromXYZ[0][j] /= q->width;\r
422                 STfromXYZ[1][j] /= q->height;\r
423         }\r
424 }\r
425 \r
426 /*\r
427 ================\r
428 Face_MakePlane\r
429 ================\r
430 */\r
431 void Face_MakePlane (face_t *f)\r
432 {\r
433         int             j;\r
434         vec3_t  t1, t2, t3;\r
435 \r
436         // convert to a vector / dist plane\r
437         for (j=0 ; j<3 ; j++)\r
438         {\r
439                 t1[j] = f->planepts[0][j] - f->planepts[1][j];\r
440                 t2[j] = f->planepts[2][j] - f->planepts[1][j];\r
441                 t3[j] = f->planepts[1][j];\r
442         }\r
443         \r
444         CrossProduct(t1,t2, f->plane.normal);\r
445         if (VectorCompare (f->plane.normal, vec3_origin))\r
446                 Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n");\r
447         VectorNormalize (f->plane.normal, f->plane.normal);\r
448         f->plane.dist = DotProduct (t3, f->plane.normal);\r
449 }\r
450 \r
451 /*\r
452 ================\r
453 EmitTextureCoordinates\r
454 ================\r
455 */\r
456 void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)\r
457 {\r
458         float   STfromXYZ[2][4];\r
459 \r
460         Face_TextureVectors (f,  STfromXYZ);\r
461         xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3];\r
462         xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];\r
463 }\r
464 \r
465 //==========================================================================\r
466 \r
467 /*\r
468 ================\r
469 Brush_MakeFacePlanes\r
470 ================\r
471 */\r
472 void Brush_MakeFacePlanes (brush_t *b)\r
473 {\r
474         face_t  *f;\r
475 \r
476         for (f=b->brush_faces ; f ; f=f->next)\r
477         {\r
478                 Face_MakePlane (f);\r
479         }\r
480 }\r
481 \r
482 /*\r
483 ================\r
484 DrawBrushEntityName\r
485 ================\r
486 */\r
487 void DrawBrushEntityName (brush_t *b)\r
488 {\r
489   const char  *name;\r
490   float a, s, c;\r
491   vec3_t  mid;\r
492   int   i;\r
493 \r
494   if (!b->owner)\r
495     return;   // during contruction\r
496 \r
497   if (b->owner == world_entity)\r
498     return;\r
499 \r
500   if (b != b->owner->brushes.onext)\r
501     return; // not key brush\r
502 \r
503   // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views\r
504   // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job?\r
505   // Brush_DrawFacingAngle() works when called, but is not being called.\r
506   if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE))\r
507   {\r
508     // draw the angle pointer\r
509     a = FloatForKey (b->owner, "angle");\r
510     s = sin (a/180*Q_PI);\r
511     c = cos (a/180*Q_PI);\r
512     for (i=0 ; i<3 ; i++)\r
513       mid[i] = (b->mins[i] + b->maxs[i])*0.5; \r
514 \r
515     qglBegin (GL_LINE_STRIP);\r
516     qglVertex3fv (mid);\r
517     mid[0] += c*8;\r
518     mid[1] += s*8;\r
519     mid[2] += s*8;\r
520     qglVertex3fv (mid);\r
521     mid[0] -= c*4;\r
522     mid[1] -= s*4;\r
523     mid[2] -= s*4;\r
524     mid[0] -= s*4;\r
525     mid[1] += c*4;\r
526     mid[2] += c*4;\r
527     qglVertex3fv (mid);\r
528     mid[0] += c*4;\r
529     mid[1] += s*4;\r
530     mid[2] += s*4;\r
531     mid[0] += s*4;\r
532     mid[1] -= c*4;\r
533     mid[2] -= c*4;\r
534     qglVertex3fv (mid);\r
535     mid[0] -= c*4;\r
536     mid[1] -= s*4;\r
537     mid[2] -= s*4;\r
538     mid[0] += s*4;\r
539     mid[1] -= c*4;\r
540     mid[2] -= c*4;\r
541     qglVertex3fv (mid);\r
542     qglEnd ();\r
543   }\r
544 \r
545   if (g_qeglobals.d_savedinfo.show_names)\r
546   {\r
547     name = ValueForKey (b->owner, "classname");\r
548     qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);\r
549     gtk_glwidget_print_string(name);\r
550   }\r
551 }\r
552 \r
553 /*\r
554 =================\r
555 Brush_MakeFaceWinding\r
556 \r
557 returns the visible polygon on a face\r
558 =================\r
559 */\r
560 winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face)\r
561 {\r
562         winding_t       *w;\r
563         face_t          *clip;\r
564         plane_t                 plane;\r
565         qboolean                past;\r
566 \r
567   // get a poly that covers an effectively infinite area\r
568         w = Winding_BaseForPlane (&face->plane);\r
569 \r
570         // chop the poly by all of the other faces\r
571         past = false;\r
572         for (clip = b->brush_faces ; clip && w ; clip=clip->next)\r
573         {\r
574                 if (clip == face)\r
575                 {\r
576                         past = true;\r
577                         continue;\r
578                 }\r
579                 if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999\r
580                         && fabs(face->plane.dist - clip->plane.dist) < 0.01 )\r
581                 {       // identical plane, use the later one\r
582                         if (past)\r
583                         {\r
584                                 free (w);\r
585                                 return NULL;\r
586                         }\r
587                         continue;\r
588                 }\r
589 \r
590                 // flip the plane, because we want to keep the back side\r
591                 VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);\r
592                 plane.dist = -clip->plane.dist;\r
593                 \r
594                 w = Winding_Clip (w, &plane, false);\r
595                 if (!w)\r
596                         return w;\r
597         }\r
598         \r
599         if (w->numpoints < 3)\r
600         {\r
601                 free(w);\r
602                 w = NULL;\r
603         }\r
604 \r
605         if (!w)\r
606                 Sys_FPrintf (SYS_WRN, "unused plane\n");\r
607 \r
608         return w;\r
609 }\r
610 \r
611 /*\r
612 =================\r
613 Brush_SnapPlanepts\r
614 =================\r
615 */\r
616 void Brush_SnapPlanepts (brush_t *b)\r
617 {\r
618         int             i, j;\r
619         face_t  *f;\r
620 \r
621   if (g_PrefsDlg.m_bNoClamp)\r
622     return;\r
623 \r
624   if (g_qeglobals.d_bSmallGrid)\r
625   {\r
626           for (f=b->brush_faces ; f; f=f->next)\r
627                   for (i=0 ; i<3 ; i++)\r
628                           for (j=0 ; j<3 ; j++)\r
629                                 f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize;\r
630   }\r
631   else\r
632   {\r
633           for (f=b->brush_faces ; f; f=f->next)\r
634                   for (i=0 ; i<3 ; i++)\r
635                           for (j=0 ; j<3 ; j++)\r
636                                   f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);\r
637   }\r
638 }\r
639         \r
640 /*\r
641 ** Brush_Build\r
642 **\r
643 ** Builds a brush rendering data and also sets the min/max bounds\r
644 */\r
645 // TTimo\r
646 // added a bConvert flag to convert between old and new brush texture formats\r
647 // TTimo\r
648 // brush grouping: update the group treeview if necessary\r
649 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest)\r
650 {\r
651         bool            bLocalConvert;\r
652 \r
653         \r
654 #ifdef _DEBUG\r
655         if (!g_qeglobals.m_bBrushPrimitMode && bConvert)\r
656                 Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");\r
657 #endif\r
658 \r
659         // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only\r
660         if (bConvert && !g_qeglobals.bNeedConvert)\r
661         {\r
662 #ifdef _DEBUG\r
663     //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes\r
664     // back and forth in one format or the other .. more when mixing BP / noBP in the same maps.\r
665 #endif\r
666                 bLocalConvert = true;\r
667                 g_qeglobals.bNeedConvert = true;\r
668         }\r
669         else\r
670           bLocalConvert = false;\r
671 \r
672         /*\r
673         ** build the windings and generate the bounding box\r
674         */\r
675         Brush_BuildWindings(b, bSnap);\r
676 \r
677   if(b->owner->model.pRender)\r
678   {\r
679     const aabb_t *aabb = b->owner->model.pRender->GetAABB();\r
680     VectorAdd(aabb->origin, aabb->extents, b->maxs);\r
681     VectorSubtract(aabb->origin, aabb->extents, b->mins);\r
682   } \r
683 \r
684         //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH !\r
685 \r
686         /*\r
687         ** move the points and edges if in select mode\r
688         */\r
689         if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)\r
690                 SetupVertexSelection ();\r
691 \r
692         if (b->itemOwner == 0) //NULL)\r
693           Group_AddToProperGroup(b);\r
694 \r
695         if (bMarkMap)\r
696         {\r
697                 Sys_MarkMapModified();\r
698         }\r
699 \r
700         if (bLocalConvert)\r
701                 g_qeglobals.bNeedConvert = false;\r
702 \r
703         // spog - applying filters to brush during brush_build instead of during redraw\r
704         if (bFilterTest)\r
705                 b->bFiltered = FilterBrush( b );\r
706 }\r
707 \r
708 /*\r
709 ==============\r
710 Brush_SplitBrushByFace\r
711 \r
712 The incoming brush is NOT freed.\r
713 The incoming face is NOT left referenced.\r
714 ==============\r
715 */\r
716 void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk)\r
717 {\r
718         brush_t *b;\r
719         face_t  *nf;\r
720         vec3_t  temp;\r
721 \r
722         b = Brush_Clone (in);\r
723         nf = Face_Clone (f);\r
724 \r
725         nf->texdef = b->brush_faces->texdef;\r
726   if (bCaulk)\r
727   {\r
728     nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());\r
729   }\r
730         nf->next = b->brush_faces;\r
731         b->brush_faces = nf;\r
732 \r
733         Brush_Build( b );\r
734         Brush_RemoveEmptyFaces ( b );\r
735         if ( !b->brush_faces )\r
736         {       // completely clipped away\r
737                 Brush_Free (b);\r
738                 *back = NULL;\r
739         }\r
740         else\r
741         {\r
742                 Entity_LinkBrush (in->owner, b);\r
743                 *back = b;\r
744         }\r
745 \r
746         b = Brush_Clone (in);\r
747         nf = Face_Clone (f);\r
748         // swap the plane winding\r
749         VectorCopy (nf->planepts[0], temp);\r
750         VectorCopy (nf->planepts[1], nf->planepts[0]);\r
751         VectorCopy (temp, nf->planepts[1]);\r
752 \r
753         nf->texdef = b->brush_faces->texdef;\r
754   if (bCaulk)\r
755   {\r
756     nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());\r
757   }\r
758         nf->next = b->brush_faces;\r
759         b->brush_faces = nf;\r
760 \r
761         Brush_Build( b );\r
762         Brush_RemoveEmptyFaces ( b );\r
763         if ( !b->brush_faces )\r
764         {       // completely clipped away\r
765                 Brush_Free (b);\r
766                 *front = NULL;\r
767         }\r
768         else\r
769         {\r
770                 Entity_LinkBrush (in->owner, b);\r
771                 *front = b;\r
772         }\r
773 }\r
774 \r
775 /*\r
776 =================\r
777 Brush_BestSplitFace\r
778 \r
779 returns the best face to split the brush with.\r
780 return NULL if the brush is convex\r
781 =================\r
782 */\r
783 face_t *Brush_BestSplitFace(brush_t *b)\r
784 {\r
785         face_t *face, *f, *bestface;\r
786         winding_t *front, *back;\r
787         int splits, tinywindings, value, bestvalue;\r
788 \r
789         bestvalue = 999999;\r
790         bestface = NULL;\r
791         for (face = b->brush_faces; face; face = face->next)\r
792         {\r
793                 splits = 0;\r
794                 tinywindings = 0;\r
795                 for (f = b->brush_faces; f; f = f->next)\r
796                 {\r
797                         if (f == face) continue;\r
798                         //\r
799                         Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back);\r
800 \r
801                         if (!front)\r
802                         {\r
803                                 Winding_Free(back);\r
804                         }\r
805                         else if (!back)\r
806                         {\r
807                                 Winding_Free(front);\r
808                         }\r
809                         else\r
810                         {\r
811                                 splits++;\r
812                                 if (Winding_IsTiny(front)) tinywindings++;\r
813                                 if (Winding_IsTiny(back)) tinywindings++;\r
814                         }\r
815                 }\r
816                 if (splits)\r
817                 {\r
818                         value = splits + 50 * tinywindings;\r
819                         if (value < bestvalue)\r
820                         {\r
821                                 bestvalue = value;\r
822                                 bestface = face;\r
823                         }\r
824                 }\r
825         }\r
826         return bestface;\r
827 }\r
828 \r
829 /*\r
830 =================\r
831 Brush_MakeConvexBrushes\r
832 \r
833 MrE FIXME: this doesn't work because the old\r
834                    Brush_SplitBrushByFace is used\r
835 Turns the brush into a minimal number of convex brushes.\r
836 If the input brush is convex then it will be returned.\r
837 Otherwise the input brush will be freed.\r
838 NOTE: the input brush should have windings for the faces.\r
839 =================\r
840 */\r
841 brush_t *Brush_MakeConvexBrushes(brush_t *b)\r
842 {\r
843         brush_t *front, *back, *end;\r
844         face_t *face;\r
845 \r
846         b->next = NULL;\r
847         face = Brush_BestSplitFace(b);\r
848         if (!face) return b;\r
849         Brush_SplitBrushByFace(b, face, &front, &back);\r
850         //this should never happen\r
851         if (!front && !back) return b;\r
852         Brush_Free(b);\r
853         if (!front)\r
854                 return Brush_MakeConvexBrushes(back);\r
855         b = Brush_MakeConvexBrushes(front);\r
856         if (back)\r
857         {\r
858                 for (end = b; end->next; end = end->next);\r
859                 end->next = Brush_MakeConvexBrushes(back);\r
860         }\r
861         return b;\r
862 }\r
863 \r
864 /*\r
865 =================\r
866 Brush_Convex\r
867 =================\r
868 */\r
869 int Brush_Convex(brush_t *b)\r
870 {\r
871         face_t *face1, *face2;\r
872 \r
873         for (face1 = b->brush_faces; face1; face1 = face1->next)\r
874         {\r
875                 if (!face1->face_winding) continue;\r
876                 for (face2 = b->brush_faces; face2; face2 = face2->next)\r
877                 {\r
878                         if (face1 == face2) continue;\r
879                         if (!face2->face_winding) continue;\r
880                         if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,\r
881                                                                                 face1->plane.normal, face2->plane.normal,\r
882                                                                                 face1->plane.dist, face2->plane.dist))\r
883                         {\r
884                                 return false;\r
885                         }\r
886                 }\r
887         }\r
888         return true;\r
889 }\r
890 \r
891 /*\r
892 =================\r
893 Brush_MoveVertexes\r
894 \r
895 - The input brush must be convex\r
896 - The input brush must have face windings.\r
897 - The output brush will be convex.\r
898 - Returns true if the WHOLE vertex movement is performed.\r
899 =================\r
900 */\r
901 \r
902 // define this to debug the vertex editing mode\r
903 #ifdef _DEBUG\r
904 //#define DBG_VERT\r
905 #endif\r
906 \r
907 #define MAX_MOVE_FACES          64\r
908 \r
909 int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)\r
910 {\r
911         face_t *f, *face, *newface, *lastface, *nextface;\r
912         face_t *movefaces[MAX_MOVE_FACES];\r
913         int movefacepoints[MAX_MOVE_FACES];\r
914         winding_t *w, tmpw;\r
915         vec3_t start, mid;\r
916         plane_t plane;\r
917         int i, j, k, nummovefaces, result, done;\r
918         float dot, front, back, frac, smallestfrac;\r
919 \r
920 #ifdef DBG_VERT\r
921   Sys_Printf("Bursh_MoveVertex: %p vertex: %g %g %g delta: %g %g %g end: %g %g %g snap: %s\n", b, vertex[0], vertex[1], vertex[2], delta[0], delta[1], delta[2], end[0], end[1], end[2], bSnap ? "true" : "false" );\r
922 #endif\r
923 \r
924         result = true;\r
925         //\r
926         tmpw.numpoints = 3;\r
927         tmpw.maxpoints = 3;\r
928         VectorCopy(vertex, start);\r
929         VectorAdd(vertex, delta, end);\r
930         //snap or not?\r
931         if (bSnap)\r
932                 for (i = 0; i < 3; i++)\r
933                         end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize;\r
934         //\r
935         VectorCopy(end, mid);\r
936         //if the start and end are the same\r
937         if (Point_Equal(start, end, 0.3f)) return false;\r
938         //the end point may not be the same as another vertex\r
939         for (face = b->brush_faces; face; face = face->next)\r
940         {\r
941                 w = face->face_winding;\r
942                 if (!w) continue;\r
943                 for (i = 0; i < w->numpoints; i++)\r
944                 {\r
945                         if (Point_Equal(w->points[i], end, 0.3f))\r
946                         {\r
947                                 VectorCopy(vertex, end);\r
948                                 return false;\r
949                         }\r
950                 }\r
951         }\r
952         //\r
953         done = false;\r
954         while(!done)\r
955         {\r
956                 //chop off triangles from all brush faces that use the to be moved vertex\r
957                 //store pointers to these chopped off triangles in movefaces[]\r
958                 nummovefaces = 0;\r
959                 for (face = b->brush_faces; face; face = face->next)\r
960                 {\r
961                         w = face->face_winding;\r
962                         if (!w) continue;\r
963                         for (i = 0; i < w->numpoints; i++)\r
964                         {\r
965                                 if (Point_Equal(w->points[i], start, 0.2f))\r
966                                 {\r
967                                         if (face->face_winding->numpoints <= 3)\r
968                                         {\r
969                                                 movefacepoints[nummovefaces] = i;\r
970                                                 movefaces[nummovefaces++] = face;\r
971                                                 break;\r
972                                         }\r
973                                         dot = DotProduct(end, face->plane.normal) - face->plane.dist;\r
974                                         //if the end point is in front of the face plane\r
975                                         if (dot > 0.1)\r
976                                         {\r
977                                           //fanout triangle subdivision\r
978                                           for (k = i; k < i + w->numpoints-3; k++)\r
979                                           {\r
980                                             VectorCopy(w->points[i], tmpw.points[0]);\r
981                                             VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);\r
982                                             VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);\r
983                                             //\r
984                                             newface = Face_Clone(face);\r
985                                             //get the original\r
986                                             for (f = face; f->original; f = f->original) ;\r
987                                             newface->original = f;\r
988                                             //store the new winding\r
989                                             if (newface->face_winding) Winding_Free(newface->face_winding);\r
990                                             newface->face_winding = Winding_Clone(&tmpw);\r
991                                             //get the texture information\r
992                                             newface->pShader = face->pShader;\r
993                                             newface->d_texture = face->d_texture;\r
994 \r
995                                             //add the face to the brush\r
996                                             newface->next = b->brush_faces;\r
997                                             b->brush_faces = newface;\r
998                                             //add this new triangle to the move faces\r
999                                             movefacepoints[nummovefaces] = 0;\r
1000                                             movefaces[nummovefaces++] = newface;\r
1001                                           }\r
1002                                           //give the original face a new winding\r
1003                                           VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);\r
1004                                           VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);\r
1005                                           VectorCopy(w->points[i], tmpw.points[2]);\r
1006                                           Winding_Free(face->face_winding);\r
1007                                           face->face_winding = Winding_Clone(&tmpw);\r
1008                                           //add the original face to the move faces\r
1009                                           movefacepoints[nummovefaces] = 2;\r
1010                                           movefaces[nummovefaces++] = face;\r
1011                                         }\r
1012                                         else\r
1013                                         {\r
1014                                                 //chop a triangle off the face\r
1015                                                 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);\r
1016                                                 VectorCopy(w->points[i], tmpw.points[1]);\r
1017                                                 VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);\r
1018                                                 //remove the point from the face winding\r
1019                                                 Winding_RemovePoint(w, i);\r
1020                                                 //get texture crap right\r
1021                                                 Face_SetColor(b, face, 1.0);\r
1022                                                 for (j = 0; j < w->numpoints; j++)\r
1023                                                         EmitTextureCoordinates(w->points[j], face->d_texture, face);\r
1024                                                 //make a triangle face\r
1025                                                 newface = Face_Clone(face);\r
1026                                                 //get the original\r
1027                                                 for (f = face; f->original; f = f->original) ;\r
1028                                                 newface->original = f;\r
1029                                                 //store the new winding\r
1030                                                 if (newface->face_winding) Winding_Free(newface->face_winding);\r
1031                                                 newface->face_winding = Winding_Clone(&tmpw);\r
1032                                                 //get the texture\r
1033                                                 newface->pShader = face->pShader;\r
1034                                                 newface->d_texture = newface->pShader->getTexture();\r
1035 //                                              newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name );\r
1036                                                 //add the face to the brush\r
1037                                                 newface->next = b->brush_faces;\r
1038                                                 b->brush_faces = newface;\r
1039                                                 //\r
1040                                                 movefacepoints[nummovefaces] = 1;\r
1041                                                 movefaces[nummovefaces++] = newface;\r
1042                                         }\r
1043                                         break;\r
1044                                 }\r
1045                         }\r
1046                 }\r
1047                 //now movefaces contains pointers to triangle faces that\r
1048                 //contain the to be moved vertex\r
1049                 //\r
1050                 done = true;\r
1051                 VectorCopy(end, mid);\r
1052                 smallestfrac = 1;\r
1053                 for (face = b->brush_faces; face; face = face->next)\r
1054                 {\r
1055                         //check if there is a move face that has this face as the original\r
1056                         for (i = 0; i < nummovefaces; i++)\r
1057                         {\r
1058                                 if (movefaces[i]->original == face) break;\r
1059                         }\r
1060                         if (i >= nummovefaces) continue;\r
1061                         //check if the original is not a move face itself\r
1062                         for (j = 0; j < nummovefaces; j++)\r
1063                         {\r
1064                                 if (face == movefaces[j]) break;\r
1065                         }\r
1066                         //if the original is not a move face itself\r
1067                         if (j >= nummovefaces)\r
1068                         {\r
1069                                 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t));\r
1070                         }\r
1071                         else\r
1072                         {\r
1073                                 k = movefacepoints[j];\r
1074                                 w = movefaces[j]->face_winding;\r
1075                                 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]);\r
1076                                 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]);\r
1077                                 //\r
1078                                 k = movefacepoints[i];\r
1079                                 w = movefaces[i]->face_winding;\r
1080                                 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]);\r
1081                                 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))\r
1082                                 {\r
1083                                         VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]);\r
1084                                         if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))\r
1085                                                 //this should never happen otherwise the face merge did a crappy job a previous pass\r
1086                                                 continue;\r
1087                                 }\r
1088                         }\r
1089                         //now we've got the plane to check agains\r
1090                         front = DotProduct(start, plane.normal) - plane.dist;\r
1091                         back = DotProduct(end, plane.normal) - plane.dist;\r
1092                         //if the whole move is at one side of the plane\r
1093                         if (front < 0.01 && back < 0.01) continue;\r
1094                         if (front > -0.01 && back > -0.01) continue;\r
1095                         //if there's no movement orthogonal to this plane at all\r
1096                         if (fabs(front-back) < 0.001) continue;\r
1097                         //ok first only move till the plane is hit\r
1098                         frac = front/(front-back);\r
1099                         if (frac < smallestfrac)\r
1100                         {\r
1101                                 mid[0] = start[0] + (end[0] - start[0]) * frac;\r
1102                                 mid[1] = start[1] + (end[1] - start[1]) * frac;\r
1103                                 mid[2] = start[2] + (end[2] - start[2]) * frac;\r
1104                                 smallestfrac = frac;\r
1105                         }\r
1106                         //\r
1107                         done = false;\r
1108                 }\r
1109 \r
1110                 //move the vertex\r
1111                 for (i = 0; i < nummovefaces; i++)\r
1112                 {\r
1113                         //move vertex to end position\r
1114                         VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]);\r
1115                         //create new face plane\r
1116                         for (j = 0; j < 3; j++)\r
1117                         {\r
1118                                 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);\r
1119                         }\r
1120                         Face_MakePlane(movefaces[i]);\r
1121                         if (VectorLength(movefaces[i]->plane.normal) < 0.1)\r
1122                                 result = false;\r
1123                 }\r
1124                 //if the brush is no longer convex\r
1125                 if (!result || !Brush_Convex(b))\r
1126                 {\r
1127                         for (i = 0; i < nummovefaces; i++)\r
1128                         {\r
1129                                 //move the vertex back to the initial position\r
1130                                 VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]);\r
1131                                 //create new face plane\r
1132                                 for (j = 0; j < 3; j++)\r
1133                                 {\r
1134                                         VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);\r
1135                                 }\r
1136                                 Face_MakePlane(movefaces[i]);\r
1137                         }\r
1138                         result = false;\r
1139                         VectorCopy(start, end);\r
1140                         done = true;\r
1141                 }\r
1142                 else\r
1143                 {\r
1144                         VectorCopy(mid, start);\r
1145                 }\r
1146                 //get texture crap right\r
1147                 for (i = 0; i < nummovefaces; i++)\r
1148                 {\r
1149                         Face_SetColor(b, movefaces[i], 1.0);\r
1150                         for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)\r
1151                                 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);\r
1152                 }\r
1153 \r
1154                 //now try to merge faces with their original faces\r
1155                 lastface = NULL;\r
1156                 for (face = b->brush_faces; face; face = nextface)\r
1157                 {\r
1158                         nextface = face->next;\r
1159                         if (!face->original)\r
1160                         {\r
1161                                 lastface = face;\r
1162                                 continue;\r
1163                         }\r
1164                         if (!Plane_Equal(&face->plane, &face->original->plane, false))\r
1165                         {\r
1166                                 lastface = face;\r
1167                                 continue;\r
1168                         }\r
1169                         w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);\r
1170                         if (!w)\r
1171                         {\r
1172                                 lastface = face;\r
1173                                 continue;\r
1174                         }\r
1175                         Winding_Free(face->original->face_winding);\r
1176                         face->original->face_winding = w;\r
1177                         //get texture crap right\r
1178                         Face_SetColor(b, face->original, 1.0);\r
1179                         for (j = 0; j < face->original->face_winding->numpoints; j++)\r
1180                                 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);\r
1181                         //remove the face that was merged with the original\r
1182                         if (lastface) lastface->next = face->next;\r
1183                         else b->brush_faces = face->next;\r
1184                         Face_Free(face);\r
1185                 }\r
1186         }\r
1187         return result;\r
1188 }\r
1189 \r
1190 /*\r
1191 =================\r
1192 Brush_InsertVertexBetween\r
1193 =================\r
1194 */\r
1195 int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2)\r
1196 {\r
1197         face_t *face;\r
1198         winding_t *w, *neww;\r
1199         vec3_t point;\r
1200         int i, insert;\r
1201 \r
1202         if (Point_Equal(p1, p2, 0.4f))\r
1203                 return false;\r
1204         VectorAdd(p1, p2, point);\r
1205         VectorScale(point, 0.5f, point);\r
1206         insert = false;\r
1207         //the end point may not be the same as another vertex\r
1208         for (face = b->brush_faces; face; face = face->next)\r
1209         {\r
1210                 w = face->face_winding;\r
1211                 if (!w) continue;\r
1212                 neww = NULL;\r
1213                 for (i = 0; i < w->numpoints; i++)\r
1214                 {\r
1215                         if (!Point_Equal(w->points[i], p1, 0.1f))\r
1216                                 continue;\r
1217                         if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f))\r
1218                         {\r
1219                                 neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints);\r
1220                                 break;\r
1221                         }\r
1222                         else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f))\r
1223                         {\r
1224                                 neww = Winding_InsertPoint(w, point, i);\r
1225                                 break;\r
1226                         }\r
1227                 }\r
1228                 if (neww)\r
1229                 {\r
1230                         Winding_Free(face->face_winding);\r
1231                         face->face_winding = neww;\r
1232                         insert = true;\r
1233                 }\r
1234         }\r
1235         return insert;\r
1236 }\r
1237 \r
1238 \r
1239 /*\r
1240 =================\r
1241 Brush_ResetFaceOriginals\r
1242 =================\r
1243 */\r
1244 void Brush_ResetFaceOriginals(brush_t *b)\r
1245 {\r
1246         face_t *face;\r
1247 \r
1248         for (face = b->brush_faces; face; face = face->next)\r
1249         {\r
1250                 face->original = NULL;\r
1251         }\r
1252 }\r
1253 \r
1254 #ifdef ENABLE_GROUPS\r
1255 /*\r
1256 ==============\r
1257 Brush_SetEpair\r
1258 sets an epair for the given brush\r
1259 ==============\r
1260 */\r
1261 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue)\r
1262 {\r
1263         if (g_qeglobals.m_bBrushPrimitMode)\r
1264         {\r
1265     if (b->patchBrush)\r
1266     {\r
1267       Patch_SetEpair(b->pPatch, pKey, pValue);\r
1268     }\r
1269     else\r
1270     {\r
1271                   SetKeyValue(b->epairs, pKey, pValue);\r
1272     }\r
1273         }\r
1274         else\r
1275         {\r
1276                 Sys_Printf("Can only set key/values in Brush primitive mode\n");\r
1277         }\r
1278 }\r
1279 \r
1280 /* \r
1281 =================\r
1282 Brush_GetKeyValue\r
1283 =================\r
1284 */\r
1285 const char* Brush_GetKeyValue(brush_t *b, const char *pKey)\r
1286 {\r
1287         if (g_qeglobals.m_bBrushPrimitMode)\r
1288         {\r
1289     if (b->patchBrush)\r
1290     {\r
1291       return Patch_GetKeyValue(b->pPatch, pKey);\r
1292     }\r
1293     else\r
1294     {\r
1295                   return ValueForKey(b->epairs, pKey);\r
1296     }\r
1297         }\r
1298         else\r
1299         {\r
1300                 Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n");\r
1301         }\r
1302   return "";\r
1303 }\r
1304 #endif\r
1305 /*\r
1306 =================\r
1307 CheckName\r
1308 temporary stuff, detect potential problems when saving the texture name\r
1309 =================\r
1310 */\r
1311 void CheckName( face_t *fa, char *pname )\r
1312 {\r
1313   if (!strlen(fa->texdef.GetName()))\r
1314         {\r
1315 #ifdef _DEBUG\r
1316                 Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n");\r
1317 #endif\r
1318                 fa->texdef.SetName(SHADER_NOT_FOUND);\r
1319                 strcpy(pname, SHADER_NOT_FOUND);\r
1320                 return;\r
1321         }\r
1322 \r
1323         // some people manage to get long filename textures (with spaces) in their maps\r
1324         if (strchr( fa->texdef.GetName(), ' ' ))\r
1325         {\r
1326                 char Msg1[1024];\r
1327     \r
1328     sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", fa->texdef.GetName() );\r
1329     \r
1330                 Sys_Printf("%s\n", Msg1 );\r
1331                 gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );\r
1332                 strcpy( pname, SHADER_NOT_FOUND );\r
1333                 return;\r
1334         }\r
1335 \r
1336   //++timo FIXME: bug #103494 detection attempt\r
1337   // TODO: clean this detection part when bug will have disappeared\r
1338         if (fa->texdef.GetName()[0] == '(')\r
1339   {\r
1340                 char *text = "Bug #103494 detected, dropping texture. Please report to timo@qeradiant.com if you have a way to reproduce!\nNOTE: this message may popup several times .. once for each buggy face detected.";\r
1341                 Sys_Printf("%s\n", text);\r
1342                 gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK );\r
1343                 // need to cleanup this dead face name or we may loop endlessly\r
1344                 fa->texdef.SetName(SHADER_NOT_FOUND);\r
1345                 strcpy( pname, SHADER_NOT_FOUND );\r
1346                 return;\r
1347         }\r
1348         strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/"\r
1349 }\r
1350 \r
1351 /*\r
1352 =============\r
1353 Brush_Create\r
1354 \r
1355 Create non-textured blocks for entities\r
1356 The brush is NOT linked to any list\r
1357 =============\r
1358 */\r
1359 brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)\r
1360 {\r
1361         int             i, j;\r
1362         vec3_t  pts[4][2];\r
1363         face_t  *f;\r
1364         brush_t *b;\r
1365 \r
1366 #if DBG_BP\r
1367         // brush primitive mode : convert texdef to brushprimit_texdef ?\r
1368         // most of the time texdef is empty\r
1369         if (g_qeglobals.m_bBrushPrimitMode)\r
1370         {\r
1371                 // check texdef is empty .. if there are cases it's not we need to write some conversion code\r
1372                 if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0)\r
1373                         Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n");\r
1374         }\r
1375 #endif\r
1376 \r
1377         for (i=0 ; i<3 ; i++)\r
1378         {\r
1379                 if (maxs[i] < mins[i])\r
1380                         Error ("Brush_InitSolid: backwards");\r
1381         }\r
1382 \r
1383         b = Brush_Alloc();\r
1384         \r
1385         pts[0][0][0] = mins[0];\r
1386         pts[0][0][1] = mins[1];\r
1387         \r
1388         pts[1][0][0] = mins[0];\r
1389         pts[1][0][1] = maxs[1];\r
1390         \r
1391         pts[2][0][0] = maxs[0];\r
1392         pts[2][0][1] = maxs[1];\r
1393         \r
1394         pts[3][0][0] = maxs[0];\r
1395         pts[3][0][1] = mins[1];\r
1396         \r
1397         for (i=0 ; i<4 ; i++)\r
1398         {\r
1399                 pts[i][0][2] = mins[2];\r
1400                 pts[i][1][0] = pts[i][0][0];\r
1401                 pts[i][1][1] = pts[i][0][1];\r
1402                 pts[i][1][2] = maxs[2];\r
1403         }\r
1404 \r
1405         for (i=0 ; i<4 ; i++)\r
1406         {\r
1407                 f = Face_Alloc();\r
1408                 f->texdef = *texdef;\r
1409                 f->texdef.flags &= ~SURF_KEEP;\r
1410                 f->texdef.contents &= ~CONTENTS_KEEP;\r
1411                 f->next = b->brush_faces;\r
1412                 b->brush_faces = f;\r
1413                 j = (i+1)%4;\r
1414 \r
1415                 VectorCopy (pts[j][1], f->planepts[0]);\r
1416                 VectorCopy (pts[i][1], f->planepts[1]);\r
1417                 VectorCopy (pts[i][0], f->planepts[2]);\r
1418         }\r
1419         \r
1420         f = Face_Alloc();\r
1421         f->texdef = *texdef;\r
1422         f->texdef.flags &= ~SURF_KEEP;\r
1423         f->texdef.contents &= ~CONTENTS_KEEP;\r
1424         f->next = b->brush_faces;\r
1425         b->brush_faces = f;\r
1426 \r
1427         VectorCopy (pts[0][1], f->planepts[0]);\r
1428         VectorCopy (pts[1][1], f->planepts[1]);\r
1429         VectorCopy (pts[2][1], f->planepts[2]);\r
1430 \r
1431         f = Face_Alloc();\r
1432         f->texdef = *texdef;\r
1433         f->texdef.flags &= ~SURF_KEEP;\r
1434         f->texdef.contents &= ~CONTENTS_KEEP;\r
1435         f->next = b->brush_faces;\r
1436         b->brush_faces = f;\r
1437 \r
1438         VectorCopy (pts[2][0], f->planepts[0]);\r
1439         VectorCopy (pts[1][0], f->planepts[1]);\r
1440         VectorCopy (pts[0][0], f->planepts[2]);\r
1441 \r
1442         return b;\r
1443 }\r
1444 \r
1445 /*\r
1446 =============\r
1447 Brush_CreatePyramid\r
1448 \r
1449 Create non-textured pyramid for light entities\r
1450 The brush is NOT linked to any list\r
1451 =============\r
1452 */\r
1453 brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef)\r
1454 {\r
1455   int i;\r
1456 \r
1457         //++timo handle new brush primitive ? return here ??\r
1458         return Brush_Create(mins, maxs, texdef);\r
1459 \r
1460         for (i=0 ; i<3 ; i++)\r
1461                 if (maxs[i] < mins[i])\r
1462                         Error ("Brush_InitSolid: backwards");\r
1463 \r
1464         brush_t* b = Brush_Alloc();\r
1465 \r
1466         vec3_t corners[4];\r
1467 \r
1468         float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2)));\r
1469 \r
1470         corners[0][0] = mins[0];\r
1471         corners[0][1] = mins[1];\r
1472         corners[0][2] = fMid;\r
1473 \r
1474         corners[1][0] = mins[0];\r
1475         corners[1][1] = maxs[1];\r
1476         corners[1][2] = fMid;\r
1477 \r
1478         corners[2][0] = maxs[0];\r
1479         corners[2][1] = maxs[1];\r
1480         corners[2][2] = fMid;\r
1481 \r
1482         corners[3][0] = maxs[0];\r
1483         corners[3][1] = mins[1];\r
1484         corners[3][2] = fMid;\r
1485 \r
1486         vec3_t top, bottom;\r
1487 \r
1488         top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2));\r
1489         top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2));\r
1490         top[2] = Rad_rint(maxs[2]);\r
1491 \r
1492         VectorCopy(top, bottom);\r
1493         bottom[2] = mins[2];\r
1494 \r
1495         // sides\r
1496         for (i = 0; i < 4; i++)\r
1497         {\r
1498                 face_t* f = Face_Alloc();\r
1499                 f->texdef = *texdef;\r
1500                 f->texdef.flags &= ~SURF_KEEP;\r
1501                 f->texdef.contents &= ~CONTENTS_KEEP;\r
1502                 f->next = b->brush_faces;\r
1503                 b->brush_faces = f;\r
1504                 int j = (i+1)%4;\r
1505 \r
1506                 VectorCopy (top, f->planepts[0]);\r
1507                 VectorCopy (corners[i], f->planepts[1]);\r
1508                 VectorCopy(corners[j], f->planepts[2]);\r
1509 \r
1510                 f = Face_Alloc();\r
1511                 f->texdef = *texdef;\r
1512                 f->texdef.flags &= ~SURF_KEEP;\r
1513                 f->texdef.contents &= ~CONTENTS_KEEP;\r
1514                 f->next = b->brush_faces;\r
1515                 b->brush_faces = f;\r
1516 \r
1517                 VectorCopy (bottom, f->planepts[2]);\r
1518                 VectorCopy (corners[i], f->planepts[1]);\r
1519                 VectorCopy(corners[j], f->planepts[0]);\r
1520         }\r
1521 \r
1522         return b;\r
1523 }\r
1524 \r
1525 \r
1526 \r
1527 \r
1528 /*\r
1529 =============\r
1530 Brush_MakeSided\r
1531 \r
1532 Makes the current brush have the given number of 2d sides\r
1533 =============\r
1534 */\r
1535 void Brush_MakeSided (int sides)\r
1536 {\r
1537         int             i, axis;\r
1538         vec3_t  mins, maxs;\r
1539         brush_t *b;\r
1540         texdef_t        *texdef;\r
1541         face_t  *f;\r
1542         vec3_t  mid;\r
1543         float   width;\r
1544         float   sv, cv;\r
1545 \r
1546         if (sides < 3)\r
1547         {\r
1548                 Sys_Status ("Bad sides number", 0);\r
1549                 return;\r
1550         }\r
1551 \r
1552         if (sides >= MAX_POINTS_ON_WINDING-4)\r
1553         {\r
1554                 Sys_Printf("too many sides.\n");\r
1555                 return;\r
1556         }\r
1557 \r
1558         if (!QE_SingleBrush ())\r
1559         {\r
1560                 Sys_Status ("Must have a single brush selected", 0 );\r
1561                 return;\r
1562         }\r
1563 \r
1564         b = selected_brushes.next;\r
1565         VectorCopy (b->mins, mins);\r
1566         VectorCopy (b->maxs, maxs);\r
1567         texdef = &g_qeglobals.d_texturewin.texdef;\r
1568 \r
1569         Brush_Free (b);\r
1570 \r
1571         if (g_pParentWnd->ActiveXY())\r
1572         {\r
1573                 switch(g_pParentWnd->ActiveXY()->GetViewType())\r
1574                 {\r
1575                         case XY: axis = 2; break;\r
1576                         case XZ: axis = 1; break;\r
1577                         case YZ: axis = 0; break;\r
1578                 }\r
1579         }\r
1580         else\r
1581         {\r
1582                 axis = 2;\r
1583         }\r
1584 \r
1585         // find center of brush\r
1586         width = 8;\r
1587         for (i = 0; i < 3; i++)\r
1588         {\r
1589                 mid[i] = (maxs[i] + mins[i]) * 0.5;\r
1590                 if (i == axis) continue;\r
1591                 if ((maxs[i] - mins[i]) * 0.5 > width)\r
1592                         width = (maxs[i] - mins[i]) * 0.5;\r
1593         }\r
1594 \r
1595         b = Brush_Alloc();\r
1596                 \r
1597         // create top face\r
1598         f = Face_Alloc();\r
1599         f->texdef = *texdef;\r
1600         f->next = b->brush_faces;\r
1601         b->brush_faces = f;\r
1602 \r
1603         f->planepts[2][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[2][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[2][axis] = maxs[axis];\r
1604         f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = maxs[axis];\r
1605         f->planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[0][axis] = maxs[axis];\r
1606 \r
1607         // create bottom face\r
1608         f = Face_Alloc();\r
1609         f->texdef = *texdef;\r
1610         f->next = b->brush_faces;\r
1611         b->brush_faces = f;\r
1612 \r
1613         f->planepts[0][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[0][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[0][axis] = mins[axis];\r
1614         f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = mins[axis];\r
1615         f->planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[2][axis] = mins[axis];\r
1616 \r
1617         for (i=0 ; i<sides ; i++)\r
1618         {\r
1619                 f = Face_Alloc();\r
1620                 f->texdef = *texdef;\r
1621                 f->next = b->brush_faces;\r
1622                 b->brush_faces = f;\r
1623 \r
1624                 sv = sin (i*3.14159265*2/sides);\r
1625                 cv = cos (i*3.14159265*2/sides);\r
1626 \r
1627                 f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5);\r
1628                 f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5);\r
1629                 f->planepts[0][axis] = mins[axis];\r
1630 \r
1631                 f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3];\r
1632                 f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3];\r
1633                 f->planepts[1][axis] = maxs[axis];\r
1634 \r
1635                 f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5);\r
1636                 f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5);\r
1637                 f->planepts[2][axis] = maxs[axis];\r
1638         }\r
1639 \r
1640         Brush_AddToList (b, &selected_brushes);\r
1641 \r
1642         Entity_LinkBrush (world_entity, b);\r
1643 \r
1644         Brush_Build( b );\r
1645 \r
1646         Sys_UpdateWindows (W_ALL);\r
1647 }\r
1648 \r
1649 \r
1650 \r
1651 /*\r
1652 =============\r
1653 Brush_Free\r
1654 \r
1655 Frees the brush with all of its faces and display list.\r
1656 Unlinks the brush from whichever chain it is in.\r
1657 Decrements the owner entity's brushcount.\r
1658 Removes owner entity if this was the last brush\r
1659 unless owner is the world.\r
1660 Removes from groups\r
1661 =============\r
1662 */\r
1663 void Brush_Free (brush_t *b, bool bRemoveNode)\r
1664 {\r
1665         face_t  *f, *next;\r
1666         epair_t *ep, *enext;\r
1667 \r
1668         // remove from group\r
1669         if (bRemoveNode)\r
1670                 Group_RemoveBrush(b);\r
1671 \r
1672         // free the patch if it's there\r
1673         if (b->patchBrush)\r
1674         {\r
1675                 Patch_Delete(b->pPatch);\r
1676         }\r
1677 \r
1678         // free faces\r
1679         for (f=b->brush_faces ; f ; f=next)\r
1680         {\r
1681                 next = f->next;\r
1682                 Face_Free( f );\r
1683         }\r
1684 \r
1685         // TTimo : free brush epairs\r
1686         for (ep = b->epairs ; ep ; ep=enext )\r
1687         {\r
1688                 enext = ep->next;\r
1689                 free (ep->key);\r
1690                 free (ep->value);\r
1691                 free (ep);\r
1692         }\r
1693 \r
1694         // unlink from active/selected list\r
1695         if (b->next)\r
1696                 Brush_RemoveFromList (b);\r
1697 \r
1698         // unlink from entity list\r
1699         if (b->onext)\r
1700                 Entity_UnlinkBrush (b);\r
1701 \r
1702         free (b);\r
1703 }\r
1704 \r
1705 /*\r
1706 =============\r
1707 Face_MemorySize\r
1708 =============\r
1709 */\r
1710 int Face_MemorySize(face_t *f )\r
1711 {\r
1712   int size = 0;\r
1713 \r
1714   if (f->face_winding)\r
1715   {\r
1716 //    size += _msize(f->face_winding);\r
1717     size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int);\r
1718   }\r
1719 //  size += _msize(f);\r
1720   size += sizeof(face_t);\r
1721   return size;\r
1722 }\r
1723 \r
1724 /*\r
1725 =============\r
1726 Brush_MemorySize\r
1727 =============\r
1728 */\r
1729 int Brush_MemorySize(brush_t *b)\r
1730 {\r
1731         face_t  *f;\r
1732         epair_t *ep;\r
1733         int size = 0;\r
1734 \r
1735         //\r
1736         if (b->patchBrush)\r
1737         {\r
1738                 size += Patch_MemorySize(b->pPatch);\r
1739         }\r
1740         //\r
1741         for (f = b->brush_faces; f; f = f->next)\r
1742         {\r
1743                 size += Face_MemorySize(f);\r
1744         }\r
1745         //\r
1746         for (ep = b->epairs; ep; ep = ep->next )\r
1747         {\r
1748 //              size += _msize(ep->key);\r
1749     size += strlen(ep->key);\r
1750 //              size += _msize(ep->value);\r
1751     size += strlen(ep->value);\r
1752 //              size += _msize(ep);\r
1753     size += sizeof(epair_t);\r
1754         }\r
1755 //      size += _msize(b);\r
1756   size += sizeof(brush_t);\r
1757         return size;\r
1758 }\r
1759 \r
1760 \r
1761 /*\r
1762 ============\r
1763 Brush_Clone\r
1764 \r
1765 Does NOT add the new brush to any lists\r
1766 ============\r
1767 */\r
1768 brush_t *Brush_Clone (brush_t *b)\r
1769 {\r
1770         brush_t *n = NULL;\r
1771         face_t  *f, *nf;\r
1772 \r
1773         if (b->patchBrush)\r
1774         {\r
1775                 patchMesh_t *p = Patch_Duplicate(b->pPatch);\r
1776                 Brush_RemoveFromList(p->pSymbiot);\r
1777                 Entity_UnlinkBrush(p->pSymbiot);\r
1778                 n = p->pSymbiot;\r
1779         }\r
1780         else\r
1781         {\r
1782         n = Brush_Alloc();\r
1783           n->numberId = g_nBrushId++;\r
1784                 n->owner = b->owner;\r
1785                 for (f=b->brush_faces ; f ; f=f->next)\r
1786                 {\r
1787                         nf = Face_Clone( f );\r
1788                         nf->next = n->brush_faces;\r
1789                         n->brush_faces = nf;\r
1790                 }\r
1791         }\r
1792 \r
1793         return n;\r
1794 }\r
1795 \r
1796 /*\r
1797 ============\r
1798 Brush_Clone\r
1799 \r
1800 Does NOT add the new brush to any lists\r
1801 ============\r
1802 */\r
1803 brush_t *Brush_FullClone(brush_t *b)\r
1804 {\r
1805         brush_t *n = NULL;\r
1806         face_t *f, *nf, *f2, *nf2;\r
1807         int j;\r
1808 \r
1809         if (b->patchBrush)\r
1810         {\r
1811                 patchMesh_t *p = Patch_Duplicate(b->pPatch);\r
1812                 Brush_RemoveFromList(p->pSymbiot);\r
1813                 Entity_UnlinkBrush(p->pSymbiot);\r
1814                 n = p->pSymbiot;\r
1815                 n->owner = b->owner;\r
1816                 Brush_Build(n);\r
1817         }\r
1818         else\r
1819         {\r
1820         n = Brush_Alloc();\r
1821         n->numberId = g_nBrushId++;\r
1822                 n->owner = b->owner;\r
1823                 VectorCopy(b->mins, n->mins);\r
1824                 VectorCopy(b->maxs, n->maxs);\r
1825                 //\r
1826                 for (f = b->brush_faces; f; f = f->next)\r
1827                 {\r
1828                         if (f->original) continue;\r
1829                         nf = Face_FullClone(f);\r
1830                         nf->next = n->brush_faces;\r
1831                         n->brush_faces = nf;\r
1832                         //copy all faces that have the original set to this face\r
1833                         for (f2 = b->brush_faces; f2; f2 = f2->next)\r
1834                         {\r
1835                                 if (f2->original == f)\r
1836                                 {\r
1837                                         nf2 = Face_FullClone(f2);\r
1838                                         nf2->next = n->brush_faces;\r
1839                                         n->brush_faces = nf2;\r
1840                                         //set original\r
1841                                         nf2->original = nf;\r
1842                                 }\r
1843                         }\r
1844                 }\r
1845                 for (nf = n->brush_faces; nf; nf = nf->next)\r
1846                 {\r
1847                         Face_SetColor(n, nf, 1.0);\r
1848                         if (nf->face_winding)\r
1849       {\r
1850         if (g_qeglobals.m_bBrushPrimitMode)\r
1851                         EmitBrushPrimitTextureCoordinates(nf,nf->face_winding);\r
1852         else\r
1853         {\r
1854                                   for (j = 0; j < nf->face_winding->numpoints; j++)\r
1855                                         EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf);\r
1856         }\r
1857       }\r
1858                 }\r
1859   }\r
1860         return n;\r
1861 }\r
1862 \r
1863  // FIXME - spog - finish this later..\r
1864  /*\r
1865 bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3)\r
1866 {\r
1867         int i;\r
1868         vec3_t v1, v2, normal[3];\r
1869         float d;\r
1870 \r
1871         //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]);\r
1872         //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]);\r
1873         //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]);\r
1874         //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]);\r
1875                 \r
1876         // test ray against triangle\r
1877         // get triangle plane normal\r
1878         //VectorSubtract(p1, p2, v1);\r
1879         //VectorSubtract(p1, p3, v2);\r
1880         //CrossProduct(v1, v2, v1);\r
1881         // check normal against direction\r
1882         //if (DotProduct(dir, v1) >= 0)\r
1883         //{\r
1884                 // generate cone normals\r
1885                 VectorSubtract(origin, p1, v1);\r
1886                 VectorSubtract(origin, p2, v2);\r
1887                 CrossProduct(v1, v2, normal[0]);\r
1888                 VectorSubtract(origin, p2, v1);\r
1889                 VectorSubtract(origin, p3, v2);\r
1890                 CrossProduct(v1, v2, normal[1]);\r
1891                 VectorSubtract(origin, p3, v1);\r
1892                 VectorSubtract(origin, p1, v2);\r
1893                 CrossProduct(v1, v2, normal[2]);\r
1894         //}\r
1895         //else\r
1896         //{\r
1897                 // flip normals if triangle faces away\r
1898         //      Sys_Printf("flipped\n");\r
1899         //      VectorSubtract(origin, p1, v1);\r
1900         //      VectorSubtract(origin, p3, v2);\r
1901         //      CrossProduct(v1, v2, normal[0]);\r
1902         //      VectorSubtract(origin, p3, v1);\r
1903         //      VectorSubtract(origin, p2, v2);\r
1904         //      CrossProduct(v1, v2, normal[1]);\r
1905         //      VectorSubtract(origin, p2, v1);\r
1906         //      VectorSubtract(origin, p1, v2);\r
1907         //      CrossProduct(v1, v2, normal[2]);\r
1908         //}\r
1909         \r
1910         for (i=0; i<3; i++)\r
1911         {\r
1912                 VectorNormalize(normal[i]);\r
1913                 //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]);\r
1914                 //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]);\r
1915                 d = DotProduct(dir, normal[i]);\r
1916                 //Sys_Printf("dotproduct: %f\n",d);\r
1917                 if (d < 0)\r
1918                         return false;\r
1919         }\r
1920         return true;\r
1921 }\r
1922 */\r
1923 \r
1924 /*\r
1925 extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,\r
1926                  float vert0[3], float vert1[3], float vert2[3],\r
1927                  double *t, double *u, double *v);\r
1928 \r
1929 bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v)\r
1930 {\r
1931   bool bIntersect = false;\r
1932   float tBest = FLT_MAX;\r
1933   int i, j;\r
1934   vec3_t xyz[3];\r
1935   vec3_t vRay[2];\r
1936 \r
1937   float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set\r
1938   \r
1939   VectorSubtract (origin, b->owner->origin, vRay[0]);\r
1940   VectorCopy (dir, vRay[1]);\r
1941 \r
1942   if (angle > 0)\r
1943   {\r
1944     int i;\r
1945     float s, c;\r
1946     float x, y;\r
1947 \r
1948     s = sin (-angle/180*Q_PI);\r
1949     c = cos (-angle/180*Q_PI);\r
1950 \r
1951     for (i=0; i<2; i++)\r
1952     {\r
1953       x = vRay[i][0];\r
1954       y = vRay[i][1];\r
1955       vRay[i][0] = (x * c) - (y * s);\r
1956       vRay[i][1] = (x * s) + (y * c);\r
1957     }\r
1958   }\r
1959 \r
1960   entitymodel *model = b->owner->md3Class->model;\r
1961 \r
1962   while (model != NULL)\r
1963   {\r
1964     for (i = 0; i < model->nTriCount; i++)\r
1965     {\r
1966       for (j = 0; j < 3; j++)\r
1967         VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]);\r
1968      \r
1969       if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v))\r
1970       {\r
1971         bIntersect = true;\r
1972         if (*t < tBest)\r
1973           tBest = *t;\r
1974       }\r
1975     }\r
1976     model = model->pNext;\r
1977   }\r
1978   if (bIntersect)\r
1979   {\r
1980     *t = tBest;\r
1981     return true;\r
1982   }\r
1983   else\r
1984   {\r
1985     *t = 0;\r
1986     return false;\r
1987   }\r
1988 }\r
1989 */\r
1990 \r
1991 /*\r
1992 ==============\r
1993 Brush_Ray\r
1994 \r
1995 Itersects a ray with a brush\r
1996 Returns the face hit and the distance along the ray the intersection occured at\r
1997 Returns NULL and 0 if not hit at all\r
1998 \r
1999 http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556\r
2000 ==============\r
2001 */\r
2002 extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v);\r
2003 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags)\r
2004 {\r
2005         face_t  *f, *firstface = NULL;\r
2006         vec3_t  p1, p2;\r
2007         float   frac, d1, d2;\r
2008         int             i;\r
2009 \r
2010         if (b->owner->eclass->fixedsize\r
2011     && b->owner->model.pSelect\r
2012     && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))\r
2013     && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)\r
2014         {\r
2015     ray_t ray_local;\r
2016     vec_t dist_local = FLT_MAX;\r
2017     ray_construct_for_vec3(&ray_local, origin, dir);\r
2018                 if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local))\r
2019     {\r
2020       *dist = dist_local;\r
2021       return b->brush_faces;\r
2022     }\r
2023     else\r
2024     {\r
2025       *dist = 0.0f;\r
2026       return NULL;\r
2027     }\r
2028         }\r
2029 \r
2030   VectorCopy (origin, p1);\r
2031         for (i=0 ; i<3 ; i++)\r
2032                 p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord;\r
2033 \r
2034         for (f=b->brush_faces ; f ; f=f->next)\r
2035         {\r
2036                 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;\r
2037                 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;\r
2038                 if (d1 >= 0 && d2 >= 0)\r
2039                 {\r
2040                         *dist = 0;\r
2041                         return NULL;    // ray is on front side of face\r
2042                 }\r
2043                 if (d1 <=0 && d2 <= 0)\r
2044                         continue;\r
2045                 // clip the ray to the plane\r
2046                 frac = d1 / (d1 - d2);\r
2047                 if (d1 > 0)\r
2048                 {\r
2049                         firstface = f;\r
2050                         for (i=0 ; i<3 ; i++)\r
2051                                 p1[i] = p1[i] + frac *(p2[i] - p1[i]);\r
2052                 }\r
2053                 else\r
2054                 {\r
2055                         for (i=0 ; i<3 ; i++)\r
2056                                 p2[i] = p1[i] + frac *(p2[i] - p1[i]);\r
2057                 }\r
2058         }\r
2059 \r
2060         // find distance p1 is along dir\r
2061         VectorSubtract (p1, origin, p1);\r
2062         d1 = DotProduct (p1, dir);\r
2063 \r
2064         *dist = d1;\r
2065         \r
2066         // new test stuff for patches\r
2067         if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush)\r
2068         {\r
2069     double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are\r
2070                 if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v))\r
2071                 {\r
2072                         *dist = 0;\r
2073                         return NULL;\r
2074                 }\r
2075     else\r
2076     {\r
2077       *dist = (float)t;\r
2078       //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v);\r
2079     }\r
2080         }\r
2081 \r
2082   // IMPORTANT NOTE:\r
2083   // modifications to the discarding code here should be matched in the selection code\r
2084   // see Brush_Draw  \r
2085   \r
2086   // do some last minute filtering\r
2087   if (firstface && nFlags & SF_CAMERA)\r
2088   {\r
2089     if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)\r
2090     {\r
2091       if (strstr(firstface->texdef.GetName(), "caulk"))\r
2092       {\r
2093         *dist = 0;\r
2094         return NULL;\r
2095       }\r
2096     }\r
2097     if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)\r
2098     {\r
2099       if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster"))\r
2100       {\r
2101         *dist = 0;\r
2102         return NULL;\r
2103       }\r
2104     }    \r
2105     if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)\r
2106     {\r
2107       if (strstr(firstface->texdef.GetName(), "clip"))\r
2108       {\r
2109         *dist = 0;\r
2110         return NULL;\r
2111       }\r
2112     }\r
2113   }\r
2114 \r
2115         return firstface;\r
2116 }\r
2117 \r
2118 //PGM\r
2119 face_t *Brush_Point (vec3_t origin, brush_t *b)\r
2120 {\r
2121         face_t  *f;\r
2122         float   d1;\r
2123 \r
2124         for (f=b->brush_faces ; f ; f=f->next)\r
2125         {\r
2126                 d1 = DotProduct (origin, f->plane.normal) - f->plane.dist;\r
2127                 if (d1 > 0)\r
2128                 {\r
2129                         return NULL;    // point is on front side of face\r
2130                 }\r
2131         }\r
2132 \r
2133         return b->brush_faces;\r
2134 }\r
2135 //PGM\r
2136 \r
2137 \r
2138 void    Brush_AddToList (brush_t *b, brush_t *blist)\r
2139 {\r
2140         if (b->next || b->prev)\r
2141                 Error ("Brush_AddToList: already linked");\r
2142         \r
2143         if (blist == &selected_brushes || blist == &active_brushes)\r
2144         {\r
2145                 if (b->patchBrush && blist == &selected_brushes)\r
2146                 {\r
2147                         Patch_Select(b->pPatch);\r
2148                 }\r
2149         }\r
2150         b->next = blist->next;\r
2151         blist->next->prev = b;\r
2152         blist->next = b;\r
2153         b->prev = blist;\r
2154         \r
2155         // TTimo messaging\r
2156         DispatchRadiantMsg( RADIANT_SELECTION );        \r
2157 }\r
2158 \r
2159 void    Brush_RemoveFromList (brush_t *b)\r
2160 {\r
2161         if (!b->next || !b->prev)\r
2162                 Error ("Brush_RemoveFromList: not linked");\r
2163         \r
2164         if (b->patchBrush)\r
2165         {\r
2166                 Patch_Deselect(b->pPatch);\r
2167         }\r
2168         b->next->prev = b->prev;\r
2169         b->prev->next = b->next;\r
2170         b->next = b->prev = NULL;\r
2171 }\r
2172 \r
2173 /*\r
2174 ===============\r
2175 SetFaceTexdef\r
2176 \r
2177 Doesn't set the curve flags\r
2178 \r
2179 NOTE : ( TTimo )\r
2180         never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture\r
2181         use Texture_ForName() to find the right shader\r
2182         FIXME : send the right shader ( qtexture_t * ) in the parameters ?\r
2183 \r
2184 TTimo: surface plugin, added an IPluginTexdef* parameter\r
2185                 if not NULL, get ->Copy() of it into the face ( and remember to hook )\r
2186                 if NULL, ask for a default\r
2187 \r
2188  TTimo - shader code cleanup\r
2189    added IShader* parameter\r
2190   ===============\r
2191 */\r
2192 void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {\r
2193         int             oldFlags;\r
2194         int             oldContents;\r
2195         face_t  *tf;\r
2196 \r
2197         oldFlags = f->texdef.flags;\r
2198         oldContents = f->texdef.contents;\r
2199         if (g_qeglobals.m_bBrushPrimitMode)\r
2200         {\r
2201                 f->texdef = *texdef;\r
2202                 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );\r
2203         }\r
2204         else\r
2205                 if (bFitScale)\r
2206                 {\r
2207                         f->texdef = *texdef;\r
2208                         // fit the scaling of the texture on the actual plane\r
2209                         vec3_t p1,p2,p3; // absolute coordinates\r
2210                         // compute absolute coordinates\r
2211                         ComputeAbsolute(f,p1,p2,p3);\r
2212                         // compute the scale\r
2213                         vec3_t vx,vy;\r
2214                         VectorSubtract(p2,p1,vx);\r
2215                         VectorNormalize(vx, vx);\r
2216                         VectorSubtract(p3,p1,vy);\r
2217                         VectorNormalize(vy, vy);\r
2218                         // assign scale\r
2219                         VectorScale(vx,texdef->scale[0],vx);\r
2220                         VectorScale(vy,texdef->scale[1],vy);\r
2221                         VectorAdd(p1,vx,p2);\r
2222                         VectorAdd(p1,vy,p3);\r
2223                         // compute back shift scale rot\r
2224                         AbsoluteToLocal(f->plane,f,p1,p2,p3);\r
2225                 }\r
2226                 else\r
2227                         f->texdef = *texdef;\r
2228         f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);\r
2229         f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);\r
2230 \r
2231         // if this is a curve face, set all other curve faces to the same texdef\r
2232         if (f->texdef.flags & SURF_CURVE)\r
2233         {\r
2234                 for (tf = b->brush_faces ; tf ; tf = tf->next)\r
2235                 {\r
2236                         if (tf->texdef.flags & SURF_CURVE)\r
2237                                 tf->texdef = f->texdef;\r
2238                 }\r
2239         }\r
2240 }\r
2241 \r
2242 /*\r
2243 ===============\r
2244 SetFaceTexdef\r
2245 \r
2246 Doesn't set the curve flags\r
2247   \r
2248 NOTE : ( TTimo )\r
2249         never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture\r
2250         use Texture_ForName() to find the right shader\r
2251         FIXME : send the right shader ( qtexture_t * ) in the parameters ?\r
2252  \r
2253  TTimo: surface plugin, added an IPluginTexdef* parameter\r
2254                 if not NULL, get ->Copy() of it into the face ( and remember to hook )\r
2255                 if NULL, ask for a default\r
2256 ===============\r
2257 */\r
2258 void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {\r
2259         int             oldFlags;\r
2260         int             oldContents;\r
2261  \r
2262         oldFlags = f->texdef.flags;\r
2263         oldContents = f->texdef.contents;\r
2264 \r
2265   if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build\r
2266     Face_SetShader(f, texdef->GetName());\r
2267 \r
2268         if (g_qeglobals.m_bBrushPrimitMode)\r
2269         {\r
2270                 f->texdef = *texdef;\r
2271                 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );\r
2272         }\r
2273         else\r
2274   { \r
2275                 if (bFitScale)\r
2276                 {\r
2277                         f->texdef = *texdef;\r
2278                         // fit the scaling of the texture on the actual plane\r
2279                         vec3_t p1,p2,p3; // absolute coordinates\r
2280                         // compute absolute coordinates\r
2281                         ComputeAbsolute(f,p1,p2,p3);\r
2282                         // compute the scale\r
2283                         vec3_t vx,vy;\r
2284                         VectorSubtract(p2,p1,vx);\r
2285                         VectorNormalize(vx, vx);\r
2286                         VectorSubtract(p3,p1,vy);\r
2287                         VectorNormalize(vy, vy);\r
2288                         // assign scale\r
2289                         VectorScale(vx,texdef->scale[0],vx);\r
2290                         VectorScale(vy,texdef->scale[1],vy);\r
2291                         VectorAdd(p1,vx,p2);\r
2292                         VectorAdd(p1,vy,p3);\r
2293                         // compute back shift scale rot\r
2294                         AbsoluteToLocal(f->plane,f,p1,p2,p3);\r
2295                 }\r
2296                 else\r
2297     {\r
2298                         f->texdef = *texdef;\r
2299     }\r
2300   }\r
2301         f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);\r
2302         f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);\r
2303 }\r
2304  \r
2305 #ifdef _DEBUG\r
2306 void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)\r
2307 {\r
2308         for (face_t* f = b->brush_faces ; f ; f = f->next) \r
2309                 SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef);\r
2310         Brush_Build( b );\r
2311         if (b->patchBrush)\r
2312         {\r
2313                 Patch_SetTexture(b->pPatch, texdef, pTexdef );\r
2314                 b->bFiltered = FilterBrush( b );\r
2315         }\r
2316 }\r
2317 #endif\r
2318 \r
2319 void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)\r
2320 {\r
2321         for (face_t* f = b->brush_faces ; f ; f = f->next) \r
2322                 SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef);\r
2323         Brush_Build( b );\r
2324         if (b->patchBrush)\r
2325         {\r
2326                 Patch_SetTexture(b->pPatch, texdef, pTexdef );\r
2327                 b->bFiltered = FilterBrush( b );\r
2328         }\r
2329 }\r
2330 \r
2331 \r
2332 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)\r
2333 {\r
2334         float   d1, d2, fr;\r
2335         int             i;\r
2336         float   *v;\r
2337 \r
2338         d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;\r
2339         d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;\r
2340 \r
2341         if (d1 >= 0 && d2 >= 0)\r
2342                 return false;           // totally outside\r
2343         if (d1 <= 0 && d2 <= 0)\r
2344                 return true;            // totally inside\r
2345 \r
2346         fr = d1 / (d1 - d2);\r
2347 \r
2348         if (d1 > 0)\r
2349                 v = p1;\r
2350         else\r
2351                 v = p2;\r
2352 \r
2353         for (i=0 ; i<3 ; i++)\r
2354                 v[i] = p1[i] + fr*(p2[i] - p1[i]);\r
2355 \r
2356         return true;\r
2357 }\r
2358 \r
2359 \r
2360 int AddPlanept (float *f)\r
2361 {\r
2362         int             i;\r
2363 \r
2364         for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)\r
2365                 if (g_qeglobals.d_move_points[i] == f)\r
2366                         return 0;\r
2367         g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;\r
2368         return 1;\r
2369 }\r
2370 \r
2371 /*\r
2372 ==============\r
2373 Brush_SelectFaceForDragging\r
2374 \r
2375 Adds the faces planepts to move_points, and\r
2376 rotates and adds the planepts of adjacent face if shear is set\r
2377 ==============\r
2378 */\r
2379 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)\r
2380 {\r
2381         int             i;\r
2382         face_t  *f2;\r
2383         winding_t       *w;\r
2384         float   d;\r
2385         brush_t *b2;\r
2386         int             c;\r
2387 \r
2388         if (b->owner->eclass->fixedsize)\r
2389                 return;\r
2390 \r
2391         c = 0;\r
2392         for (i=0 ; i<3 ; i++)\r
2393                 c += AddPlanept (f->planepts[i]);\r
2394         if (c == 0)\r
2395                 return;         // already completely added\r
2396 \r
2397         // select all points on this plane in all brushes the selection\r
2398         for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)\r
2399         {\r
2400                 if (b2 == b)\r
2401                         continue;\r
2402                 for (f2=b2->brush_faces ; f2 ; f2=f2->next)\r
2403                 {\r
2404                         for (i=0 ; i<3 ; i++)\r
2405                                 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)\r
2406                                 -f->plane.dist) > ON_EPSILON)\r
2407                                         break;\r
2408                         if (i==3)\r
2409                         {       // move this face as well\r
2410                                 Brush_SelectFaceForDragging (b2, f2, shear);\r
2411                                 break;\r
2412                         }\r
2413                 }\r
2414         }\r
2415 \r
2416 \r
2417         // if shearing, take all the planes adjacent to \r
2418         // selected faces and rotate their points so the\r
2419         // edge clipped by a selcted face has two of the points\r
2420         if (!shear)\r
2421                 return;\r
2422 \r
2423         for (f2=b->brush_faces ; f2 ; f2=f2->next)\r
2424         {\r
2425                 if (f2 == f)\r
2426                         continue;\r
2427                 w = Brush_MakeFaceWinding (b, f2);\r
2428                 if (!w)\r
2429                         continue;\r
2430 \r
2431                 // any points on f will become new control points\r
2432                 for (i=0 ; i<w->numpoints ; i++)\r
2433                 {\r
2434                         d = DotProduct (w->points[i], f->plane.normal) \r
2435                                 - f->plane.dist;\r
2436                         if (d > -ON_EPSILON && d < ON_EPSILON)\r
2437                                 break;\r
2438                 }\r
2439 \r
2440                 //\r
2441                 // if none of the points were on the plane,\r
2442                 // leave it alone\r
2443                 //\r
2444                 if (i != w->numpoints)\r
2445                 {\r
2446                         if (i == 0)\r
2447                         {       // see if the first clockwise point was the\r
2448                                 // last point on the winding\r
2449                                 d = DotProduct (w->points[w->numpoints-1]\r
2450                                         , f->plane.normal) - f->plane.dist;\r
2451                                 if (d > -ON_EPSILON && d < ON_EPSILON)\r
2452                                         i = w->numpoints - 1;\r
2453                         }\r
2454 \r
2455                         AddPlanept (f2->planepts[0]);\r
2456 \r
2457                         VectorCopy (w->points[i], f2->planepts[0]);\r
2458                         if (++i == w->numpoints)\r
2459                                 i = 0;\r
2460                         \r
2461                         // see if the next point is also on the plane\r
2462                         d = DotProduct (w->points[i]\r
2463                                 , f->plane.normal) - f->plane.dist;\r
2464                         if (d > -ON_EPSILON && d < ON_EPSILON)\r
2465                                 AddPlanept (f2->planepts[1]);\r
2466 \r
2467                         VectorCopy (w->points[i], f2->planepts[1]);\r
2468                         if (++i == w->numpoints)\r
2469                                 i = 0;\r
2470 \r
2471                         // the third point is never on the plane\r
2472 \r
2473                         VectorCopy (w->points[i], f2->planepts[2]);\r
2474                 }\r
2475 \r
2476                 free(w);\r
2477         }\r
2478 }\r
2479 \r
2480 /*\r
2481 ==============\r
2482 Brush_SideSelect\r
2483 \r
2484 The mouse click did not hit the brush, so grab one or more side\r
2485 planes for dragging\r
2486 ==============\r
2487 */\r
2488 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir\r
2489                                            , qboolean shear)\r
2490 {\r
2491         face_t  *f, *f2;\r
2492         vec3_t  p1, p2;\r
2493 \r
2494         for (f=b->brush_faces ; f ; f=f->next)\r
2495         {\r
2496                 VectorCopy (origin, p1);\r
2497                 VectorMA (origin, 2*g_MaxWorldCoord, dir, p2);\r
2498 \r
2499                 for (f2=b->brush_faces ; f2 ; f2=f2->next)\r
2500                 {\r
2501                         if (f2 == f)\r
2502                                 continue;\r
2503                         ClipLineToFace (p1, p2, f2);\r
2504                 }\r
2505 \r
2506                 if (f2)\r
2507                         continue;\r
2508 \r
2509                 if (VectorCompare (p1, origin))\r
2510                         continue;\r
2511                 if (ClipLineToFace (p1, p2, f))\r
2512                         continue;\r
2513 \r
2514                 Brush_SelectFaceForDragging (b, f, shear);\r
2515         }       \r
2516 }\r
2517 \r
2518 bool g_bBuildWindingsNoTexBuild = false;\r
2519 \r
2520 void Brush_SetBuildWindingsNoTexBuild(bool bBuild)\r
2521 {\r
2522   g_bBuildWindingsNoTexBuild = bBuild;\r
2523 }\r
2524 \r
2525 // TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary\r
2526 //    saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases\r
2527 //    ie when we want to update a shader\r
2528 //    default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild\r
2529 void Brush_BuildWindings( brush_t *b, bool bSnap )\r
2530 {\r
2531         winding_t *w;\r
2532         face_t    *face;\r
2533         vec_t      v;\r
2534 \r
2535         if (bSnap)\r
2536                 Brush_SnapPlanepts( b );\r
2537 \r
2538         // clear the mins/maxs bounds\r
2539         b->mins[0] = b->mins[1] = b->mins[2] = 99999;\r
2540         b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;\r
2541 \r
2542         Brush_MakeFacePlanes (b);\r
2543 \r
2544         face = b->brush_faces;\r
2545 \r
2546         float fCurveColor = 1.0;\r
2547 \r
2548         for ( ; face ; face=face->next)\r
2549         {\r
2550                 int i, j;\r
2551                 free(face->face_winding);\r
2552                 w = face->face_winding = Brush_MakeFaceWinding (b, face);\r
2553 \r
2554     if (!g_bBuildWindingsNoTexBuild || !face->d_texture)\r
2555     {\r
2556 #ifdef _DEBUG\r
2557       // if there's no d_texture, then we expect pShader to be empty\r
2558       if (!face->d_texture && face->pShader)\r
2559         Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n");\r
2560 #endif\r
2561       if ((!face->d_texture && !face->pShader) || !face->pShader)\r
2562       {\r
2563         // NOTE TTimo\r
2564         // patch 84 for bug 253 doesn't dec ref the potential face->pShader\r
2565         // add a debug check to make sure this is actually not necessary\r
2566 #ifdef _DEBUG\r
2567         if (face->pShader)\r
2568         {\r
2569           Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n");\r
2570         }\r
2571 #endif\r
2572         face->pShader = QERApp_Shader_ForName( face->texdef.GetName() );\r
2573         face->pShader->IncRef();\r
2574         face->d_texture = face->pShader->getTexture();\r
2575       }\r
2576     }\r
2577 \r
2578                 if (!w)\r
2579                         continue;\r
2580         \r
2581                 for (i=0 ; i<w->numpoints ; i++)\r
2582                 {\r
2583                         // add to bounding box\r
2584                         for (j=0 ; j<3 ; j++)\r
2585                         {\r
2586                                 v = w->points[i][j];\r
2587                                 if (v > b->maxs[j])\r
2588                                         b->maxs[j] = v;\r
2589                                 if (v < b->mins[j])\r
2590                                         b->mins[j] = v;\r
2591                         }\r
2592                 }\r
2593                 Face_SetColor (b, face, fCurveColor);\r
2594 \r
2595                 fCurveColor -= .10f;\r
2596                 if (fCurveColor <= 0)\r
2597                         fCurveColor = 1.0f;\r
2598 \r
2599                 // computing ST coordinates for the windings\r
2600                 if (g_qeglobals.m_bBrushPrimitMode)\r
2601                 {\r
2602                         if (g_qeglobals.bNeedConvert)\r
2603                         {\r
2604                                 // we have parsed old brushes format and need conversion\r
2605                                 // convert old brush texture representation to new format\r
2606                                 FaceToBrushPrimitFace(face);\r
2607 #ifdef _DEBUG\r
2608                                 // use old texture coordinates code to check against\r
2609                             for (i=0 ; i<w->numpoints ; i++)\r
2610                                         EmitTextureCoordinates( w->points[i], face->d_texture, face);\r
2611 #endif\r
2612                         }\r
2613                         // use new texture representation to compute texture coordinates\r
2614                         // in debug mode we will check against old code and warn if there are differences\r
2615                         EmitBrushPrimitTextureCoordinates(face,w);\r
2616                 }\r
2617                 else\r
2618                 {\r
2619       if (g_qeglobals.bNeedConvert)\r
2620       {\r
2621         BrushPrimitFaceToFace(face);\r
2622 /*\r
2623         // we have parsed brush primitives and need conversion back to standard format\r
2624         // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it\r
2625                                 // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling\r
2626                                 // I tried various tweaks, no luck .. seems shifting is lost\r
2627         brushprimit_texdef_t aux;\r
2628         ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );\r
2629         TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );\r
2630                                 face->texdef.scale[0]/=2.0;\r
2631                                 face->texdef.scale[1]/=2.0;\r
2632 */\r
2633       }\r
2634                     for (i=0 ; i<w->numpoints ; i++)\r
2635                                 EmitTextureCoordinates( w->points[i], face->d_texture, face);\r
2636                 }\r
2637         }\r
2638 }\r
2639 \r
2640 /*\r
2641 ==================\r
2642 Brush_RemoveEmptyFaces\r
2643 \r
2644 Frees any overconstraining faces\r
2645 ==================\r
2646 */\r
2647 void Brush_RemoveEmptyFaces ( brush_t *b )\r
2648 {\r
2649         face_t  *f, *next;\r
2650 \r
2651         f = b->brush_faces;\r
2652         b->brush_faces = NULL;\r
2653 \r
2654         for ( ; f ; f=next)\r
2655         {\r
2656                 next = f->next;\r
2657                 if (!f->face_winding)\r
2658                         Face_Free (f);\r
2659                 else\r
2660                 {\r
2661                         f->next = b->brush_faces;\r
2662                         b->brush_faces = f;\r
2663                 }\r
2664 \r
2665         }\r
2666 }\r
2667 \r
2668 void Brush_SnapToGrid(brush_t *pb)\r
2669 {\r
2670         face_t *f;\r
2671         vec3_t temp;\r
2672         vec3_t diff[2];\r
2673         int mult[3];\r
2674         int i, j, n;\r
2675         // TTimo: some brushes are "special" and should not be snapped\r
2676         // specially fixed-size entity ones\r
2677         if (pb->owner->eclass->fixedsize)\r
2678         {\r
2679                 // save current origin\r
2680                 VectorCopy (pb->owner->origin, temp);\r
2681                 // snap the origin\r
2682                 VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize);\r
2683                 // return if amount is zero\r
2684                 if (VectorCompare (pb->owner->origin, temp))\r
2685                         return;\r
2686                 // transform brush faces same amount\r
2687                 VectorSubtract (pb->owner->origin, temp, temp);\r
2688                 for (f = pb->brush_faces; f; f = f->next)\r
2689                 {\r
2690                         for (i=0 ; i<3 ; i++)\r
2691                                 VectorAdd (f->planepts[i], temp, f->planepts[i]);\r
2692                 }\r
2693         }\r
2694         else\r
2695         {\r
2696                 for (f = pb->brush_faces ; f; f = f->next)\r
2697                 {\r
2698                         for (j=0; j<2; j++)\r
2699                         {\r
2700                                 // spog - move planepts apart just far enough to avoid snapping two together\r
2701                                 VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]);\r
2702                                 for (i=0; i<3; i++)\r
2703                                 {\r
2704                                         if (diff[j][i] == 0.0f)\r
2705                                                 mult[i] = 2; // next value up from 1\r
2706                                         else  // multiplier = gridsize / component difference, rounded up\r
2707                                                 mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i]));\r
2708                                 }\r
2709                                 \r
2710                                 if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1\r
2711                                 {\r
2712                                         n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2;\r
2713                                         for (i=0; i<3; i++)\r
2714                                                 diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component\r
2715                                 }\r
2716                                 VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]);\r
2717                         }\r
2718 \r
2719                         for (i=0; i<3; i++)\r
2720                                 VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize);\r
2721 \r
2722                 }\r
2723         }\r
2724         Brush_Build(pb,true,true,false,false); // don't filter\r
2725 }\r
2726 \r
2727 void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild)\r
2728 {\r
2729         for (face_t* f=b->brush_faces ; f ; f=f->next)\r
2730         {\r
2731                 for (int i=0 ; i<3 ; i++)\r
2732                 {\r
2733                         VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]);\r
2734                 }\r
2735         }\r
2736         if (bBuild)\r
2737         {\r
2738                 Brush_Build(b,false,false,false,false); // don't filter\r
2739         }\r
2740 }\r
2741 \r
2742 void Brush_Center(brush_t *b, vec3_t vNewCenter)\r
2743 {\r
2744   vec3_t vMid;\r
2745   // get center of the brush\r
2746   for (int j = 0; j < 3; j++)\r
2747   {\r
2748     vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5);\r
2749   }\r
2750   // calc distance between centers\r
2751   VectorSubtract(vNewCenter, vMid, vMid);\r
2752   Brush_Move(b, vMid, true);\r
2753 \r
2754 }\r
2755 \r
2756 void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax)\r
2757 {\r
2758   face_t *f;\r
2759   texdef_t texdef;\r
2760   int i;\r
2761   short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };\r
2762 \r
2763   for (i=0 ; i<3 ; i++)\r
2764                 if (vMax[i] < vMin[i])\r
2765                         Error ("Brush_Resize: invalid input");\r
2766 \r
2767   if(b->brush_faces != NULL)\r
2768     texdef = b->brush_faces->texdef;\r
2769   else\r
2770     texdef = g_qeglobals.d_texturewin.texdef;\r
2771 \r
2772   while (b->brush_faces != NULL)\r
2773   {\r
2774     f = b->brush_faces->next;\r
2775     Face_Free(b->brush_faces);\r
2776     b->brush_faces = f;\r
2777   }\r
2778 \r
2779   for(i=0; i<3; i++)\r
2780   {\r
2781     f = b->brush_faces;\r
2782     b->brush_faces = Face_Alloc();\r
2783     b->brush_faces->next = f;\r
2784     f = b->brush_faces;\r
2785     f->texdef = texdef;\r
2786     VectorCopy(vMax, f->planepts[0]);\r
2787     VectorCopy(vMax, f->planepts[1]);\r
2788     VectorCopy(vMax, f->planepts[2]);\r
2789     f->planepts[2][box[i][0]] = vMin[box[i][0]];\r
2790     f->planepts[1][box[i][1]] = vMin[box[i][1]];\r
2791   }\r
2792   for(i=0; i<3; i++)\r
2793   {\r
2794     f = b->brush_faces;\r
2795     b->brush_faces = Face_Alloc();\r
2796     b->brush_faces->next = f;\r
2797     f = b->brush_faces;\r
2798     f->texdef = texdef;\r
2799     VectorCopy(vMin, f->planepts[0]);\r
2800     VectorCopy(vMin, f->planepts[1]);\r
2801     VectorCopy(vMin, f->planepts[2]);\r
2802     f->planepts[1][box[i][0]] = vMax[box[i][0]];\r
2803     f->planepts[2][box[i][1]] = vMax[box[i][1]];\r
2804   }\r
2805 }\r
2806 \r
2807 void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up)\r
2808 {\r
2809         int                     angleVal;\r
2810         vec3_t          angles;\r
2811 \r
2812         angleVal = IntForKey(e, "angle");\r
2813         if (angleVal == -1)                             // up\r
2814         {\r
2815                 VectorSet(angles, 270, 0, 0);\r
2816         }\r
2817         else if(angleVal == -2)         // down\r
2818         {\r
2819                 VectorSet(angles, 90, 0, 0);\r
2820         }\r
2821         else\r
2822         {\r
2823                 VectorSet(angles, 0, angleVal, 0);\r
2824         }\r
2825 \r
2826         AngleVectors(angles, forward, right, up);\r
2827 }\r
2828 \r
2829 void Brush_DrawFacingAngle (brush_t *b, entity_t *e)\r
2830 {\r
2831         vec3_t  forward, right, up;\r
2832         vec3_t  endpoint, tip1, tip2;\r
2833         vec3_t  start;\r
2834         float   dist;\r
2835 \r
2836         VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);\r
2837         VectorScale(start, 0.5, start);\r
2838         dist = (b->maxs[0] - start[0]) * 2.5;\r
2839 \r
2840         FacingVectors (e, forward, right, up);\r
2841         VectorMA (start, dist, forward, endpoint);\r
2842 \r
2843         dist = (b->maxs[0] - start[0]) * 0.5;\r
2844         VectorMA (endpoint, -dist, forward, tip1);\r
2845         VectorMA (tip1, -dist, up, tip1);\r
2846         VectorMA (tip1, 2*dist, up, tip2);\r
2847 \r
2848         qglColor4f (1, 1, 1, 1);\r
2849         qglLineWidth (4);\r
2850         qglBegin (GL_LINES);\r
2851         qglVertex3fv (start);\r
2852         qglVertex3fv (endpoint);\r
2853         qglVertex3fv (endpoint);\r
2854         qglVertex3fv (tip1);\r
2855         qglVertex3fv (endpoint);\r
2856         qglVertex3fv (tip2);\r
2857         qglEnd ();\r
2858         qglLineWidth (1);\r
2859 }\r
2860 \r
2861 void Brush_FaceDraw(face_t *face, int nGLState)\r
2862 {\r
2863         const winding_t *w = face->face_winding;\r
2864   if (w == NULL) return;\r
2865   if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting)\r
2866                 qglNormal3fv(face->plane.normal);\r
2867   /*\r
2868         if (mode & DRAW_GL_TEXTURE_2D)\r
2869                 qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]);\r
2870         qglVertexPointer(3, GL_FLOAT, 5, w->points);\r
2871 \r
2872         if (mode & DRAW_GL_FILL)\r
2873                 qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints);\r
2874         else\r
2875                 qglDrawArrays(GL_POLYGON, 0, w->numpoints);\r
2876   */\r
2877 \r
2878   if (nGLState & DRAW_GL_FILL)\r
2879     qglBegin(GL_TRIANGLE_FAN);\r
2880   else\r
2881     qglBegin(GL_POLYGON);\r
2882         \r
2883         for (int i=0 ; i<w->numpoints ; i++)\r
2884         {\r
2885                 if (nGLState & DRAW_GL_TEXTURE_2D)\r
2886                         qglTexCoord2fv( &w->points[i][3] );\r
2887                 qglVertex3fv(w->points[i]);\r
2888         }\r
2889         qglEnd();\r
2890 }\r
2891 \r
2892 void Brush_Draw(brush_t *b)\r
2893 {\r
2894         face_t                  *face;\r
2895         int                             order;\r
2896         qtexture_t              *prev = 0;\r
2897         winding_t *w;\r
2898 \r
2899         int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode;\r
2900   int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate;\r
2901 \r
2902         GLfloat material[4], identity[4];\r
2903         VectorSet(identity, 0.8f, 0.8f, 0.8f);\r
2904         IShader *pShader;\r
2905         qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);\r
2906         qglDisableClientState(GL_NORMAL_ARRAY);\r
2907 \r
2908   // guarantee the texture will be set first\r
2909   bool bTrans;\r
2910         prev = NULL;\r
2911         for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)\r
2912         {\r
2913                 w = face->face_winding;\r
2914                 if (!w)\r
2915                 {\r
2916                         continue;               // freed face\r
2917                 }\r
2918 \r
2919      bTrans = (face->pShader->getFlags() & QER_TRANS);\r
2920 \r
2921           if (bTrans && !(nGLState & DRAW_GL_BLEND))\r
2922       continue;\r
2923     if (!bTrans && nGLState & DRAW_GL_BLEND)\r
2924       continue;\r
2925                 \r
2926                 // IMPORTANT NOTE:\r
2927                 // modifications to the discarding code here should be matched in the selection code\r
2928                 // see Brush_Ray\r
2929 \r
2930                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)\r
2931                 {\r
2932                         if (strstr(face->texdef.GetName(), "caulk"))\r
2933                                 continue;\r
2934                 }\r
2935 \r
2936                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)\r
2937                 {\r
2938                         if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster"))\r
2939                                 continue;\r
2940                 }\r
2941 \r
2942                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)\r
2943                 {\r
2944                         if (strstr(face->texdef.GetName(), "clip"))\r
2945                                 continue;\r
2946     }\r
2947 \r
2948     if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(')\r
2949     {\r
2950       prev = NULL;\r
2951       qglDisable(GL_TEXTURE_2D);\r
2952     }\r
2953     else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev)\r
2954     {\r
2955       // set the texture for this face\r
2956       prev = face->d_texture;\r
2957       qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );\r
2958     }\r
2959     \r
2960     if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting)\r
2961     {\r
2962       if (!b->owner->eclass->fixedsize)\r
2963         material[3] = face->pShader->getTrans();\r
2964       else\r
2965         material[3] = 1;\r
2966       VectorCopy(face->d_color, material);\r
2967 \r
2968                         if (nGLState & DRAW_GL_TEXTURE_2D)\r
2969         qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]);\r
2970                         else\r
2971         qglColor4fv(material);\r
2972     }\r
2973     else if (!b->owner->eclass->fixedsize)\r
2974                 {\r
2975                         pShader = face->pShader;\r
2976                         VectorCopy(pShader->getTexture()->color, material);\r
2977                         material[3] = identity[3] = pShader->getTrans();\r
2978 \r
2979                         if (nGLState & DRAW_GL_TEXTURE_2D)\r
2980         qglColor4fv(identity);\r
2981                         else\r
2982         qglColor4fv(material);\r
2983                 }\r
2984     \r
2985                 // draw the polygon\r
2986 \r
2987                 Brush_FaceDraw(face, nGLState);\r
2988         }\r
2989         qglPopClientAttrib();\r
2990 }\r
2991 \r
2992 void Face_Draw( face_t *f )\r
2993 {\r
2994         int i;\r
2995 \r
2996         if ( f->face_winding == 0 )\r
2997                 return;\r
2998         qglBegin(GL_POLYGON);\r
2999         for ( i = 0 ; i < f->face_winding->numpoints; i++)\r
3000                 qglVertex3fv( f->face_winding->points[i] );\r
3001         qglEnd();\r
3002 }\r
3003 \r
3004 entity_t *FindEntity(const char *pszKey, const char *pszValue)\r
3005 {\r
3006         entity_t *pe;\r
3007         \r
3008         pe = entities.next;\r
3009         \r
3010         for (; pe != NULL && pe != &entities ; pe = pe->next)\r
3011         {\r
3012                 if (!strcmp(ValueForKey(pe, pszKey), pszValue))\r
3013                         return pe;\r
3014         }\r
3015 \r
3016         return NULL;\r
3017 }\r
3018 \r
3019 void Brush_DrawXY(brush_t *b, int nViewType)\r
3020 {\r
3021         face_t *face;\r
3022         int     order;\r
3023         winding_t *w;\r
3024         int        i;\r
3025 \r
3026   if (b->patchBrush)\r
3027   {\r
3028     Patch_DrawXY(b->pPatch);\r
3029     if (!g_bPatchShowBounds)\r
3030       return;\r
3031   }                     \r
3032 \r
3033   if (b->owner->eclass->fixedsize)\r
3034   {\r
3035     if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))\r
3036     {\r
3037 #if 1 // requires vertex arrays enabled\r
3038       DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType);\r
3039 #else\r
3040       vec3_t vCorners[4];\r
3041       float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;\r
3042 \r
3043       vCorners[0][0] = b->mins[0];\r
3044       vCorners[0][1] = b->mins[1];\r
3045       vCorners[0][2] = fMid;\r
3046 \r
3047       vCorners[1][0] = b->mins[0];\r
3048       vCorners[1][1] = b->maxs[1];\r
3049       vCorners[1][2] = fMid;\r
3050 \r
3051       vCorners[2][0] = b->maxs[0];\r
3052       vCorners[2][1] = b->maxs[1];\r
3053       vCorners[2][2] = fMid;\r
3054 \r
3055       vCorners[3][0] = b->maxs[0];\r
3056       vCorners[3][1] = b->mins[1];\r
3057       vCorners[3][2] = fMid;\r
3058 \r
3059       vec3_t vTop, vBottom;\r
3060 \r
3061       vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);\r
3062       vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);\r
3063       vTop[2] = b->maxs[2];\r
3064 \r
3065       VectorCopy(vTop, vBottom);\r
3066       vBottom[2] = b->mins[2];\r
3067 \r
3068       qglBegin(GL_LINES);\r
3069       qglVertex3fv(vTop);\r
3070       qglVertex3fv(vCorners[0]);\r
3071       qglVertex3fv(vTop);\r
3072       qglVertex3fv(vCorners[1]);\r
3073       qglVertex3fv(vTop);\r
3074       qglVertex3fv(vCorners[2]);\r
3075       qglVertex3fv(vTop);\r
3076       qglVertex3fv(vCorners[3]);\r
3077       qglEnd();\r
3078 \r
3079       qglBegin(GL_LINES);\r
3080       qglVertex3fv(vBottom);\r
3081       qglVertex3fv(vCorners[0]);\r
3082       qglVertex3fv(vBottom);\r
3083       qglVertex3fv(vCorners[1]);\r
3084       qglVertex3fv(vBottom);\r
3085       qglVertex3fv(vCorners[2]);\r
3086       qglVertex3fv(vBottom);\r
3087       qglVertex3fv(vCorners[3]);\r
3088       qglEnd();\r
3089 \r
3090       qglBegin(GL_LINE_LOOP);\r
3091       qglVertex3fv(vCorners[0]);\r
3092       qglVertex3fv(vCorners[1]);\r
3093       qglVertex3fv(vCorners[2]);\r
3094       qglVertex3fv(vCorners[3]);\r
3095       qglEnd();\r
3096 #endif\r
3097       DrawBrushEntityName (b);\r
3098       return;\r
3099     }\r
3100     else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)))\r
3101     {\r
3102       qglPushAttrib(GL_CURRENT_BIT); // save brush colour\r
3103       qglColor3fv(b->owner->eclass->color);\r
3104       if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX )\r
3105         b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY);\r
3106       aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);\r
3107       qglPopAttrib();\r
3108       return;\r
3109     }\r
3110     //}\r
3111   }\r
3112 \r
3113         for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)\r
3114         {\r
3115                 // moved so check occurs earlier\r
3116                 w = face->face_winding;\r
3117                 if (!w)\r
3118                         continue;\r
3119                 // only draw polygons facing in a direction we care about\r
3120     if (nViewType == XY)\r
3121     {\r
3122                   if (face->plane.normal[2] <= 0)\r
3123                           continue;\r
3124     }\r
3125     else\r
3126     {\r
3127       if (nViewType == XZ)\r
3128       {\r
3129         if (face->plane.normal[1] >= 0) // stop axes being mirrored\r
3130           continue;\r
3131       }\r
3132       else \r
3133       {\r
3134         if (face->plane.normal[0] <= 0)\r
3135           continue;\r
3136       }\r
3137     }\r
3138 \r
3139                 // draw the polygon\r
3140                 qglBegin(GL_LINE_LOOP);\r
3141     for (i=0 ; i<w->numpoints ; i++)\r
3142                   qglVertex3fv(w->points[i]);\r
3143                 qglEnd();\r
3144         }\r
3145 \r
3146         DrawBrushEntityName (b);\r
3147 \r
3148 }\r
3149 \r
3150 /*\r
3151 ============\r
3152 Brush_Move\r
3153 ============\r
3154 */\r
3155 void Brush_Move (brush_t *b, const vec3_t move, bool bSnap)\r
3156 {\r
3157   int i;\r
3158   face_t *f;\r
3159 \r
3160   for (f=b->brush_faces ; f ; f=f->next)\r
3161     for (i=0 ; i<3 ; i++)\r
3162       VectorAdd (f->planepts[i], move, f->planepts[i]);\r
3163 \r
3164   if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize)\r
3165   {\r
3166     for (f=b->brush_faces ; f ; f=f->next)\r
3167     {\r
3168       vec3_t vTemp;\r
3169       VectorCopy(move, vTemp);\r
3170       Face_MoveTexture(f, vTemp);\r
3171     }\r
3172   }\r
3173 \r
3174   Brush_Build( b, bSnap,true,false,false); // don't filter\r
3175 \r
3176 \r
3177   if (b->patchBrush)\r
3178   {\r
3179     //Patch_Move(b->nPatchID, move);\r
3180     Patch_Move(b->pPatch, move);\r
3181   }\r
3182 \r
3183 \r
3184   // PGM - keep the origin vector up to date on fixed size entities.\r
3185   if(b->owner->eclass->fixedsize)\r
3186   {\r
3187     char text[64];\r
3188     VectorAdd(b->owner->origin, move, b->owner->origin);\r
3189     sprintf (text, "%i %i %i",\r
3190       (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);\r
3191     SetKeyValue(b->owner, "origin", text);\r
3192           //VectorAdd(b->maxs, b->mins, b->owner->origin);\r
3193           //VectorScale(b->owner->origin, 0.5, b->owner->origin);\r
3194   }\r
3195 }\r
3196 \r
3197 \r
3198 \r
3199 void Brush_Print(brush_t* b)\r
3200 {\r
3201   int nFace = 0;\r
3202   for (face_t* f = b->brush_faces ; f ; f=f->next)\r
3203   {\r
3204     Sys_Printf("Face %i\n", nFace++);\r
3205     Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);\r
3206     Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);\r
3207     Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);\r
3208   }\r
3209  }\r
3210 \r
3211 \r
3212 \r
3213 /*\r
3214 =============\r
3215 Brush_MakeSided\r
3216 \r
3217 Makes the current brushhave the given number of 2d sides and turns it into a cone\r
3218 =============\r
3219 */\r
3220 void Brush_MakeSidedCone(int sides)\r
3221 {\r
3222         int             i;\r
3223         vec3_t  mins, maxs;\r
3224         brush_t *b;\r
3225         texdef_t        *texdef;\r
3226         face_t  *f;\r
3227         vec3_t  mid;\r
3228         float   width;\r
3229         float   sv, cv;\r
3230 \r
3231         if (sides < 3 || sides > 32)\r
3232         {\r
3233                 Sys_Status ("Bad sides number", 0);\r
3234                 return;\r
3235         }\r
3236 \r
3237         if (!QE_SingleBrush ())\r
3238         {\r
3239                 Sys_Status ("Must have a single brush selected", 0 );\r
3240                 return;\r
3241         }\r
3242 \r
3243         b = selected_brushes.next;\r
3244         VectorCopy (b->mins, mins);\r
3245         VectorCopy (b->maxs, maxs);\r
3246         texdef = &g_qeglobals.d_texturewin.texdef;\r
3247 \r
3248         Brush_Free (b);\r
3249 \r
3250         // find center of brush\r
3251         width = 8;\r
3252         for (i=0 ; i<2 ; i++)\r
3253         {\r
3254                 mid[i] = (maxs[i] + mins[i])*0.5;\r
3255                 if (maxs[i] - mins[i] > width)\r
3256                         width = maxs[i] - mins[i];\r
3257         }\r
3258         width /= 2;\r
3259 \r
3260         b = Brush_Alloc();\r
3261 \r
3262         // create bottom face\r
3263         f = Face_Alloc();\r
3264         f->texdef = *texdef;\r
3265         f->next = b->brush_faces;\r
3266         b->brush_faces = f;\r
3267 \r
3268         f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];\r
3269         f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];\r
3270         f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];\r
3271 \r
3272         for (i=0 ; i<sides ; i++)\r
3273         {\r
3274                 f = Face_Alloc();\r
3275                 f->texdef = *texdef;\r
3276                 f->next = b->brush_faces;\r
3277                 b->brush_faces = f;\r
3278 \r
3279                 sv = sin (i*3.14159265*2/sides);\r
3280                 cv = cos (i*3.14159265*2/sides);\r
3281 \r
3282 \r
3283                 f->planepts[0][0] = floor(mid[0]+width*cv+0.5);\r
3284                 f->planepts[0][1] = floor(mid[1]+width*sv+0.5);\r
3285                 f->planepts[0][2] = mins[2];\r
3286 \r
3287                 f->planepts[1][0] = mid[0];\r
3288                 f->planepts[1][1] = mid[1];\r
3289                 f->planepts[1][2] = maxs[2];\r
3290 \r
3291                 f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5);\r
3292                 f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5);\r
3293                 f->planepts[2][2] = maxs[2];\r
3294 \r
3295         }\r
3296 \r
3297         Brush_AddToList (b, &selected_brushes);\r
3298 \r
3299         Entity_LinkBrush (world_entity, b);\r
3300 \r
3301         Brush_Build( b );\r
3302 \r
3303         Sys_UpdateWindows (W_ALL);\r
3304 }\r
3305 \r
3306 /*\r
3307 =============\r
3308 Brush_MakeSided\r
3309 \r
3310 Makes the current brushhave the given number of 2d sides and turns it into a sphere\r
3311 =============\r
3312 \r
3313 */\r
3314 void Brush_MakeSidedSphere(int sides)\r
3315 {\r
3316         int             i,j;\r
3317         vec3_t  mins, maxs;\r
3318         brush_t *b;\r
3319         texdef_t        *texdef;\r
3320         face_t  *f;\r
3321         vec3_t  mid;\r
3322 \r
3323         if (sides < 4 || sides > 32)\r
3324         {\r
3325                 Sys_Status ("Bad sides number", 0);\r
3326                 return;\r
3327         }\r
3328 \r
3329         if (!QE_SingleBrush ())\r
3330         {\r
3331                 Sys_Status ("Must have a single brush selected", 0 );\r
3332                 return;\r
3333         }\r
3334 \r
3335         b = selected_brushes.next;\r
3336         VectorCopy (b->mins, mins);\r
3337         VectorCopy (b->maxs, maxs);\r
3338         texdef = &g_qeglobals.d_texturewin.texdef;\r
3339 \r
3340         Brush_Free (b);\r
3341 \r
3342         // find center of brush\r
3343         float radius = 8;\r
3344         for (i=0 ; i<2 ; i++)\r
3345         {\r
3346                 mid[i] = (maxs[i] + mins[i])*0.5;\r
3347                 if (maxs[i] - mins[i] > radius)\r
3348                         radius = maxs[i] - mins[i];\r
3349         }\r
3350         radius /= 2;\r
3351 \r
3352         b = Brush_Alloc();\r
3353 \r
3354         float dt = float(2 * Q_PI / sides);\r
3355         float dp = float(Q_PI / sides);\r
3356   float t,p;\r
3357         for(i=0; i <= sides-1; i++)\r
3358   {\r
3359                 for(j=0;j <= sides-2; j++)\r
3360                 {\r
3361                         t = i * dt;\r
3362                         p = float(j * dp - Q_PI / 2);\r
3363 \r
3364       f = Face_Alloc();\r
3365             f->texdef = *texdef;\r
3366             f->next = b->brush_faces;\r
3367             b->brush_faces = f;\r
3368 \r
3369       VectorPolar(f->planepts[0], radius, t, p);\r
3370       VectorPolar(f->planepts[1], radius, t, p + dp);\r
3371       VectorPolar(f->planepts[2], radius, t + dt, p + dp);\r
3372 \r
3373       for (int k = 0; k < 3; k++)\r
3374         VectorAdd(f->planepts[k], mid, f->planepts[k]);\r
3375                 }\r
3376   }\r
3377 \r
3378   p = float((sides - 1) * dp - Q_PI / 2);\r
3379         for(i = 0; i <= sides-1; i++)\r
3380         {\r
3381                 t = i * dt;\r
3382 \r
3383     f = Face_Alloc();\r
3384           f->texdef = *texdef;\r
3385           f->next = b->brush_faces;\r
3386           b->brush_faces = f;\r
3387 \r
3388     VectorPolar(f->planepts[0], radius, t, p);\r
3389     VectorPolar(f->planepts[1], radius, t + dt, p + dp);\r
3390     VectorPolar(f->planepts[2], radius, t + dt, p);\r
3391 \r
3392     for (int k = 0; k < 3; k++)\r
3393       VectorAdd(f->planepts[k], mid, f->planepts[k]);\r
3394         }\r
3395 \r
3396         Brush_AddToList (b, &selected_brushes);\r
3397 \r
3398         Entity_LinkBrush (world_entity, b);\r
3399 \r
3400         Brush_Build( b );\r
3401 \r
3402         Sys_UpdateWindows (W_ALL);\r
3403 }\r
3404 \r
3405 void Face_FitTexture( face_t * face, int nHeight, int nWidth )\r
3406 {\r
3407   winding_t *w;\r
3408   vec3_t   mins,maxs;\r
3409   int i;\r
3410   float width, height, temp;\r
3411   float rot_width, rot_height;\r
3412   float cosv,sinv,ang;\r
3413   float min_t, min_s, max_t, max_s;\r
3414   float s,t;\r
3415   vec3_t        vecs[2];\r
3416   vec3_t   coords[4];\r
3417   texdef_t      *td;\r
3418   \r
3419   if (nHeight < 1)\r
3420     nHeight = 1;\r
3421   if (nWidth < 1)\r
3422     nWidth = 1;\r
3423   \r
3424   ClearBounds (mins, maxs);\r
3425   \r
3426   w = face->face_winding;\r
3427   if (!w)\r
3428   {\r
3429     return;\r
3430   }\r
3431   for (i=0 ; i<w->numpoints ; i++)\r
3432   {\r
3433     AddPointToBounds( w->points[i], mins, maxs );\r
3434   }\r
3435   \r
3436   if (g_qeglobals.m_bBrushPrimitMode)\r
3437     Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth );\r
3438   else\r
3439   {\r
3440     \r
3441     td = &face->texdef;\r
3442     //\r
3443     // get the current angle\r
3444     //\r
3445     ang = td->rotate / 180 * Q_PI;\r
3446     sinv = sin(ang);\r
3447     cosv = cos(ang);\r
3448     \r
3449     // get natural texture axis\r
3450     TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]);\r
3451     \r
3452     min_s = DotProduct( mins, vecs[0] );\r
3453     min_t = DotProduct( mins, vecs[1] );\r
3454     max_s = DotProduct( maxs, vecs[0] );\r
3455     max_t = DotProduct( maxs, vecs[1] );\r
3456     width = max_s - min_s;\r
3457     height = max_t - min_t;\r
3458     coords[0][0] = min_s;\r
3459     coords[0][1] = min_t;\r
3460     coords[1][0] = max_s;\r
3461     coords[1][1] = min_t;\r
3462     coords[2][0] = min_s;\r
3463     coords[2][1] = max_t;\r
3464     coords[3][0] = max_s;\r
3465     coords[3][1] = max_t;\r
3466     min_s = min_t = 99999;\r
3467     max_s = max_t = -99999;\r
3468     for (i=0; i<4; i++)\r
3469     {\r
3470       s = cosv * coords[i][0] - sinv * coords[i][1];\r
3471       t = sinv * coords[i][0] + cosv * coords[i][1];\r
3472       if (i&1)\r
3473       {\r
3474         if (s > max_s)\r
3475         {\r
3476           max_s = s;\r
3477         }\r
3478       }\r
3479       else\r
3480       {\r
3481         if (s < min_s)\r
3482         {\r
3483           min_s = s;\r
3484         }\r
3485         if (i<2)\r
3486         {\r
3487           if (t < min_t)\r
3488           {\r
3489             min_t = t;\r
3490           }\r
3491         }\r
3492         else\r
3493         {\r
3494           if (t > max_t)\r
3495           {\r
3496             max_t = t;\r
3497           }\r
3498         }\r
3499       }\r
3500     }\r
3501     rot_width =  (max_s - min_s);\r
3502     rot_height = (max_t - min_t);\r
3503     td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth)));\r
3504     td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight)));\r
3505     \r
3506     td->shift[0] = min_s/td->scale[0];\r
3507     temp = (int)(td->shift[0] / (face->d_texture->width*nWidth));\r
3508     temp = (temp+1)*face->d_texture->width*nWidth;\r
3509     td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth);\r
3510     \r
3511     td->shift[1] = min_t/td->scale[1];\r
3512     temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));\r
3513     temp = (temp+1)*(face->d_texture->height*nHeight);\r
3514     td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);\r
3515     \r
3516     td->shift[1] = min_t/td->scale[1];\r
3517     temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));\r
3518     temp = (temp+1)*(face->d_texture->height*nHeight);\r
3519     td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);\r
3520     \r
3521   }\r
3522 }\r
3523 \r
3524 void Brush_FitTexture( brush_t *b, int nHeight, int nWidth )\r
3525 {\r
3526         face_t *face;\r
3527 \r
3528         for (face = b->brush_faces ; face ; face=face->next)\r
3529   {\r
3530     Face_FitTexture( face, nHeight, nWidth );\r
3531   }\r
3532 }\r
3533 \r
3534 void aabb_draw(const aabb_t *aabb, int mode)\r
3535 {\r
3536   vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } };\r
3537   vec3_t points[8];\r
3538         vec3_t vMin, vMax;\r
3539   VectorSubtract(aabb->origin, aabb->extents, vMin);\r
3540   VectorAdd(aabb->origin, aabb->extents, vMax);\r
3541   VectorSet(points[0], vMin[0], vMax[1], vMax[2]);\r
3542   VectorSet(points[1], vMax[0], vMax[1], vMax[2]);\r
3543   VectorSet(points[2], vMax[0], vMin[1], vMax[2]);\r
3544   VectorSet(points[3], vMin[0], vMin[1], vMax[2]);\r
3545   VectorSet(points[4], vMin[0], vMax[1], vMin[2]);\r
3546   VectorSet(points[5], vMax[0], vMax[1], vMin[2]);\r
3547   VectorSet(points[6], vMax[0], vMin[1], vMin[2]);\r
3548   VectorSet(points[7], vMin[0], vMin[1], vMin[2]);\r
3549 \r
3550   qglBegin(GL_QUADS);\r
3551 \r
3552   qglNormal3fv(normals[0]);\r
3553   qglVertex3fv(points[2]);\r
3554   qglVertex3fv(points[1]);\r
3555   qglVertex3fv(points[5]);\r
3556   qglVertex3fv(points[6]);\r
3557 \r
3558   qglNormal3fv(normals[1]);\r
3559   qglVertex3fv(points[1]);\r
3560   qglVertex3fv(points[0]);\r
3561   qglVertex3fv(points[4]);\r
3562   qglVertex3fv(points[5]);\r
3563 \r
3564   qglNormal3fv(normals[2]);\r
3565   qglVertex3fv(points[0]);\r
3566   qglVertex3fv(points[1]);\r
3567   qglVertex3fv(points[2]);\r
3568   qglVertex3fv(points[3]);\r
3569 \r
3570   qglNormal3fv(normals[3]);\r
3571   qglVertex3fv(points[3]);\r
3572   qglVertex3fv(points[7]);\r
3573   qglVertex3fv(points[4]);\r
3574   qglVertex3fv(points[0]);\r
3575 \r
3576   qglNormal3fv(normals[4]);\r
3577   qglVertex3fv(points[3]);\r
3578   qglVertex3fv(points[2]);\r
3579   qglVertex3fv(points[6]);\r
3580   qglVertex3fv(points[7]);\r
3581 \r
3582   qglNormal3fv(normals[5]);\r
3583   qglVertex3fv(points[7]);\r
3584   qglVertex3fv(points[6]);\r
3585   qglVertex3fv(points[5]);\r
3586   qglVertex3fv(points[4]);\r
3587 \r
3588   qglEnd();\r
3589 \r
3590 /*\r
3591 \r
3592 \r
3593   vec3_t Coords[8];\r
3594 \r
3595         vec3_t vMin, vMax;\r
3596   VectorSubtract(aabb->origin, aabb->extents, vMin);\r
3597   VectorAdd(aabb->origin, aabb->extents, vMax);\r
3598   VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]);\r
3599   VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]);\r
3600   VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]);\r
3601   VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]);\r
3602   VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]);\r
3603   VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]);\r
3604   VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]);\r
3605   VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]);\r
3606 \r
3607         vec3_t Normals[8] = { {-1, 0, 0 },\r
3608                                                                                         { 0, 0, 0 },\r
3609                                                                                         { 0, 0, 0 },\r
3610                                                                                         { 0, 0, 1 },\r
3611                                                                                         { 0, 0,-1 },\r
3612                                                                                         { 0, 1, 0 },\r
3613                                                                                         { 1, 0, 0 },\r
3614                                                                                         { 0,-1, 0 } };\r
3615   \r
3616         unsigned short Indices[24] = { 2, 1, 5, 6,\r
3617                                                                                                                                  1, 0, 4, 5,\r
3618                                                                                                                                  0, 1, 2, 3,\r
3619                                                                                                                                  3, 7, 4, 0,\r
3620                                                                                                                                  3, 2, 6, 7,\r
3621                                                                                                                                  7, 6, 5, 4 };\r
3622 \r
3623   qglVertexPointer(3, GL_FLOAT, 0, Coords);         // filling the arrays\r
3624   qglNormalPointer(GL_FLOAT, 0, Normals);\r
3625   \r
3626   //glLockArraysEXT(0, count);                // extension GL_EXT_compiled_vertex_array\r
3627   \r
3628   qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices);\r
3629     \r
3630   //glUnlockArraysEXT;                        // extension GL_EXT_compiled_vertex_array\r
3631 */\r
3632 }\r
3633 \r
3634 qboolean IsBrushSelected(brush_t* bSel)\r
3635 {\r
3636         for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next)\r
3637   {\r
3638     if (b == bSel)\r
3639       return true;\r
3640   }\r
3641   return false;\r
3642 }\r
3643 \r
3644 \r