]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/q2map/patches.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / tools / quake2 / q2map / patches.c
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 "qrad.h"\r
23 \r
24 vec3_t  texture_reflectivity[MAX_MAP_TEXINFO];\r
25 \r
26 /*\r
27 ===================================================================\r
28 \r
29   TEXTURE LIGHT VALUES\r
30 \r
31 ===================================================================\r
32 */\r
33 \r
34 /*\r
35 ======================\r
36 CalcTextureReflectivity_Quake2\r
37 ======================\r
38 */\r
39 void CalcTextureReflectivity_Quake2 (void)\r
40 {\r
41         int                             i;\r
42         int                             j, k, texels;\r
43         int                             color[3];\r
44         int                             texel;\r
45         byte                    *palette;\r
46         char                    path[1024];\r
47         float                   r, scale;\r
48         miptex_t                *mt;\r
49 \r
50         sprintf (path, "%spics/colormap.pcx", gamedir);\r
51 \r
52         // get the game palette\r
53         Load256Image (path, NULL, &palette, NULL, NULL);\r
54 \r
55         // allways set index 0 even if no textures\r
56         texture_reflectivity[0][0] = 0.5;\r
57         texture_reflectivity[0][1] = 0.5;\r
58         texture_reflectivity[0][2] = 0.5;\r
59 \r
60         for (i=0 ; i<numtexinfo ; i++)\r
61         {\r
62                 // see if an earlier texinfo allready got the value\r
63                 for (j=0 ; j<i ; j++)\r
64                 {\r
65                         if (!strcmp (texinfo[i].texture, texinfo[j].texture))\r
66                         {\r
67                                 VectorCopy (texture_reflectivity[j], texture_reflectivity[i]);\r
68                                 break;\r
69                         }\r
70                 }\r
71                 if (j != i)\r
72                         continue;\r
73 \r
74                 // load the wal file\r
75                 sprintf (path, "%stextures/%s.wal", gamedir, texinfo[i].texture);\r
76                 if (TryLoadFile (path, (void **)&mt) == -1)\r
77                 {\r
78                         Sys_Printf ("Couldn't load %s\n", path);\r
79                         texture_reflectivity[i][0] = 0.5;\r
80                         texture_reflectivity[i][1] = 0.5;\r
81                         texture_reflectivity[i][2] = 0.5;\r
82                         continue;\r
83                 }\r
84                 texels = LittleLong(mt->width)*LittleLong(mt->height);\r
85                 color[0] = color[1] = color[2] = 0;\r
86 \r
87                 for (j=0 ; j<texels ; j++)\r
88                 {\r
89                         texel = ((byte *)mt)[LittleLong(mt->offsets[0]) + j];\r
90                         for (k=0 ; k<3 ; k++)\r
91                                 color[k] += palette[texel*3+k];\r
92                 }\r
93 \r
94                 for (j=0 ; j<3 ; j++)\r
95                 {\r
96                         r = color[j]/texels/255.0;\r
97                         texture_reflectivity[i][j] = r;\r
98                 }\r
99                 // scale the reflectivity up, because the textures are\r
100                 // so dim\r
101                 scale = ColorNormalize (texture_reflectivity[i],\r
102                         texture_reflectivity[i]);\r
103                 if (scale < 0.5)\r
104                 {\r
105                         scale *= 2;\r
106                         VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]);\r
107                 }\r
108 #if 0\r
109 texture_reflectivity[i][0] = 0.5;\r
110 texture_reflectivity[i][1] = 0.5;\r
111 texture_reflectivity[i][2] = 0.5;\r
112 #endif\r
113         }\r
114 }\r
115 \r
116 /*\r
117 ======================\r
118 CalcTextureReflectivity_Heretic2\r
119 ======================\r
120 */\r
121 void CalcTextureReflectivity_Heretic2 (void)\r
122 {\r
123         int                             i;\r
124         int                             j, texels;\r
125         int                             color[3];\r
126         int                             texel;\r
127         char                    path[1024];\r
128         float                   r;\r
129         miptex_m8_t             *mt;\r
130         miptex_m32_t            *mt32;\r
131         byte                    *pos;\r
132 \r
133 \r
134         // allways set index 0 even if no textures\r
135         texture_reflectivity[0][0] = 0.5;\r
136         texture_reflectivity[0][1] = 0.5;\r
137         texture_reflectivity[0][2] = 0.5;\r
138 \r
139         for (i=0 ; i<numtexinfo ; i++)\r
140         {\r
141                 // see if an earlier texinfo allready got the value\r
142                 for (j=0 ; j<i ; j++)\r
143                 {\r
144                         if (!strcmp (texinfo[i].texture, texinfo[j].texture))\r
145                         {\r
146                                 VectorCopy (texture_reflectivity[j], texture_reflectivity[i]);\r
147                                 break;\r
148                         }\r
149                 }\r
150                 if (j != i)\r
151                         continue;\r
152 \r
153                 // load the wal file\r
154 \r
155                 sprintf (path, "%stextures/%s.m32", gamedir, texinfo[i].texture);\r
156                 if (TryLoadFile (path, (void **)&mt32) == -1)\r
157                 {\r
158                         sprintf (path, "%stextures/%s.m8", gamedir, texinfo[i].texture);\r
159                         if (TryLoadFile (path, (void **)&mt) == -1)\r
160                         {\r
161                                 Sys_Printf ("Couldn't load %s\n", path);\r
162                                 texture_reflectivity[i][0] = 0.5;\r
163                                 texture_reflectivity[i][1] = 0.5;\r
164                                 texture_reflectivity[i][2] = 0.5;\r
165                                 continue;\r
166                         }\r
167                         texels = LittleLong(mt->width[0])*LittleLong(mt->height[0]);\r
168                         color[0] = color[1] = color[2] = 0;\r
169 \r
170                         for (j=0 ; j<texels ; j++)\r
171                         {\r
172                                 texel = ((byte *)mt)[LittleLong(mt->offsets[0]) + j];\r
173                                 color[0] += mt->palette[texel].r;\r
174                                 color[1] += mt->palette[texel].g;\r
175                                 color[2] += mt->palette[texel].b;\r
176                         }\r
177 \r
178                         free(mt);\r
179                 }\r
180                 else\r
181                 {\r
182                         texels = LittleLong(mt32->width[0])*LittleLong(mt32->height[0]);\r
183                         color[0] = color[1] = color[2] = 0;\r
184 \r
185                         for (j=0 ; j<texels ; j++)\r
186                         {\r
187                                 pos = (byte *)mt32 + mt32->offsets[0] + (j<<2);\r
188                                 color[0] += *pos++;     // r\r
189                                 color[1] += *pos++;     // g\r
190                                 color[2] += *pos++;     // b\r
191                         }\r
192 \r
193                         free(mt32);\r
194                 }\r
195 \r
196 \r
197                 for (j=0 ; j<3 ; j++)\r
198                 {\r
199                         r = color[j]/((float) texels*255.0);\r
200                         texture_reflectivity[i][j] = r;\r
201                 }\r
202         }\r
203 }\r
204 \r
205 /*\r
206 =======================================================================\r
207 \r
208 MAKE FACES\r
209 \r
210 =======================================================================\r
211 */\r
212 \r
213 /*\r
214 =============\r
215 WindingFromFace\r
216 =============\r
217 */\r
218 winding_t       *WindingFromFace (dface_t *f)\r
219 {\r
220         int                     i;\r
221         int                     se;\r
222         dvertex_t       *dv;\r
223         int                     v;\r
224         winding_t       *w;\r
225 \r
226         w = AllocWinding (f->numedges);\r
227         w->numpoints = f->numedges;\r
228 \r
229         for (i=0 ; i<f->numedges ; i++)\r
230         {\r
231                 se = dsurfedges[f->firstedge + i];\r
232                 if (se < 0)\r
233                         v = dedges[-se].v[1];\r
234                 else\r
235                         v = dedges[se].v[0];\r
236 \r
237                 dv = &dvertexes[v];\r
238                 VectorCopy (dv->point, w->p[i]);\r
239         }\r
240 \r
241         RemoveColinearPoints (w);\r
242 \r
243         return w;\r
244 }\r
245 \r
246 /*\r
247 =============\r
248 BaseLightForFace\r
249 =============\r
250 */\r
251 void BaseLightForFace (dface_t *f, vec3_t color)\r
252 {\r
253         texinfo_t       *tx;\r
254 \r
255         //\r
256         // check for light emited by texture\r
257         //\r
258         tx = &texinfo[f->texinfo];\r
259         if (!(tx->flags & SURF_LIGHT) || tx->value == 0)\r
260         {\r
261                 VectorClear (color);\r
262                 return;\r
263         }\r
264 \r
265         VectorScale (texture_reflectivity[f->texinfo], tx->value, color);\r
266 }\r
267 \r
268 qboolean IsSky (dface_t *f)\r
269 {\r
270         texinfo_t       *tx;\r
271 \r
272         tx = &texinfo[f->texinfo];\r
273         if (tx->flags & SURF_SKY)\r
274                 return true;\r
275         return false;\r
276 }\r
277 \r
278 /*\r
279 =============\r
280 MakePatchForFace\r
281 =============\r
282 */\r
283 float   totalarea;\r
284 void MakePatchForFace (int fn, winding_t *w)\r
285 {\r
286         dface_t *f;\r
287         float   area;\r
288         patch_t         *patch;\r
289         dplane_t        *pl;\r
290         int                     i;\r
291         vec3_t          color;\r
292         dleaf_t         *leaf;\r
293 \r
294         f = &dfaces[fn];\r
295 \r
296         area = WindingArea (w);\r
297         totalarea += area;\r
298 \r
299         patch = &patches[num_patches];\r
300         if (num_patches == MAX_PATCHES)\r
301                 Error ("num_patches == MAX_PATCHES");\r
302         patch->next = face_patches[fn];\r
303         face_patches[fn] = patch;\r
304 \r
305         patch->winding = w;\r
306 \r
307         if (f->side)\r
308                 patch->plane = &backplanes[f->planenum];\r
309         else\r
310                 patch->plane = &dplanes[f->planenum];\r
311         if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] )\r
312         {       // origin offset faces must create new planes\r
313                 if (numplanes + fakeplanes >= MAX_MAP_PLANES)\r
314                         Error ("numplanes + fakeplanes >= MAX_MAP_PLANES");\r
315                 pl = &dplanes[numplanes + fakeplanes];\r
316                 fakeplanes++;\r
317 \r
318                 *pl = *(patch->plane);\r
319                 pl->dist += DotProduct (face_offset[fn], pl->normal);\r
320                 patch->plane = pl;\r
321         }\r
322 \r
323         WindingCenter (w, patch->origin);\r
324         VectorAdd (patch->origin, patch->plane->normal, patch->origin);\r
325         leaf = Rad_PointInLeaf(patch->origin);\r
326         patch->cluster = leaf->cluster;\r
327         if (patch->cluster == -1)\r
328                 Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n");\r
329 \r
330         patch->area = area;\r
331         if (patch->area <= 1)\r
332                 patch->area = 1;\r
333         patch->sky = IsSky (f);\r
334 \r
335         VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity);\r
336 \r
337         // non-bmodel patches can emit light\r
338         if (fn < dmodels[0].numfaces)\r
339         {\r
340                 BaseLightForFace (f, patch->baselight);\r
341 \r
342                 ColorNormalize (patch->reflectivity, color);\r
343 \r
344                 for (i=0 ; i<3 ; i++)\r
345                         patch->baselight[i] *= color[i];\r
346 \r
347                 VectorCopy (patch->baselight, patch->totallight);\r
348         }\r
349         num_patches++;\r
350 }\r
351 \r
352 \r
353 entity_t *EntityForModel (int modnum)\r
354 {\r
355         int             i;\r
356         char    *s;\r
357         char    name[16];\r
358 \r
359         sprintf (name, "*%i", modnum);\r
360         // search the entities for one using modnum\r
361         for (i=0 ; i<num_entities ; i++)\r
362         {\r
363                 s = ValueForKey (&entities[i], "model");\r
364                 if (!strcmp (s, name))\r
365                         return &entities[i];\r
366         }\r
367 \r
368         return &entities[0];\r
369 }\r
370 \r
371 /*\r
372 =============\r
373 MakePatches\r
374 =============\r
375 */\r
376 void MakePatches (void)\r
377 {\r
378         int             i, j, k;\r
379         dface_t *f;\r
380         int             fn;\r
381         winding_t       *w;\r
382         dmodel_t        *mod;\r
383         vec3_t          origin;\r
384         entity_t        *ent;\r
385 \r
386         Sys_FPrintf( SYS_VRB, "%i faces\n", numfaces);\r
387 \r
388         for (i=0 ; i<nummodels ; i++)\r
389         {\r
390                 mod = &dmodels[i];\r
391                 ent = EntityForModel (i);\r
392                 // bmodels with origin brushes need to be offset into their\r
393                 // in-use position\r
394                 GetVectorForKey (ent, "origin", origin);\r
395 //VectorCopy (vec3_origin, origin);\r
396 \r
397                 for (j=0 ; j<mod->numfaces ; j++)\r
398                 {\r
399                         fn = mod->firstface + j;\r
400                         face_entity[fn] = ent;\r
401                         VectorCopy (origin, face_offset[fn]);\r
402                         f = &dfaces[fn];\r
403                         w = WindingFromFace (f);\r
404                         for (k=0 ; k<w->numpoints ; k++)\r
405                         {\r
406                                 VectorAdd (w->p[k], origin, w->p[k]);\r
407                         }\r
408                         MakePatchForFace (fn, w);\r
409                 }\r
410         }\r
411 \r
412         Sys_FPrintf( SYS_VRB, "%i sqaure feet\n", (int)(totalarea/64));\r
413 }\r
414 \r
415 /*\r
416 =======================================================================\r
417 \r
418 SUBDIVIDE\r
419 \r
420 =======================================================================\r
421 */\r
422 \r
423 void FinishSplit (patch_t *patch, patch_t *newp)\r
424 {\r
425         dleaf_t         *leaf;\r
426 \r
427         VectorCopy (patch->baselight, newp->baselight);\r
428         VectorCopy (patch->totallight, newp->totallight);\r
429         VectorCopy (patch->reflectivity, newp->reflectivity);\r
430         newp->plane = patch->plane;\r
431         newp->sky = patch->sky;\r
432 \r
433         patch->area = WindingArea (patch->winding);\r
434         newp->area = WindingArea (newp->winding);\r
435 \r
436         if (patch->area <= 1)\r
437                 patch->area = 1;\r
438         if (newp->area <= 1)\r
439                 newp->area = 1;\r
440 \r
441         WindingCenter (patch->winding, patch->origin);\r
442         VectorAdd (patch->origin, patch->plane->normal, patch->origin);\r
443         leaf = Rad_PointInLeaf(patch->origin);\r
444         patch->cluster = leaf->cluster;\r
445         if (patch->cluster == -1)\r
446                 Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n");\r
447 \r
448         WindingCenter (newp->winding, newp->origin);\r
449         VectorAdd (newp->origin, newp->plane->normal, newp->origin);\r
450         leaf = Rad_PointInLeaf(newp->origin);\r
451         newp->cluster = leaf->cluster;\r
452         if (newp->cluster == -1)\r
453                 Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n");\r
454 }\r
455 \r
456 /*\r
457 =============\r
458 SubdividePatch\r
459 \r
460 Chops the patch only if its local bounds exceed the max size\r
461 =============\r
462 */\r
463 void    SubdividePatch (patch_t *patch)\r
464 {\r
465         winding_t *w, *o1, *o2;\r
466         vec3_t  mins, maxs, total;\r
467         vec3_t  split;\r
468         vec_t   dist;\r
469         int             i, j;\r
470         vec_t   v;\r
471         patch_t *newp;\r
472 \r
473         w = patch->winding;\r
474         mins[0] = mins[1] = mins[2] = 99999;\r
475         maxs[0] = maxs[1] = maxs[2] = -99999;\r
476         for (i=0 ; i<w->numpoints ; i++)\r
477         {\r
478                 for (j=0 ; j<3 ; j++)\r
479                 {\r
480                         v = w->p[i][j];\r
481                         if (v < mins[j])\r
482                                 mins[j] = v;\r
483                         if (v > maxs[j])\r
484                                 maxs[j] = v;\r
485                 }\r
486         }\r
487         VectorSubtract (maxs, mins, total);\r
488         for (i=0 ; i<3 ; i++)\r
489                 if (total[i] > (subdiv+1) )\r
490                         break;\r
491         if (i == 3)\r
492         {\r
493                 // no splitting needed\r
494                 return;         \r
495         }\r
496 \r
497         //\r
498         // split the winding\r
499         //\r
500         VectorCopy (vec3_origin, split);\r
501         split[i] = 1;\r
502         dist = (mins[i] + maxs[i])*0.5;\r
503         ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);\r
504 \r
505         //\r
506         // create a new patch\r
507         //\r
508         if (num_patches == MAX_PATCHES)\r
509                 Error ("MAX_PATCHES");\r
510         newp = &patches[num_patches];\r
511         num_patches++;\r
512 \r
513         newp->next = patch->next;\r
514         patch->next = newp;\r
515 \r
516         patch->winding = o1;\r
517         newp->winding = o2;\r
518 \r
519         FinishSplit (patch, newp);\r
520 \r
521         SubdividePatch (patch);\r
522         SubdividePatch (newp);\r
523 }\r
524 \r
525 \r
526 /*\r
527 =============\r
528 DicePatch\r
529 \r
530 Chops the patch by a global grid\r
531 =============\r
532 */\r
533 void    DicePatch (patch_t *patch)\r
534 {\r
535         winding_t *w, *o1, *o2;\r
536         vec3_t  mins, maxs;\r
537         vec3_t  split;\r
538         vec_t   dist;\r
539         int             i;\r
540         patch_t *newp;\r
541 \r
542         w = patch->winding;\r
543         WindingBounds (w, mins, maxs);\r
544         for (i=0 ; i<3 ; i++)\r
545                 if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv))\r
546                         break;\r
547         if (i == 3)\r
548         {\r
549                 // no splitting needed\r
550                 return;         \r
551         }\r
552 \r
553         //\r
554         // split the winding\r
555         //\r
556         VectorCopy (vec3_origin, split);\r
557         split[i] = 1;\r
558         dist = subdiv*(1+floor((mins[i]+1)/subdiv));\r
559         ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);\r
560 \r
561         //\r
562         // create a new patch\r
563         //\r
564         if (num_patches == MAX_PATCHES)\r
565                 Error ("MAX_PATCHES");\r
566         newp = &patches[num_patches];\r
567         num_patches++;\r
568 \r
569         newp->next = patch->next;\r
570         patch->next = newp;\r
571 \r
572         patch->winding = o1;\r
573         newp->winding = o2;\r
574 \r
575         FinishSplit (patch, newp);\r
576 \r
577         DicePatch (patch);\r
578         DicePatch (newp);\r
579 }\r
580 \r
581 \r
582 /*\r
583 =============\r
584 SubdividePatches\r
585 =============\r
586 */\r
587 void SubdividePatches (void)\r
588 {\r
589         int             i, num;\r
590 \r
591         if (subdiv < 1)\r
592                 return;\r
593 \r
594         num = num_patches;      // because the list will grow\r
595         for (i=0 ; i<num ; i++)\r
596         {\r
597 //              SubdividePatch (&patches[i]);\r
598                 DicePatch (&patches[i]);\r
599         }\r
600         Sys_FPrintf( SYS_VRB, "%i patches after subdivision\n", num_patches);\r
601 }\r
602 \r
603 //=====================================================================\r