]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/texwindow.cpp
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / radiant / texwindow.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 //\r
23 // Texture Window\r
24 //\r
25 // Leonardo Zide (leo@lokigames.com)\r
26 //\r
27 \r
28 /*!\todo\r
29 Clean up texture menu.\r
30 - Remove all global variables and use some objects instead.\r
31 - Create an interface for a plugin to add texture menu items.\r
32 - Make sure the interface is not dependent on gtk.\r
33 */\r
34 \r
35 #ifdef _WIN32\r
36 //#include <gdk/win32/gdkwin32.h> \r
37 #include <gdk/gdkwin32.h> \r
38 #endif\r
39 #if defined (__linux__) || defined (__APPLE__)\r
40 #include <gdk/gdkx.h>\r
41 #include <dirent.h>\r
42 #endif\r
43 #include <gtk/gtk.h>\r
44 #include <assert.h>\r
45 #include <sys/stat.h>\r
46 #include "stdafx.h"\r
47 #include "texwindow.h"\r
48 #include "str.h"\r
49 #include "missing.h"\r
50 #include "texmanip.h"\r
51 \r
52 #define TYP_MIPTEX      68\r
53 static unsigned tex_palette[256];\r
54 \r
55 #define FONT_HEIGHT     10\r
56 \r
57 //int           texture_mode = GL_NEAREST;\r
58 //int           texture_mode = GL_NEAREST_MIPMAP_NEAREST;\r
59 //int           texture_mode = GL_NEAREST_MIPMAP_LINEAR;\r
60 //int           texture_mode = GL_LINEAR;\r
61 //int           texture_mode = GL_LINEAR_MIPMAP_NEAREST;\r
62 int             texture_mode = GL_LINEAR_MIPMAP_LINEAR;\r
63 \r
64 int g_nTextureOffset = 0;\r
65 \r
66 // current active texture directory\r
67 //++timo FIXME: I'm not sure this is used anymore\r
68 char            texture_directory[128];\r
69 // if true, the texture window will only display in-use shaders\r
70 // if false, all the shaders in memory are displayed\r
71 qboolean g_bShowAllShaders;\r
72 \r
73 bool g_bFilterEnabled = false;\r
74 CString g_strFilter;\r
75 \r
76 // texture layout functions\r
77 // TTimo: now based on shaders\r
78 int     nActiveShadersCount;\r
79 int     nCurrentShader;\r
80 IShader*  pCurrentShader;\r
81 qtexture_t  *current_texture = NULL;\r
82 int     current_x, current_y, current_row;\r
83 \r
84 // globals for textures\r
85 int     texture_nummenus;\r
86 char    texture_menunames[MAX_TEXTUREDIRS][128];\r
87 \r
88 // the list of scripts/*.shader files we need to work with\r
89 // those are listed in shaderlist file\r
90 // FIXME TTimo I get the feeling that those would need to move to the shaders module\r
91 //   for now it's still more simple to just keep it here\r
92 GSList *l_shaderfiles = NULL;\r
93 \r
94 void SelectTexture (int mx, int my, bool bShift, bool bFitScale=false);\r
95 \r
96 void  Texture_MouseDown (int x, int y, int buttons);\r
97 void  Texture_MouseMoved (int x, int y, int buttons);\r
98 \r
99 CPtrArray g_lstSkinCache;\r
100 \r
101 // TTimo: modifed to add a qtexture_t, Texture_LoadSkin loads using the shader API / QERApp_TryTexture_ForName\r
102 // m_strName is a copy of qtex->name\r
103 struct SkinInfo\r
104 {\r
105   CString m_strName;\r
106   int m_nTextureBind;\r
107   qtexture_t *m_qtex;\r
108   SkinInfo(const char *pName, int n, qtexture_t *qtex)\r
109   {\r
110     m_strName = pName;\r
111     m_nTextureBind = n;\r
112     m_qtex = qtex;\r
113   };\r
114   SkinInfo(){};\r
115 };\r
116 \r
117 // =============================================================================\r
118 // global functions\r
119 \r
120 // gets active texture extension\r
121 //\r
122 // FIXME: fix this to be generic from project file\r
123 //\r
124 int GetTextureExtensionCount()\r
125 {\r
126   // hardcoded hack for png support\r
127   if (g_pGameDescription->mGameFile == "sof2.game")\r
128     return 3;\r
129   else\r
130     return 2;\r
131 }\r
132 \r
133 const char* GetTextureExtension(int nIndex)\r
134 {\r
135   switch(nIndex)\r
136   {\r
137     case 0:\r
138       return "tga";\r
139       break;\r
140     case 1:\r
141       return "jpg";\r
142       break;\r
143     case 2:\r
144       return "png";\r
145       break;\r
146     default:\r
147       return NULL;\r
148   }\r
149 }\r
150 \r
151 /*\r
152 ==============\r
153 Texture_InitPalette\r
154 ==============\r
155 */\r
156 void Texture_InitPalette (byte *pal)\r
157 {\r
158   int   r,g,b;\r
159   int   i;\r
160   int   inf;\r
161   byte  gammatable[256];\r
162   float gamma;\r
163 \r
164   gamma = g_qeglobals.d_savedinfo.fGamma;\r
165 \r
166   if (gamma == 1.0)\r
167   {\r
168     for (i=0 ; i<256 ; i++)\r
169       gammatable[i] = i;\r
170   } else\r
171   {\r
172     for (i=0 ; i<256 ; i++)\r
173     {\r
174       inf = (int)( 255.0f * pow( ( i + 0.5f ) / 255.5f , gamma ) + 0.5f );\r
175       if (inf < 0)\r
176         inf = 0;\r
177       if (inf > 255)\r
178         inf = 255;\r
179       gammatable[i] = inf;\r
180     }\r
181   }\r
182 \r
183   for (i=0 ; i<256 ; i++)\r
184   {\r
185     r = gammatable[pal[0]];\r
186     g = gammatable[pal[1]];\r
187     b = gammatable[pal[2]];\r
188     pal += 3;\r
189 \r
190     //v = (r<<24) + (g<<16) + (b<<8) + 255;\r
191     //v = BigLong (v);\r
192 \r
193     //tex_palette[i] = v;\r
194     tex_palette[i*3+0] = r;\r
195     tex_palette[i*3+1] = g;\r
196     tex_palette[i*3+2] = b;\r
197   }\r
198 }\r
199 \r
200 void SetTexParameters (void)\r
201 {\r
202   qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_mode );\r
203 \r
204   switch ( texture_mode )\r
205   {\r
206   case GL_NEAREST:\r
207   case GL_NEAREST_MIPMAP_NEAREST:\r
208   case GL_NEAREST_MIPMAP_LINEAR:\r
209     qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );\r
210     break;\r
211   case GL_LINEAR:\r
212   case GL_LINEAR_MIPMAP_NEAREST:\r
213   case GL_LINEAR_MIPMAP_LINEAR:\r
214     qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\r
215     break;\r
216   }\r
217 }\r
218 \r
219 /*\r
220 ============\r
221 Texture_SetMode\r
222 ============\r
223 */\r
224 void Texture_SetMode(int iMenu)\r
225 {\r
226   int iMode;\r
227   qboolean texturing = true;\r
228   gpointer item = NULL;\r
229 \r
230   switch (iMenu)\r
231   {\r
232   case ID_VIEW_NEAREST:\r
233     item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_nearest");\r
234     iMode = GL_NEAREST;\r
235     break;\r
236   case ID_VIEW_NEARESTMIPMAP:\r
237     item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_nearestmipmap");\r
238     iMode = GL_NEAREST_MIPMAP_NEAREST;\r
239     break;\r
240   case ID_VIEW_LINEAR:\r
241     item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_linear");\r
242     iMode = GL_LINEAR;\r
243     break;\r
244   case ID_VIEW_BILINEAR:\r
245     item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_bilinear");\r
246     iMode = GL_NEAREST_MIPMAP_LINEAR;\r
247     break;\r
248   case ID_VIEW_BILINEARMIPMAP:\r
249     item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_bilinearmipmap");\r
250     iMode = GL_LINEAR_MIPMAP_NEAREST;\r
251     break;\r
252   case ID_VIEW_TRILINEAR:\r
253     item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_trilinear");\r
254     iMode = GL_LINEAR_MIPMAP_LINEAR;\r
255     break;\r
256   case ID_TEXTURES_WIREFRAME:\r
257     item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_wireframe");\r
258     iMode = -1;\r
259     texturing = false;\r
260     break;\r
261   case ID_TEXTURES_FLATSHADE:\r
262     item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_flatshade");\r
263     iMode = -1;\r
264     texturing = false;\r
265     break;\r
266   }\r
267 \r
268   g_qeglobals.d_savedinfo.iTexMenu = iMenu;\r
269   // NOTE: texture_mode is a GLenum used directly in glTexParameter\r
270   if(iMode!=-1) texture_mode = iMode;\r
271 \r
272   g_bIgnoreCommands++;\r
273   if (item != NULL)\r
274     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);\r
275   g_bIgnoreCommands--;\r
276 \r
277   if (texturing)\r
278     SetTexParameters ();\r
279 \r
280   if ( !texturing && iMenu == ID_TEXTURES_WIREFRAME)\r
281   {\r
282     g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_wire;\r
283     Map_BuildBrushData();\r
284     Sys_UpdateWindows (W_ALL);\r
285     return;\r
286   } else if ( !texturing && iMenu == ID_TEXTURES_FLATSHADE)\r
287   {\r
288     g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_solid;\r
289     Map_BuildBrushData();\r
290     Sys_UpdateWindows (W_ALL);\r
291     return;\r
292   }\r
293 \r
294   for (qtexture_t *q = g_qeglobals.d_qtextures; q; q = q->next)\r
295   {\r
296     qglBindTexture (GL_TEXTURE_2D, q->texture_number);\r
297     SetTexParameters ();\r
298   }\r
299 \r
300   // select the default texture\r
301   qglBindTexture( GL_TEXTURE_2D, 0 );\r
302 \r
303   qglFinish();\r
304 \r
305   if (g_pParentWnd->GetCamWnd()->Camera()->draw_mode != cd_texture)\r
306   {\r
307     g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_texture;\r
308     Map_BuildBrushData();\r
309   }\r
310 \r
311   Sys_UpdateWindows (W_ALL);\r
312 }\r
313 \r
314 /*!\r
315 gamma correction stuff\r
316 took out of QERApp_LoadTextureRGBA for clarity\r
317 */\r
318 byte g_gammatable[256];\r
319 void ResampleGamma(float fGamma)\r
320 {\r
321   int i,inf;\r
322   if (fGamma == 1.0)\r
323   {\r
324     for (i = 0; i < 256; i++)\r
325       g_gammatable[i] = i;\r
326   } else\r
327   {\r
328     for (i = 0; i < 256; i++)\r
329     {\r
330       inf = (int)( 255.0f * pow( (i + 0.5f) / 255.5f , fGamma ) + 0.5f );\r
331       if (inf < 0)\r
332         inf = 0;\r
333       if (inf > 255)\r
334         inf = 255;\r
335       g_gammatable[i] = inf;\r
336     }\r
337   }\r
338 }\r
339 \r
340 /*!\r
341 this function does the actual processing of raw RGBA data into a GL texture\r
342 it will also generate the mipmaps\r
343 it looks like pPixels nWidth nHeight are the only relevant parameters\r
344 */\r
345 qtexture_t *QERApp_LoadTextureRGBA(unsigned char* pPixels, int nWidth, int nHeight)\r
346 {\r
347   static float fGamma = -1;\r
348   float total[3];\r
349   byte  *outpixels = NULL;\r
350   int   i, j, resampled, width2, height2, width3, height3;\r
351   int   max_tex_size = 0, mip = 0;\r
352   int   nCount = nWidth * nHeight;\r
353 \r
354   if (fGamma != g_qeglobals.d_savedinfo.fGamma)\r
355   {\r
356     fGamma = g_qeglobals.d_savedinfo.fGamma;\r
357     ResampleGamma(fGamma);\r
358   }\r
359 \r
360   qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);\r
361   if (!max_tex_size)\r
362     max_tex_size = 1024;\r
363 \r
364   qtexture_t *q = (qtexture_t*)g_malloc(sizeof(*q));\r
365   q->width = nWidth;\r
366   q->height = nHeight;\r
367 \r
368   total[0] = total[1] = total[2] = 0.0f;\r
369 \r
370   // resample texture gamma according to user settings\r
371   for (i = 0; i < (nCount * 4); i += 4)\r
372   {\r
373     for (j = 0; j < 3; j++)\r
374     {\r
375       total[j] += (pPixels + i)[j];\r
376       byte b = (pPixels + i)[j];\r
377       (pPixels + i)[j] = g_gammatable[b];\r
378     }\r
379   }\r
380 \r
381   q->color[0] = total[0] / (nCount * 255);\r
382   q->color[1] = total[1] / (nCount * 255);\r
383   q->color[2] = total[2] / (nCount * 255);\r
384 \r
385   qglGenTextures (1, &q->texture_number);\r
386 \r
387   qglBindTexture( GL_TEXTURE_2D, q->texture_number );\r
388 \r
389   SetTexParameters();\r
390 \r
391   width2 = 1; while (width2 < nWidth) width2 <<= 1;\r
392   height2 = 1; while (height2 < nHeight) height2 <<= 1;\r
393 \r
394   width3 = width2;\r
395   height3 = height2;\r
396   while (width3 > max_tex_size) width3 >>= 1;\r
397   while (height3 > max_tex_size) height3 >>= 1;\r
398   if (width3 < 1) width3 = 1;\r
399   if (height3 < 1) height3 = 1;\r
400 \r
401   if (!(width2 == nWidth && height2 == nHeight)) {\r
402     resampled = 1;\r
403     outpixels = (byte *)malloc(width2 * height2 * 4);\r
404     R_ResampleTexture(pPixels, nWidth, nHeight, outpixels, width2, height2, 4);\r
405   } else {\r
406     resampled = 0;\r
407     outpixels = pPixels;\r
408   }\r
409 \r
410   while (width2 > width3 || height2 > height3)\r
411   {\r
412     GL_MipReduce(outpixels, outpixels, width2, height2, width3, height3);\r
413 \r
414     if (width2 > width3)\r
415       width2 >>= 1;\r
416     if (height2 > height3)\r
417       height2 >>= 1;\r
418   }\r
419 \r
420   qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels);\r
421   while (width2 > 1 || height2 > 1)\r
422   {\r
423     GL_MipReduce(outpixels, outpixels, width2, height2, 1, 1);\r
424 \r
425     if (width2 > 1)\r
426       width2 >>= 1;\r
427     if (height2 > 1)\r
428       height2 >>= 1;\r
429 \r
430     qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels);\r
431   }\r
432 \r
433   qglBindTexture(GL_TEXTURE_2D, 0);\r
434   if (resampled)\r
435     free(outpixels);\r
436 \r
437   return q;\r
438 }\r
439 \r
440 /*\r
441 ==================\r
442 DumpUnreferencedShaders\r
443 usefull function: dumps the list of .shader files that are not referenced to the console\r
444 ==================\r
445 */\r
446 void DumpUnreferencedShaders()\r
447 {\r
448   GSList *lst, *sh, *files;\r
449   bool bFound = false;\r
450 \r
451   files = vfsGetFileList ("scripts", "shader");\r
452   for (lst = files; lst; lst = lst->next)\r
453   {\r
454     bool listed = false;\r
455 \r
456     for (sh = l_shaderfiles; sh != NULL; sh = g_slist_next (sh))\r
457       if (!strcmp ((char*)sh->data, (char*)lst->data))\r
458       {\r
459         listed = true;\r
460         break;\r
461       }\r
462 \r
463     if (!listed)\r
464     {\r
465       if (!bFound)\r
466       {\r
467         bFound = true;\r
468         Sys_FPrintf (SYS_WRN, "Following shader files are not referenced in shaderlist.txt:\n");\r
469       }\r
470       Sys_FPrintf (SYS_WRN, "%s\n", (char*)lst->data);\r
471     }\r
472   }\r
473 \r
474   vfsClearFileDirList (&files);\r
475 }\r
476 \r
477 /*\r
478 ==================\r
479 BuildShaderList\r
480 build a CStringList of shader names\r
481 ==================\r
482 */\r
483 void BuildShaderList()\r
484 {\r
485   int count;\r
486   char filename[1024];\r
487   char *pBuff;\r
488   char dirstring[NAME_MAX];\r
489   int nLen;\r
490   if (l_shaderfiles!=NULL)\r
491   {\r
492     g_slist_free(l_shaderfiles);\r
493     l_shaderfiles = NULL;\r
494   }\r
495 \r
496   if (g_pGameDescription->mGameFile != "hl.game")\r
497   {\r
498     strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer());\r
499     count = vfsGetFileCount(filename, 0 );\r
500     if (count==0)\r
501     {\r
502       Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer());\r
503       return;\r
504     }\r
505     // NOTE TTimo we use vfsGetFullPath solely to get the full path of the shader list we are gonna load\r
506     //   but we actually send the relative path to vfsLoadFile\r
507     //   so let's hope there is no disparity between the two functions\r
508     if (!vfsGetFullPath(filename, 0, 0))\r
509     {\r
510       Sys_FPrintf(SYS_ERR, "Couldn't find full path for '%s'\n", g_pGameDescription->mShaderlist.GetBuffer());\r
511       Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n");\r
512       return;\r
513     }\r
514     Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0));\r
515     nLen = vfsLoadFile (filename, reinterpret_cast<void**>(&pBuff), 0);\r
516     if (nLen > 0)\r
517     {\r
518       StartTokenParsing(pBuff);\r
519       nLen = 0;\r
520       while (GetToken(true))\r
521       {\r
522         GSList *tmp;\r
523         bool found = false;\r
524         \r
525         // each token should be a shader filename\r
526         sprintf(dirstring, "%s.shader", token);\r
527         \r
528         for (tmp = l_shaderfiles; tmp != NULL; tmp = tmp->next)\r
529         {\r
530           if (!strcmp (dirstring, (char*)tmp->data))\r
531           {\r
532             found = true;\r
533             Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data);\r
534             break;\r
535           }\r
536         }\r
537         \r
538         if (!found)\r
539         {\r
540           l_shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring));\r
541           nLen++;\r
542         }\r
543       }\r
544       g_free(pBuff);\r
545     }\r
546   }\r
547 }\r
548 \r
549 /*\r
550 ==================\r
551 FillTextureMenu\r
552 \r
553 ==================\r
554 */\r
555 void ClearGSList (GSList* lst)\r
556 {\r
557   GSList *p = lst;\r
558   while (p)\r
559   {\r
560     free (p->data);\r
561     p = g_slist_remove (p, p->data);\r
562   }\r
563 }\r
564 \r
565 void FillTextureMenu (GSList** pArray)\r
566 {\r
567   GtkWidget *menu, *sep, *item; // point to the Textures GtkMenu and to the last separator\r
568   GList *lst;\r
569   GSList *texdirs = NULL;\r
570   GSList *texdirs_tmp = NULL;\r
571   GSList *p;\r
572   char dirRoot[NAME_MAX];\r
573   // this is an index used to count the number of texture items (for splitting/avoiding to get out of window)\r
574   // we start with a != 0 value to compensate for the initial number of items in the texture menu\r
575   int nMenuCount = 12;\r
576 \r
577   // delete everything\r
578   menu = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_textures"));\r
579   sep = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_textures_separator"));\r
580   lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep);\r
581   while (lst->next)\r
582   {\r
583     // these delete functions are recursive, it's gonna free all submenus\r
584     gtk_widget_destroy (GTK_WIDGET (lst->next->data));\r
585     // lst is no longer relevant, need to get it again\r
586     lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep);\r
587   }\r
588 \r
589   texture_nummenus = 0;\r
590 \r
591   // add everything\r
592   if (!g_qeglobals.d_project_entity)\r
593     return;\r
594 \r
595   // scan texture dirs and pak files only if not restricting to shaderlist\r
596   if (!g_PrefsDlg.m_bTexturesShaderlistOnly)\r
597   {\r
598     texdirs_tmp = vfsGetDirList ("textures/");\r
599     for (p=texdirs_tmp; p; p=g_slist_next(p))\r
600     {\r
601       // Hydra: erm, this didn't used to do anything except leak memory...\r
602       // For Halflife support this is required to work however.\r
603       // g_slist_append(texdirs, p->data);\r
604       texdirs = g_slist_append(texdirs, strdup((char *)p->data));\r
605     }\r
606     vfsClearFileDirList (&texdirs_tmp);\r
607   }\r
608 \r
609   // scan the shaders in shaderlist.txt\r
610   BuildShaderList ();\r
611   PreloadShaders ();\r
612   DumpUnreferencedShaders ();\r
613   while (l_shaderfiles != NULL)\r
614   {\r
615     char shaderfile[PATH_MAX];\r
616     gboolean found = FALSE;\r
617 \r
618     ExtractFileName ((char*)l_shaderfiles->data, shaderfile);\r
619     StripExtension (shaderfile);\r
620     g_strdown (shaderfile);\r
621 \r
622     for (GSList *tmp = texdirs; tmp; tmp = g_slist_next (tmp))\r
623       if (!strcasecmp ((char*)tmp->data, shaderfile))\r
624       {\r
625               found = TRUE;\r
626               break;\r
627       }\r
628 \r
629     if (!found)\r
630       texdirs = g_slist_prepend (texdirs, strdup (shaderfile));\r
631 \r
632     free (l_shaderfiles->data);\r
633     l_shaderfiles = g_slist_remove (l_shaderfiles, l_shaderfiles->data);\r
634   }\r
635 \r
636   // sort the list\r
637   texdirs = g_slist_sort (texdirs, (GCompareFunc)strcmp);\r
638 \r
639   GSList *temp = texdirs;\r
640   while (temp)\r
641   {\r
642     char* ptr = strchr ((char*)temp->data, '_');\r
643 \r
644     // do we shrink the menus?\r
645     if (ptr != NULL)\r
646     {\r
647       // extract the root\r
648       strcpy (dirRoot, (char*)temp->data);\r
649       dirRoot[ptr - (char*)temp->data + 1] = 0;\r
650 \r
651       // we shrink only if we have at least two things to shrink :-)\r
652       if (temp->next && (strstr ((char*)temp->next->data, dirRoot) == (char*)temp->next->data))\r
653       {\r
654               GtkWidget *pSubMenu = gtk_menu_new ();\r
655         GtkWidget *pSubMenuRef = pSubMenu;\r
656               // keep going...\r
657               do\r
658               {\r
659                 item = gtk_menu_item_new_with_label ((char*)temp->data);\r
660                 gtk_widget_show (item);\r
661           CheckMenuSplitting (pSubMenu);\r
662                 gtk_container_add (GTK_CONTAINER (pSubMenu), item);\r
663                 gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand),\r
664                                     GINT_TO_POINTER (CMD_TEXTUREWAD+texture_nummenus));\r
665 \r
666                 strcpy (texture_menunames[texture_nummenus], (char*)temp->data);\r
667                 strcat (texture_menunames[texture_nummenus], "/");\r
668                 if (pArray)\r
669                   *pArray = g_slist_append (*pArray, strdup ((char*)temp->data));\r
670                 if (++texture_nummenus == MAX_TEXTUREDIRS)\r
671                 {\r
672                   Sys_Printf("WARNING: max texture directories count has been reached!\n");\r
673                   // push submenu and get out\r
674                   item = gtk_menu_item_new_with_label (dirRoot);\r
675                   gtk_widget_show (item);\r
676                   gtk_container_add (GTK_CONTAINER (menu), item);\r
677                   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), pSubMenu);\r
678                   ClearGSList (texdirs);\r
679                   return;\r
680                 }\r
681                 temp = temp->next;\r
682               }\r
683         while (temp && (strstr((char*)temp->data, dirRoot)==temp->data));\r
684 \r
685         ptr = strchr (dirRoot, '_');\r
686         *ptr = 0;\r
687               item = gtk_menu_item_new_with_label (dirRoot);\r
688               gtk_widget_show (item);\r
689               CheckMenuSplitting (menu);\r
690               gtk_container_add (GTK_CONTAINER (menu), item);\r
691         gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), pSubMenuRef);\r
692               continue;\r
693       }\r
694     }\r
695 \r
696     item = gtk_menu_item_new_with_label ((char*)temp->data);\r
697     gtk_widget_show (item);\r
698     CheckMenuSplitting (menu);\r
699     gtk_container_add (GTK_CONTAINER (menu), item);\r
700     gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand),\r
701                         GINT_TO_POINTER (CMD_TEXTUREWAD+texture_nummenus));\r
702 \r
703     strcpy (texture_menunames[texture_nummenus], (char*)temp->data);\r
704     strcat (texture_menunames[texture_nummenus], "/");\r
705     if (pArray)\r
706       *pArray = g_slist_append (*pArray, strdup ((char*)temp->data));\r
707     if (++texture_nummenus == MAX_TEXTUREDIRS)\r
708     {\r
709       Sys_Printf("WARNING: max texture directories count has been reached!\n");\r
710       ClearGSList (texdirs);\r
711       return;\r
712     }\r
713 \r
714     temp = temp->next;\r
715   }\r
716   ClearGSList (texdirs);\r
717 }\r
718 \r
719 /*\r
720 ==============\r
721 Texture_ShowDirectory\r
722 relies on texture_directory global for the directory to use\r
723 called by\r
724   void Texture_ShowDirectory (int menunum, bool bLinked)\r
725   void  Texture_ShowDirectory (char* pPath, bool bLinked)\r
726 1) Load the shaders for the given directory\r
727 2) Scan the remaining texture, load them and assign them a default shader (the "noshader" shader)\r
728 NOTE: when writing a texture plugin, or some texture extensions, this function may need to be overriden, and made\r
729   available through the IShaders interface\r
730 NOTE: for texture window layout:\r
731   all shaders are stored with alphabetical order after load\r
732   previously loaded and displayed stuff is hidden, only in-use and newly loaded is shown\r
733   ( the GL textures are not flushed though)\r
734 ==============\r
735 */\r
736 void Texture_ShowDirectory ()\r
737 {\r
738   char  name[1024];\r
739   char  dirstring[1024];\r
740   CString strTemp;\r
741   int shaders_count = 0;\r
742   int textures_count = 0;\r
743   GSList *files = NULL, *temp;\r
744 \r
745   g_bScreenUpdates = false;\r
746 \r
747   // refresh the in-use textures: that will clear the IsDisplayed flag on unused stuff\r
748   // and leave it on in-use so they'll still be displayed\r
749   Texture_ShowInuse();\r
750   // and textures loaded in the following lines will be displayed as well...\r
751   // NOTE: shaders that are not in use but have been loaded previously are still in memory. But they don't get displayed.\r
752 \r
753   g_qeglobals.d_texturewin.originy = 0;\r
754   // load texture_directory.shader\r
755   // NOTE: because of above call to Texture_ClearInuse, g_ActiveShaders will have the newly loaded shaders only\r
756   // we'll use that later to check if textures have a shader associated or not\r
757   // NOTE: all shaders loaded through QERApp_LoadShadersFromDir will get their InUse flag to True, we'll need a call to Texture_ShowInUse for later cleanup/adjustment\r
758   // NOTE: QERApp_LoadShadersFromDir has two criterions for loading a shader:\r
759   //   the shaderfile is texture_directory (like "museum" will load everything in museum.shader)\r
760   //   the shader name contains texture_directory (like "base_floor" will load museum.shader::base_floor/concfloor_rain)\r
761   shaders_count = QERApp_LoadShadersFromDir(texture_directory);\r
762   // load remaining texture files\r
763   // if a texture is already in use to represent a shader, ignore it\r
764 \r
765   // need this function "GSList *lst SynapseServer::GetMinorList(char *major_name);"\r
766   \r
767   sprintf (dirstring, "textures/%s", texture_directory);\r
768   g_ImageManager.BeginExtensionsScan();\r
769   const char* ext;\r
770   while(ext=g_ImageManager.GetNextExtension())\r
771   {\r
772     files = g_slist_concat(files, vfsGetFileList (dirstring, ext));\r
773   }\r
774 \r
775   for (temp = files; temp; temp = temp->next)\r
776   {\r
777     sprintf(name, "%s%s", texture_directory, (char*)temp->data);\r
778 \r
779       StripExtension (name);\r
780       strTemp = name;\r
781       strTemp.MakeLower();\r
782 \r
783     if (strTemp.Find(".specular") >= 0 ||\r
784          strTemp.Find(".glow") >= 0 ||\r
785          strTemp.Find(".bump") >= 0 ||\r
786          strTemp.Find(".diffuse") >= 0 ||\r
787          strTemp.Find(".blend") >= 0 ||\r
788                strTemp.Find(".alpha") >= 0)\r
789          continue;\r
790 \r
791     // avoid ever loading a texture name with spaces\r
792     if (strTemp.Find(" ") >= 0)\r
793     {\r
794       Sys_FPrintf(SYS_WRN, "WARNING: Skipping texture name with spaces [%s]\n", strTemp.GetBuffer());\r
795       continue;\r
796     }\r
797 \r
798     // build a texture name that fits the conventions for qtexture_t::name\r
799     char stdName[1024];\r
800     sprintf( stdName, "textures/%s", name );\r
801     // check if this texture doesn't have a shader\r
802     if (!QERApp_ActiveShader_ForTextureName( stdName ))\r
803     {\r
804       QERApp_CreateShader_ForTextureName (stdName);\r
805       textures_count++;\r
806     }\r
807   }\r
808 \r
809   Sys_Printf("Loaded %d shaders and created default shader for %d orphan textures.\n",\r
810              shaders_count, textures_count );\r
811 \r
812   vfsClearFileDirList (&files);\r
813 \r
814   // sort for displaying\r
815   QERApp_SortActiveShaders();\r
816 \r
817   sprintf (name, "Textures: %s", texture_directory);\r
818   gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name);\r
819 \r
820   // select the first texture in the list\r
821   if (!g_qeglobals.d_texturewin.texdef.GetName()[0])\r
822     SelectTexture (16, g_qeglobals.d_texturewin.height -16, false);\r
823 \r
824   g_bScreenUpdates = true;\r
825 \r
826   Sys_UpdateWindows (W_TEXTURE);\r
827 }\r
828 \r
829 /*\r
830 ==============\r
831 Texture_ShowDirectory\r
832 1) Load the shaders for the given directory\r
833 2) Scan the remaining texture, load them and assign them a default shader (the "noshader" shader)\r
834 NOTE: when writing a texture plugin, or some texture extensions, this function may need to be overriden, and made\r
835   available through the IShaders interface\r
836 ==============\r
837 */\r
838 void Texture_ShowDirectory (int menunum)\r
839 {\r
840   strcpy (texture_directory, texture_menunames[menunum-CMD_TEXTUREWAD]);\r
841   Texture_ShowDirectory();\r
842 }\r
843 \r
844 // scroll origin so the current texture is completely on screen\r
845 // if current texture is not displayed, nothing is changed\r
846 void Texture_ResetPosition()\r
847 {\r
848   qtexture_t  *q;\r
849   int  x,y;\r
850 \r
851   //this shouldn't ever happen, we startup with notex\r
852   if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) {\r
853     return;\r
854   }\r
855 \r
856   // otherwise position with current texture shown\r
857   // this used to be in Texture_SetTexture\r
858   Texture_StartPos ();\r
859   while (1)\r
860   {\r
861     // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture\r
862     Texture_NextPos (&x, &y);\r
863     q = current_texture;\r
864     // if the current texture never found (because // 'show shaders' is off,\r
865     // for example), do nothing\r
866     if (!q) \r
867       break;\r
868     \r
869     int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100));\r
870     // we have found when texdef->name and the shader name match\r
871     // NOTE: as everywhere else for our comparisons, we are not case sensitive\r
872     if (!strcmpi( g_qeglobals.d_texturewin.texdef.GetName(), pCurrentShader->getName() ))\r
873     {\r
874       // take care of calls before initialized\r
875       if ( !g_qeglobals.d_texturewin.height) {\r
876         g_qeglobals.d_texturewin.originy = 0;\r
877         break;\r
878       }\r
879       // if the bottom of our selected texture will fit with origin 0, use that\r
880       // to prevent scrolling uglyness (stuff scrolled off screen when \r
881       // everything would fit)\r
882       if ( -(y -nHeight-2*FONT_HEIGHT) <  g_qeglobals.d_texturewin.height) {\r
883         g_qeglobals.d_texturewin.originy = 0;\r
884         break;\r
885       }\r
886       // if current is off the top of the window, move it to the top\r
887       if (y > g_qeglobals.d_texturewin.originy)\r
888       {\r
889         g_qeglobals.d_texturewin.originy = y;\r
890         break;\r
891       }\r
892 \r
893       // if current is off the bottom, put it on the bottom\r
894       if (y-nHeight-2*FONT_HEIGHT < g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height)\r
895       {\r
896         g_qeglobals.d_texturewin.originy = y-nHeight-2*FONT_HEIGHT+g_qeglobals.d_texturewin.height;\r
897         break;\r
898       }\r
899       // if we made it here, it should already be in view\r
900       break;\r
901     }\r
902   }\r
903   Sys_UpdateWindows (W_TEXTURE);\r
904 }\r
905 \r
906 /*\r
907 ==============\r
908 Texture_ShowAll\r
909 will set the IsDisplayed flag on all the active shaders, so we see everything that's currently in memory\r
910 ==============\r
911 */\r
912 void Texture_ShowAll()\r
913 {\r
914   char name[1024];\r
915 \r
916 #ifdef _DEBUG\r
917   if (g_bShowAllShaders)\r
918     Sys_Printf("WARNING: already showing all shaders\n");\r
919 #endif\r
920   QERApp_ActiveShaders_SetDisplayed(true);\r
921   g_bShowAllShaders = true;\r
922   // put some information in the texture window title?\r
923   sprintf (name, "Textures: in use");\r
924   gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name);\r
925   Sys_UpdateWindows (W_TEXTURE);\r
926 }\r
927 \r
928 /*\r
929 ==============\r
930 Texture_ShowInuse\r
931 clear all IsDisplayed flags\r
932 scan the map, set IsInUse (will set IsDisplayed on the way)\r
933 NOTE: don't sort the textures, don't update the windows (it's used in several contexts, not always necessary to do either)\r
934 ==============\r
935 */\r
936 void WINAPI Texture_ShowInuse (void)\r
937 {\r
938   face_t  *f;\r
939   brush_t *b;\r
940   char  name[1024];\r
941 \r
942   g_qeglobals.d_texturewin.originy = 0;\r
943 \r
944   // purge\r
945   QERApp_ActiveShaders_SetDisplayed(false);\r
946   // scan and only display in-use stuff\r
947   Sys_Status("Selecting active textures", 0);\r
948 \r
949   for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next)\r
950   {\r
951     if (b->patchBrush)\r
952     {\r
953       b->pPatch->pShader->SetInUse(true);\r
954     } else\r
955     {\r
956       for (f=b->brush_faces ; f ; f=f->next)\r
957       {\r
958         f->pShader->SetInUse(true);\r
959       }\r
960     }\r
961   }\r
962   for (b=selected_brushes.next ; b != NULL && b != &selected_brushes ; b=b->next)\r
963   {\r
964     if (b->patchBrush)\r
965     {\r
966       b->pPatch->pShader->SetInUse(true);\r
967     } else\r
968     {\r
969       for (f=b->brush_faces ; f ; f=f->next)\r
970       {\r
971         f->pShader->SetInUse(true);\r
972       }\r
973     }\r
974   }\r
975 \r
976   // we are no longer showing everything\r
977   g_bShowAllShaders = false;\r
978   // put some information in the texture window title?\r
979   sprintf (name, "Textures: in use");\r
980   gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name);\r
981 \r
982 \r
983   // select the first texture in the list\r
984   if (!g_qeglobals.d_texturewin.texdef.GetName()[0])\r
985   {\r
986     SelectTexture (16, g_qeglobals.d_texturewin.height -16, false);\r
987   }\r
988 }\r
989 \r
990 void Texture_ShowStartupShaders()\r
991 {\r
992   if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_COMMON)\r
993   {\r
994     // RIANT\r
995     // HACK FOR JK2 SUPPORT\r
996     if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game")\r
997     {\r
998       strcpy (texture_directory, "system/");\r
999     }\r
1000     // RIANT\r
1001     // HACK FOR SOF2 SUPPORT\r
1002     else if (g_pGameDescription->mGameFile == "sof2.game")\r
1003     {\r
1004       strcpy (texture_directory, "tools/");\r
1005     }\r
1006     else strcpy (texture_directory, "common/");\r
1007     Texture_ShowDirectory ();\r
1008   }\r
1009 \r
1010   if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_ALL) {\r
1011     int    count;\r
1012     char   filename[1024];\r
1013     char   *pBuff;\r
1014     char   dirstring[NAME_MAX];\r
1015     int    nLen;\r
1016     GSList *shaderfiles = NULL;\r
1017 \r
1018     strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer());\r
1019     count = vfsGetFileCount(filename, 0);\r
1020     if (count == 0)\r
1021     {\r
1022       Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer());\r
1023       return;\r
1024     }\r
1025 \r
1026     if (!vfsGetFullPath(filename, 0, 0))\r
1027     {\r
1028       Sys_FPrintf(SYS_ERR, "Couldn't find full path for '%s'\n", g_pGameDescription->mShaderlist.GetBuffer());\r
1029       Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n");\r
1030       return;\r
1031     }\r
1032 \r
1033     Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0));\r
1034     nLen = vfsLoadFile (filename, reinterpret_cast<void**>(&pBuff), 0);\r
1035     if (nLen > 0)\r
1036     {\r
1037       StartTokenParsing(pBuff);\r
1038       nLen = 0;\r
1039       while (GetToken(true))\r
1040       {\r
1041         GSList *tmp;\r
1042         bool found = false;\r
1043 \r
1044         // each token should be a shader filename\r
1045         sprintf(dirstring, "%s.shader", token);\r
1046 \r
1047         for (tmp = shaderfiles; tmp != NULL; tmp = tmp->next)\r
1048         {\r
1049           if (!strcmp (dirstring, (char*)tmp->data))\r
1050           {\r
1051             found = true;\r
1052             Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data);\r
1053             break;\r
1054           }\r
1055         }\r
1056 \r
1057         if (!found)\r
1058         {\r
1059           shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring));\r
1060           strcpy (texture_directory, dirstring);\r
1061           Texture_ShowDirectory ();\r
1062           nLen++;\r
1063         }\r
1064       }\r
1065       g_free(pBuff);\r
1066     }\r
1067   }\r
1068 }\r
1069 \r
1070 /*\r
1071 ============================================================================\r
1072 \r
1073 TEXTURE LAYOUT\r
1074 \r
1075 TTimo: now based on a rundown through all the shaders\r
1076 nActiveShadersCount: number of shader that have a qtexture_t and may be displayed in the tex window\r
1077 nCurrentShader: index of active shader that has the current_texture\r
1078 pCurrentShader: IShader* for current shader\r
1079 NOTE: we expect the Active shaders count doesn't change during a Texture_StartPos .. Texture_NextPos cycle\r
1080   otherwise we may need to rely on a list instead of an array storage\r
1081 ============================================================================\r
1082 */\r
1083 \r
1084 void Texture_StartPos (void)\r
1085 {\r
1086   //++timo TODO: check use of current_texture and current_row?\r
1087   current_x = 8;\r
1088   current_y = -8;\r
1089   current_row = 0;\r
1090   nActiveShadersCount = QERApp_GetActiveShaderCount();\r
1091   nCurrentShader = -1;\r
1092   current_texture = NULL;\r
1093   pCurrentShader = NULL;\r
1094 }\r
1095 \r
1096 // if texture_showinuse jump over non in-use textures\r
1097 // it's not very clear what should be done here and what in Texture_Draw .. maybe merging the two would do good\r
1098 IShader* Texture_NextPos (int *x, int *y)\r
1099 {\r
1100   qtexture_t* q;\r
1101   while (1)\r
1102   {\r
1103     if (nCurrentShader >= nActiveShadersCount - 1)\r
1104     {\r
1105       // no more shaders\r
1106       current_texture = NULL;\r
1107       pCurrentShader = NULL;\r
1108       return NULL;\r
1109     }\r
1110     nCurrentShader++;\r
1111     pCurrentShader = QERApp_ActiveShader_ForIndex(nCurrentShader);\r
1112     if (pCurrentShader == NULL)\r
1113     {\r
1114       Sys_Printf("ERROR: unexpected pCurrentShader == NULL in Texture_NextPos\n");\r
1115       return NULL;\r
1116     }\r
1117     current_texture = pCurrentShader->getTexture();\r
1118     q = current_texture;\r
1119 \r
1120     if (!q)\r
1121     {\r
1122       Sys_Printf("WARNING: found an IShader without qtexture_t in Texture_NextPos\n");\r
1123       return NULL;\r
1124     }\r
1125 \r
1126     /*\r
1127     Never show anything other than "textures/" path,\r
1128     This is for q1/q2/q3 .map format, which expects "textures/" path on everything we apply\r
1129     */\r
1130     if(strncmp(pCurrentShader->getName(), "textures/", 9) != 0)\r
1131       continue;\r
1132 \r
1133     // don't show shaders?\r
1134     if (!(g_PrefsDlg.m_bShowShaders || pCurrentShader->IsDefault()))\r
1135       continue;\r
1136 \r
1137     if (g_PrefsDlg.m_bTextureWindow)\r
1138     {\r
1139       // some basic filtering\r
1140       if (!g_pParentWnd->GetTexWnd()->CheckFilter( pCurrentShader->getName() ))\r
1141         continue;\r
1142     }\r
1143 \r
1144     //++timo FIXME: texture_showinuse is useless? with the menu and reload we just refresh the IsDisplayed flag\r
1145     // but the IsInUse is only relevant to draw the green outline\r
1146     if (pCurrentShader->IsDisplayed())\r
1147       break;\r
1148 \r
1149     continue;\r
1150   }\r
1151 \r
1152   int nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100));\r
1153   int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100));\r
1154   if (current_x + nWidth > g_qeglobals.d_texturewin.width-8 && current_row)\r
1155   { // go to the next row unless the texture is the first on the row\r
1156     current_x = 8;\r
1157     current_y -= current_row + FONT_HEIGHT + 4;\r
1158     current_row = 0;\r
1159   }\r
1160 \r
1161   *x = current_x;\r
1162   *y = current_y;\r
1163 \r
1164   // Is our texture larger than the row? If so, grow the\r
1165   // row height to match it\r
1166 \r
1167   if (current_row < nHeight)\r
1168     current_row = nHeight;\r
1169 \r
1170   // never go less than 64, or the names get all crunched up\r
1171   current_x += nWidth < 64 ? 64 : nWidth;\r
1172   current_x += 8;\r
1173 \r
1174   return pCurrentShader;\r
1175 }\r
1176 \r
1177 /*\r
1178 ============================================================================\r
1179 \r
1180   MOUSE ACTIONS\r
1181 \r
1182 ============================================================================\r
1183 */\r
1184 \r
1185 static  int textures_cursorx, textures_cursory;\r
1186 \r
1187 /*\r
1188 ============\r
1189 Texture_SetTexture\r
1190 \r
1191 brushprimit_texdef must be understood as a qtexture_t with width=2 height=2 ( the default one )\r
1192 ============\r
1193 */\r
1194 \r
1195 //++timo NOTE: this is a mix of Shader module stuff and texture explorer\r
1196 // it might need to be split in parts or moved out .. dunno\r
1197 void WINAPI Texture_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef *pTexdef, bool bSetSelection )\r
1198 {\r
1199   if (texdef->GetName()[0] == '(')\r
1200   {\r
1201     Sys_Status("Can't select an entity texture", 0);\r
1202     return;\r
1203   }\r
1204   g_qeglobals.d_texturewin.texdef = *texdef;\r
1205   g_qeglobals.d_texturewin.texdef.flags &= ~SURF_KEEP;\r
1206   g_qeglobals.d_texturewin.texdef.contents &= ~CONTENTS_KEEP;\r
1207   // store the shader pointer\r
1208   // NOTE: maybe passing the shader pointer would help?\r
1209   g_qeglobals.d_texturewin.pShader->DecRef();\r
1210   g_qeglobals.d_texturewin.pShader = QERApp_Shader_ForName(texdef->GetName());\r
1211   g_qeglobals.d_texturewin.pShader->IncRef();\r
1212   // set this shader as in use\r
1213   g_qeglobals.d_texturewin.pShader->SetInUse( true );\r
1214   // store the texture coordinates for new brush primitive mode\r
1215   // be sure that all the callers are using the default 2x2 texture\r
1216   if (g_qeglobals.m_bBrushPrimitMode)\r
1217   {\r
1218     g_qeglobals.d_texturewin.brushprimit_texdef = *brushprimit_texdef;\r
1219   }\r
1220 \r
1221   g_dlgFind.updateTextures(texdef->GetName());\r
1222   if (!g_dlgFind.isOpen() && bSetSelection)\r
1223   {\r
1224     Select_SetTexture(texdef,brushprimit_texdef,bFitScale);\r
1225   }\r
1226 \r
1227   //plugins: send a message telling that the selected texture may have changed\r
1228   DispatchRadiantMsg( RADIANT_TEXTURE );\r
1229 \r
1230   // scroll origin so the texture is completely on screen\r
1231   // takes texdef from g_qeglobals.d_texturewin.texdef, set above\r
1232   Texture_ResetPosition();\r
1233 }\r
1234 \r
1235 void ViewShader(const char *pFile, const char *pName)\r
1236 {\r
1237   //  ask the vfs to build the full path to the file\r
1238   // (i.e. the first one found)\r
1239   char *fullName = vfsGetFullPath(pFile,0,0);\r
1240   if (fullName == NULL)\r
1241   {\r
1242     Sys_FPrintf (SYS_ERR, "Couldn't get a full path to the shader file: %s\n", pFile);\r
1243     return;\r
1244   }\r
1245 \r
1246   char* pBuff = NULL;\r
1247   int nSize = vfsLoadFullPathFile(fullName, reinterpret_cast<void**>(&pBuff));\r
1248   if (nSize <= 0)\r
1249   {\r
1250     Sys_FPrintf (SYS_ERR, "Failed to load shader file %s\n", fullName);\r
1251     return;\r
1252   }\r
1253   // look for the shader declaration\r
1254   int nStart;\r
1255   CString strFind = pName;\r
1256   CString strLook = pBuff;\r
1257   strLook.MakeLower();\r
1258   strFind.MakeLower();\r
1259   // offset used when jumping over commented out definitions\r
1260   int nOffset = 0;\r
1261   while (true)\r
1262   {\r
1263     nStart = strLook.Find(strFind, nOffset);\r
1264     if (nStart == -1)\r
1265       break;\r
1266     // we have found something, maybe it's a commented out shader name?\r
1267     char *strCheck = new char[strLook.GetLength()+1];\r
1268     strcpy( strCheck, strLook.GetBuffer() );\r
1269     strCheck[nStart] = 0;\r
1270     char *pCheck = strrchr( strCheck, '\n' );\r
1271     // if there's a commentary sign in-between we'll continue\r
1272     if (pCheck && strstr( pCheck, "//" ))\r
1273     {\r
1274       delete[] strCheck;\r
1275       nOffset = nStart + 1;\r
1276       continue;\r
1277     }\r
1278     delete[] strCheck;\r
1279     nOffset = nStart;\r
1280     break;\r
1281   }\r
1282   // now close the file\r
1283   g_free(pBuff);\r
1284 \r
1285   DoTextEditor (fullName, nOffset);\r
1286 }\r
1287 \r
1288 /*\r
1289 ==============\r
1290 SelectTexture\r
1291 \r
1292   By mouse click\r
1293 ==============\r
1294 */\r
1295 void SelectTexture (int mx, int my, bool bShift, bool bFitScale)\r
1296 {\r
1297   int   x, y;\r
1298   qtexture_t  *q;\r
1299   texdef_t  tex;\r
1300   brushprimit_texdef_t brushprimit_tex;\r
1301 \r
1302   my += g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height;\r
1303 \r
1304   Texture_StartPos ();\r
1305   while (1)\r
1306   {\r
1307     // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture\r
1308     Texture_NextPos (&x, &y);\r
1309     q = current_texture;\r
1310     if (!q)\r
1311       break;\r
1312     int nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100));\r
1313     int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100));\r
1314     if (mx > x && mx - x < nWidth\r
1315       && my < y && y - my < nHeight + FONT_HEIGHT)\r
1316     {\r
1317       if (bShift)\r
1318       {\r
1319         if (pCurrentShader->IsDefault())\r
1320           Sys_Printf("ERROR: %s is not a shader, it's a texture.\n", pCurrentShader->getName() );\r
1321         else\r
1322           ViewShader( pCurrentShader->getShaderFileName(), pCurrentShader->getName() );\r
1323       }\r
1324       else\r
1325       {\r
1326         memset (&tex, 0, sizeof(tex));\r
1327         memset (&brushprimit_tex, 0, sizeof(brushprimit_tex));\r
1328         if (g_qeglobals.m_bBrushPrimitMode)\r
1329         {\r
1330           // brushprimit fitted to a 2x2 texture\r
1331           brushprimit_tex.coords[0][0] = 1.0f;\r
1332           brushprimit_tex.coords[1][1] = 1.0f;\r
1333         }\r
1334         else\r
1335         {\r
1336           tex.scale[0] = g_pGameDescription->mTextureDefaultScale;\r
1337           tex.scale[1] = g_pGameDescription->mTextureDefaultScale;\r
1338         }\r
1339         tex.flags = pCurrentShader->getFlags();\r
1340         // TTimo - shader code cleanup\r
1341         // texdef.name is the name of the shader, not the name of the actual texture file\r
1342         tex.SetName(pCurrentShader->getName());\r
1343         // NOTE WARNING: Texture_SetTexture uses Texture_NextPos stuff to move the window position on to the texture\r
1344         // if there's some kind of fuckup in Texture_SetTexture you may end up with different pCurrentShader or even pCurrentShader == NULL\r
1345         // so we just consider pCurrentShader and current_texture are not valid after this point\r
1346         IShader *pAuxShader = pCurrentShader;\r
1347         Texture_SetTexture ( &tex, &brushprimit_tex, bFitScale, NULL); // Nurail\r
1348         CString strTex;\r
1349         CString strName;\r
1350         // if shader, print shader name, otherwise texture name\r
1351         //++timo FIXME: maybe CShader needs some properties between color / default / actual shader\r
1352 #ifdef _DEBUG\r
1353         // this one is never supposed to be set as current one\r
1354         if (pAuxShader->IsColor())\r
1355           Sys_Printf("ERROR: unexpected pCurrentShader->IsColor() in SelectTexture\n");\r
1356 #endif\r
1357         // NOTE: IsColor is false, IsDefault the only remaining property\r
1358         if (pAuxShader->IsDefault())\r
1359         {\r
1360           strName = q->name;\r
1361           // remove the "textures/" if needed\r
1362           if (strName.Find("textures/")!=-1)\r
1363             strName = strName.Mid(9);\r
1364         }\r
1365         else\r
1366         {\r
1367           strName = pAuxShader->getName();\r
1368         }\r
1369         strTex.Format("%s W: %i H: %i", strName.GetBuffer(), q->width, q->height);\r
1370         g_pParentWnd->SetStatusText(3, strTex);\r
1371       }\r
1372       return;\r
1373     }\r
1374   }\r
1375   \r
1376   Sys_Status("Did not select a texture", 0);\r
1377 }\r
1378 \r
1379 /*\r
1380 ==============\r
1381 Texture_MouseDown\r
1382 ==============\r
1383 */\r
1384 void Texture_MouseDown (int x, int y, int buttons)\r
1385 {\r
1386   Sys_GetCursorPos (&textures_cursorx, &textures_cursory);\r
1387 \r
1388   // lbutton = select texture\r
1389   if (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_SHIFT) || buttons == (MK_LBUTTON | MK_CONTROL))\r
1390   {\r
1391     SelectTexture (x, g_qeglobals.d_texturewin.height - 1 - y, buttons & MK_SHIFT, buttons & MK_CONTROL);\r
1392     UpdateSurfaceDialog();\r
1393     UpdatePatchInspector();\r
1394   }\r
1395 }\r
1396 \r
1397 /*\r
1398 ==============\r
1399 Texture_MouseMoved\r
1400 ==============\r
1401 */\r
1402 \r
1403 void Texture_MouseMoved (int x, int y, int buttons)\r
1404 {\r
1405   int scale = 1;\r
1406 \r
1407   if ( buttons & MK_SHIFT )\r
1408     scale = 4;\r
1409 \r
1410   // rbutton = drag texture origin\r
1411   if (buttons & MK_RBUTTON)\r
1412   {\r
1413     Sys_GetCursorPos (&x, &y);\r
1414     if ( y != textures_cursory)\r
1415     {\r
1416       g_qeglobals.d_texturewin.originy += ( y-textures_cursory) * scale;\r
1417       if (g_qeglobals.d_texturewin.originy > 0)\r
1418         g_qeglobals.d_texturewin.originy = 0;\r
1419       Sys_SetCursorPos (textures_cursorx, textures_cursory);\r
1420 \r
1421       // (g_PrefsDlg.m_bTextureScrollbar && g_qeglobals_gui.d_texture_scroll != NULL)\r
1422       // fixes broken texture scrolling when scrollbar is disabled\r
1423       GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll));\r
1424       gtk_adjustment_set_value (vadjustment, abs(g_qeglobals.d_texturewin.originy));\r
1425       //\r
1426     }\r
1427     return;\r
1428   }\r
1429 }\r
1430 \r
1431 /*\r
1432 ============================================================================\r
1433 \r
1434 DRAWING\r
1435 \r
1436 ============================================================================\r
1437 */\r
1438 \r
1439 int imax(int iFloor, int i) { if (i>iFloor) return iFloor;return i;}\r
1440 \r
1441 /*\r
1442 ============\r
1443 Texture_Draw\r
1444 TTimo: relying on the shaders list to display the textures\r
1445 we must query all qtexture_t* to manage and display through the IShaders interface\r
1446 this allows a plugin to completely override the texture system\r
1447 ============\r
1448 */\r
1449 void Texture_Draw (int width, int height)\r
1450 {\r
1451   int x, y, last_y = 0, last_height = 0, nWidth, nHeight;\r
1452   qtexture_t *q;\r
1453   char *name;\r
1454 \r
1455   qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][0],\r
1456                  g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][1],\r
1457                  g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][2], 0);\r
1458   qglViewport (0,0,width,height);\r
1459   qglMatrixMode(GL_PROJECTION);\r
1460   qglLoadIdentity ();\r
1461 \r
1462   qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
1463   qglDisable (GL_DEPTH_TEST);\r
1464   qglDisable(GL_BLEND);\r
1465   qglOrtho (0, width, g_qeglobals.d_texturewin.originy-height, g_qeglobals.d_texturewin.originy, -100, 100);\r
1466   qglEnable (GL_TEXTURE_2D);\r
1467 \r
1468   qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);\r
1469   g_qeglobals.d_texturewin.width = width;\r
1470   g_qeglobals.d_texturewin.height = height;\r
1471 \r
1472   Texture_StartPos();\r
1473   for (;;)\r
1474   {\r
1475     // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture\r
1476     Texture_NextPos (&x, &y);\r
1477     q = current_texture;\r
1478     if (!q)\r
1479       break;\r
1480 \r
1481     nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100));\r
1482     nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100));\r
1483 \r
1484     if (y != last_y)\r
1485     {\r
1486       last_y = y;\r
1487       last_height = 0;\r
1488     }\r
1489     last_height = MAX (nHeight, last_height);\r
1490 \r
1491     // Is this texture visible?\r
1492     if ((y-nHeight-FONT_HEIGHT < g_qeglobals.d_texturewin.originy)\r
1493         && (y > g_qeglobals.d_texturewin.originy - height))\r
1494     {\r
1495       // borders rules:\r
1496       // if it's the current texture, draw a thick red line, else:\r
1497       // shaders have a white border, simple textures don't\r
1498       // if !texture_showinuse: (some textures displayed may not be in use)\r
1499       // draw an additional square around with 0.5 1 0.5 color\r
1500       if (!strcmpi(g_qeglobals.d_texturewin.texdef.GetName(), pCurrentShader->getName()))\r
1501       {\r
1502               qglLineWidth (3);\r
1503               qglColor3f (1,0,0);\r
1504               qglDisable (GL_TEXTURE_2D);\r
1505 \r
1506               qglBegin (GL_LINE_LOOP);\r
1507               qglVertex2f (x-4,y-FONT_HEIGHT+4);\r
1508               qglVertex2f (x-4,y-FONT_HEIGHT-nHeight-4);\r
1509               qglVertex2f (x+4+nWidth,y-FONT_HEIGHT-nHeight-4);\r
1510               qglVertex2f (x+4+nWidth,y-FONT_HEIGHT+4);\r
1511               qglEnd ();\r
1512 \r
1513               qglEnable (GL_TEXTURE_2D);\r
1514               qglLineWidth (1);\r
1515       }\r
1516       else\r
1517       {\r
1518               qglLineWidth (1);\r
1519               // shader border:\r
1520               if (!pCurrentShader->IsDefault())\r
1521               {\r
1522                 qglColor3f (1,1,1);\r
1523                 qglDisable (GL_TEXTURE_2D);\r
1524 \r
1525                 qglBegin (GL_LINE_LOOP);\r
1526                 qglVertex2f (x-1,y+1-FONT_HEIGHT);\r
1527                 qglVertex2f (x-1,y-nHeight-1-FONT_HEIGHT);\r
1528                 qglVertex2f (x+1+nWidth,y-nHeight-1-FONT_HEIGHT);\r
1529                 qglVertex2f (x+1+nWidth,y+1-FONT_HEIGHT);\r
1530                 qglEnd ();\r
1531                 qglEnable (GL_TEXTURE_2D);\r
1532               }\r
1533 \r
1534               // highlight in-use textures\r
1535               if (pCurrentShader->IsInUse())\r
1536               {\r
1537                 qglColor3f (0.5,1,0.5);\r
1538                 qglDisable (GL_TEXTURE_2D);\r
1539                 qglBegin (GL_LINE_LOOP);\r
1540                 qglVertex2f (x-3,y+3-FONT_HEIGHT);\r
1541                 qglVertex2f (x-3,y-nHeight-3-FONT_HEIGHT);\r
1542                 qglVertex2f (x+3+nWidth,y-nHeight-3-FONT_HEIGHT);\r
1543                 qglVertex2f (x+3+nWidth,y+3-FONT_HEIGHT);\r
1544                 qglEnd ();\r
1545                 qglEnable (GL_TEXTURE_2D);\r
1546               }\r
1547       }\r
1548 \r
1549       // Draw the texture\r
1550       qglBindTexture (GL_TEXTURE_2D, q->texture_number);\r
1551       QE_CheckOpenGLForErrors();\r
1552       qglColor3f (1,1,1);\r
1553       qglBegin (GL_QUADS);\r
1554       qglTexCoord2f (0,0);\r
1555       qglVertex2f (x,y-FONT_HEIGHT);\r
1556       qglTexCoord2f (1,0);\r
1557       qglVertex2f (x+nWidth,y-FONT_HEIGHT);\r
1558       qglTexCoord2f (1,1);\r
1559       qglVertex2f (x+nWidth,y-FONT_HEIGHT-nHeight);\r
1560       qglTexCoord2f (0,1);\r
1561       qglVertex2f (x,y-FONT_HEIGHT-nHeight);\r
1562       qglEnd ();\r
1563 \r
1564       // draw the texture name\r
1565       qglDisable (GL_TEXTURE_2D);\r
1566       qglColor3f (1,1,1);\r
1567 \r
1568       qglRasterPos2f (x, y-FONT_HEIGHT+2);\r
1569 \r
1570       // don't draw the directory name\r
1571       name = (char*)pCurrentShader->getName();\r
1572       name += strlen(name);\r
1573       while(name != (char*)pCurrentShader->getName() && *(name-1) != '/' && *(name-1) != '\\')\r
1574         name--;\r
1575 \r
1576       gtk_glwidget_print_string(name);\r
1577       qglEnable (GL_TEXTURE_2D);\r
1578     }\r
1579   }\r
1580 \r
1581   g_qeglobals.d_texturewin.m_nTotalHeight = abs(y) + last_height + FONT_HEIGHT + 4;\r
1582 \r
1583   // reset the current texture\r
1584   qglBindTexture(GL_TEXTURE_2D, 0);\r
1585   qglFinish();\r
1586 }\r
1587 \r
1588 //++timo seems we only know hard inits now..\r
1589 //void Texture_Init (bool bHardInit)\r
1590 void Texture_Init()\r
1591 {\r
1592   g_qeglobals.d_qtextures = NULL;\r
1593   // initialize the qtexture map\r
1594   if (g_qeglobals.d_qtexmap)\r
1595   {\r
1596     Sys_FPrintf(SYS_ERR, "TODO: delete g_qeglobals.d_qtexmap in Texture_Init\n");\r
1597   }\r
1598   g_qeglobals.d_qtexmap = g_hash_table_new (g_str_hash, g_str_equal);\r
1599   // initialize .. in some cases if no default texture / project loaded it crashes\r
1600   memset( &g_qeglobals.d_texturewin.texdef, 0, sizeof(g_qeglobals.d_texturewin.texdef) );\r
1601   g_qeglobals.d_texturewin.texdef.SetName(SHADER_NOT_FOUND);\r
1602   g_qeglobals.d_texturewin.pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND);\r
1603 }\r
1604 \r
1605 // FIXME TTimo this needs to move to the shader module along with l_shaderlist move\r
1606 // preload shader files that have been listed in shaderlist.txt\r
1607 void PreloadShaders()\r
1608 {\r
1609   GSList *lst = l_shaderfiles;\r
1610   Str shadername;\r
1611   while (lst)\r
1612   {\r
1613     shadername = g_pGameDescription->mShaderPath;\r
1614     shadername += (char*)lst->data;\r
1615     QERApp_LoadShaderFile(shadername.GetBuffer());\r
1616     lst = lst->next;\r
1617   }\r
1618 }\r
1619 \r
1620 // TTimo: modified to expect the reletive path to the skin as input\r
1621 // will look into pak files if necessary\r
1622 // uses the shader code to load the texture Try_Texture_ForName\r
1623 // modified SkinInfo accordingly to store the qtexture_t and shader name (reletive version)\r
1624 // the .md3 have bundled filetype extension, but they don't fit with the actual data\r
1625 //   ex: models/mapobjects/gargoyle.tga doesn't exist, but models/mapobjects/gargoyle.jpg can be used instead\r
1626 //   so we remove the extension before load attempt\r
1627 int WINAPI Texture_LoadSkin(char *pName, int *pnWidth, int *pnHeight)\r
1628 {\r
1629   //  byte *pic = NULL;\r
1630   //  byte *pic32 = NULL;\r
1631   int nTex = -1;\r
1632   qtexture_t *qtex;\r
1633   SkinInfo *pInfo;\r
1634   const char *pCleanName;\r
1635 \r
1636   int nSize = g_lstSkinCache.GetSize();\r
1637   pCleanName = QERApp_CleanTextureName( pName, false );\r
1638   for (int i = 0; i < nSize; i++)\r
1639   {\r
1640     SkinInfo *pInfo = reinterpret_cast<SkinInfo*>(g_lstSkinCache.GetAt(i));\r
1641     if (pInfo)\r
1642     {\r
1643       if (stricmp(pCleanName, pInfo->m_strName) == 0)\r
1644       {\r
1645         return pInfo->m_nTextureBind;\r
1646       }\r
1647     }\r
1648   }\r
1649 \r
1650   // if the load is successfull, we get back a qtexture_t\r
1651   // we don't need to free it, it's in g_qeglobals.d_qtextures\r
1652   // NOTE: we need to free the SkinInfo though..\r
1653   qtex = QERApp_Try_Texture_ForName( pCleanName );\r
1654   if (qtex)\r
1655   {\r
1656     nTex = qtex->texture_number;\r
1657     pInfo = new SkinInfo(qtex->name, nTex, qtex);\r
1658   } else\r
1659   {\r
1660     pInfo = new SkinInfo(pCleanName, -1, NULL);\r
1661   }\r
1662   g_lstSkinCache.Add(pInfo);\r
1663 \r
1664   return nTex;\r
1665 }\r
1666 \r
1667 bool TexWnd::CheckFilter( const char* name )\r
1668 {\r
1669   const char* buf = gtk_entry_get_text (GTK_ENTRY (m_pFilter));\r
1670   if (strstr( name, buf ) != 0)\r
1671     return true;\r
1672   return false;\r
1673 }\r
1674 \r
1675 // =============================================================================\r
1676 // static functions\r
1677 \r
1678 static void vertical_scroll (GtkWidget *widget, gpointer data)\r
1679 {\r
1680   ((TexWnd*)data)->OnVScroll ();\r
1681 }\r
1682 \r
1683 static void filter_changed (GtkWidget *widget, gpointer data)\r
1684 {\r
1685   CString str;\r
1686   str = gtk_entry_get_text (GTK_ENTRY (widget));\r
1687   ((TexWnd*)data)->UpdateFilter (str);\r
1688 }\r
1689 \r
1690 // =============================================================================\r
1691 // TexWnd class\r
1692 \r
1693 TexWnd::TexWnd()\r
1694 : GLWindow (FALSE)\r
1695 {\r
1696   m_pFilter = NULL;\r
1697   m_bNeedRange = true;\r
1698 }\r
1699 \r
1700 TexWnd::~TexWnd()\r
1701 {\r
1702 }\r
1703 \r
1704 void TexWnd::OnCreate ()\r
1705 {\r
1706   if (!MakeCurrent ())\r
1707     Error ("glMakeCurrent in TexWnd::OnCreate failed");\r
1708 \r
1709   g_qeglobals_gui.d_texture = m_pWidget;\r
1710   g_nTextureOffset = 0;\r
1711 \r
1712   GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll));\r
1713   gtk_signal_connect (GTK_OBJECT (vadjustment), "value_changed", GTK_SIGNAL_FUNC (vertical_scroll), this);\r
1714 \r
1715   if (g_PrefsDlg.m_bTextureScrollbar)\r
1716     gtk_widget_show (g_qeglobals_gui.d_texture_scroll);\r
1717   else\r
1718     gtk_widget_hide (g_qeglobals_gui.d_texture_scroll);\r
1719   m_bNeedRange = true;\r
1720 \r
1721   gtk_signal_connect (GTK_OBJECT (m_pFilter), "changed", GTK_SIGNAL_FUNC (filter_changed), this);\r
1722   if (g_PrefsDlg.m_bTextureWindow)\r
1723     gtk_widget_show (m_pFilter);\r
1724 }\r
1725 \r
1726 void TexWnd::UpdateFilter(const char* pFilter)\r
1727 {\r
1728   g_bFilterEnabled = false;\r
1729   if (pFilter)\r
1730   {\r
1731     g_strFilter = pFilter;\r
1732     if (g_strFilter.GetLength() > 0)\r
1733       g_bFilterEnabled = true;\r
1734     QERApp_SortActiveShaders();\r
1735   }\r
1736   Sys_UpdateWindows (W_TEXTURE);\r
1737 }\r
1738 \r
1739 void TexWnd::OnSize (int cx, int cy)\r
1740 {\r
1741   m_bNeedRange = true;\r
1742 }\r
1743 \r
1744 void TexWnd::OnExpose ()\r
1745 {\r
1746   int nOld = g_qeglobals.d_texturewin.m_nTotalHeight;\r
1747   if (!MakeCurrent ())\r
1748   {\r
1749     Sys_Printf("ERROR: glXMakeCurrent failed..\n ");\r
1750     Sys_Printf("Please restart Radiant if the Texture view is not working\n");\r
1751   } else\r
1752   {\r
1753     QE_CheckOpenGLForErrors();\r
1754     Texture_Draw (m_pWidget->allocation.width, m_pWidget->allocation.height - g_nTextureOffset);\r
1755     QE_CheckOpenGLForErrors();\r
1756     SwapBuffers ();\r
1757   }\r
1758   if (g_PrefsDlg.m_bTextureScrollbar && (m_bNeedRange || g_qeglobals.d_texturewin.m_nTotalHeight != nOld))\r
1759   {\r
1760     GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll));\r
1761 \r
1762     vadjustment->value = -g_qeglobals.d_texturewin.originy;\r
1763     vadjustment->page_size = m_pWidget->allocation.height;\r
1764     vadjustment->page_increment = m_pWidget->allocation.height/2;\r
1765     vadjustment->step_increment = 20;\r
1766     vadjustment->lower = 0;\r
1767     vadjustment->upper = g_qeglobals.d_texturewin.m_nTotalHeight;\r
1768 \r
1769     gtk_signal_emit_by_name (GTK_OBJECT (vadjustment), "changed");\r
1770 \r
1771     m_bNeedRange = false;\r
1772   }\r
1773 }\r
1774 \r
1775 void TexWnd::OnLButtonDown (guint32 flags, int pointx, int pointy)\r
1776 {\r
1777   SetCapture ();\r
1778   Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags);\r
1779 }\r
1780 \r
1781 void TexWnd::OnRButtonDown (guint32 flags, int pointx, int pointy)\r
1782 {\r
1783   SetCapture ();\r
1784   Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags);\r
1785 }\r
1786 \r
1787 void TexWnd::OnMButtonDown (guint32 flags, int pointx, int pointy)\r
1788 {\r
1789   SetCapture ();\r
1790   Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags);\r
1791 }\r
1792 \r
1793 void TexWnd::OnLButtonUp (guint32 flags, int pointx, int pointy)\r
1794 {\r
1795   ReleaseCapture ();\r
1796   // NOTE TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23\r
1797   DragDropTexture (flags, pointx, pointy);\r
1798 }\r
1799 \r
1800 void TexWnd::OnRButtonUp (guint32 flags, int pointx, int pointy)\r
1801 {\r
1802   ReleaseCapture ();\r
1803 }\r
1804 \r
1805 void TexWnd::OnMButtonUp (guint32 flags, int pointx, int pointy)\r
1806 {\r
1807   ReleaseCapture ();\r
1808 }\r
1809 \r
1810 void TexWnd::OnMouseMove (guint32 flags, int pointx, int pointy)\r
1811 {\r
1812   Texture_MouseMoved (pointx, pointy - g_nTextureOffset, flags);\r
1813   // if scrollbar is hidden, we don't seem to get an update\r
1814   if( !g_PrefsDlg.m_bTextureScrollbar )\r
1815     RedrawWindow ();\r
1816 }\r
1817 \r
1818 void TexWnd::OnVScroll ()\r
1819 {\r
1820   GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll));\r
1821 \r
1822   g_qeglobals.d_texturewin.originy = - (int)vadjustment->value;\r
1823   RedrawWindow ();\r
1824 }\r
1825 \r
1826 void TexWnd::UpdatePrefs()\r
1827 {\r
1828   if (g_PrefsDlg.m_bTextureWindow)\r
1829     gtk_widget_show (m_pFilter);\r
1830   else\r
1831     gtk_widget_hide (m_pFilter);\r
1832 \r
1833   if (g_PrefsDlg.m_bTextureScrollbar)\r
1834     gtk_widget_show (g_qeglobals_gui.d_texture_scroll);\r
1835   else\r
1836     gtk_widget_hide (g_qeglobals_gui.d_texture_scroll);\r
1837   m_bNeedRange = true;\r
1838   RedrawWindow ();\r
1839 }\r
1840 \r
1841 void TexWnd::FocusEdit()\r
1842 {\r
1843   if (GTK_WIDGET_VISIBLE (m_pFilter))\r
1844     gtk_window_set_focus (GTK_WINDOW (g_pParentWnd->m_pWidget), m_pFilter);\r
1845 }\r
1846 \r
1847 void TexWnd::OnMouseWheel(bool bUp)\r
1848 {\r
1849   if (bUp)\r
1850   {\r
1851     if(g_qeglobals.d_texturewin.originy < 0) {\r
1852       g_qeglobals.d_texturewin.originy += g_PrefsDlg.m_nWheelInc;\r
1853       // clamp so we don't get jiggle if moved by less than scrollwheel increment\r
1854       if(g_qeglobals.d_texturewin.originy > 0) {\r
1855         g_qeglobals.d_texturewin.originy = 0;\r
1856       }\r
1857     }\r
1858   }\r
1859   else\r
1860   {\r
1861     if(g_qeglobals.d_texturewin.originy > (-g_qeglobals.d_texturewin.m_nTotalHeight + g_qeglobals.d_texturewin.height))\r
1862       g_qeglobals.d_texturewin.originy -= g_PrefsDlg.m_nWheelInc;\r
1863   }\r
1864   GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll));\r
1865   gtk_adjustment_set_value (vadjustment, abs(g_qeglobals.d_texturewin.originy));\r
1866 \r
1867   RedrawWindow();\r
1868 }\r
1869 \r
1870 // NOTE TTimo\r
1871 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23\r
1872 void TexWnd::DragDropTexture (guint32 flags, int pointx, int pointy)\r
1873 {\r
1874   // This gets called from leftmouse up event. We see if the mouseup is above\r
1875   // the camwindow. If this is the case do a trace for a surface. If we hit a\r
1876   // surface, texture it with the current texture.\r
1877 \r
1878   int     m_ptXcheck, m_ptYcheck;\r
1879   int     m_ptX, m_ptY;\r
1880   GtkWidget *widget;\r
1881   gint x, y;\r
1882   vec3_t  dir;\r
1883   float   f, r, u;\r
1884   int     i;\r
1885 \r
1886   // we only want to catch a plain mouseevent\r
1887   if (flags)\r
1888     return;\r
1889 \r
1890   // see if we are above the camwindow\r
1891   Sys_GetCursorPos (&m_ptX, &m_ptY);\r
1892 \r
1893   if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating)\r
1894     widget = g_pParentWnd->GetCamWnd()->m_pParent;\r
1895   else\r
1896     widget = g_pParentWnd->GetCamWnd()->GetWidget();\r
1897 \r
1898   get_window_pos (widget, &x, &y);\r
1899 \r
1900   if (m_ptX < x || m_ptY < y ||\r
1901       m_ptX > x + widget->allocation.width ||\r
1902       m_ptY > y + widget->allocation.height)\r
1903     return;\r
1904 \r
1905   // check if the camwindow isn't being partially hidden by another window at this point\r
1906   // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=187\r
1907   m_ptXcheck = m_ptX;\r
1908   m_ptYcheck = m_ptY;\r
1909 \r
1910   if( g_pParentWnd->GetCamWnd()->GetWidget()->window != gdk_window_at_pointer( &m_ptXcheck, &m_ptYcheck ) )\r
1911     return;\r
1912 \r
1913   // calc ray direction\r
1914   x = m_ptX - x;\r
1915   y = g_pParentWnd->GetCamWnd()->Camera()->height - 1 - (m_ptY - y);\r
1916   u = (float)( y - ( g_pParentWnd->GetCamWnd()->Camera()->height * .5f ) ) / ( g_pParentWnd->GetCamWnd()->Camera()->height * .5f );\r
1917   r = (float)( x - ( g_pParentWnd->GetCamWnd()->Camera()->width * .5f ) ) / ( g_pParentWnd->GetCamWnd()->Camera()->width * .5f );\r
1918   f = 1;\r
1919 \r
1920   for (i=0 ; i<3 ; i++)\r
1921     dir[i] = g_pParentWnd->GetCamWnd()->Camera()->vpn[i] * f +\r
1922         g_pParentWnd->GetCamWnd()->Camera()->vright[i] * r +\r
1923         g_pParentWnd->GetCamWnd()->Camera()->vup[i] * u;\r
1924   VectorNormalize (dir, dir);\r
1925 \r
1926   // do a trace for a surface\r
1927         trace_t t;\r
1928 \r
1929         t = Test_Ray (g_pParentWnd->GetCamWnd()->Camera()->origin, dir, SF_SINGLEFACE);\r
1930 \r
1931   if (t.brush)\r
1932   {\r
1933     texdef_t  tex;\r
1934     brushprimit_texdef_t brushprimit_tex;\r
1935 \r
1936     memset (&tex, 0, sizeof(tex));\r
1937     memset (&brushprimit_tex, 0, sizeof(brushprimit_tex));\r
1938     if (g_qeglobals.m_bBrushPrimitMode)\r
1939     {\r
1940       // brushprimit fitted to a 2x2 texture\r
1941       brushprimit_tex.coords[0][0] = 1.0f;\r
1942       brushprimit_tex.coords[1][1] = 1.0f;\r
1943     } else\r
1944     {\r
1945       tex.scale[0] = g_pGameDescription->mTextureDefaultScale;\r
1946       tex.scale[1] = g_pGameDescription->mTextureDefaultScale;\r
1947     }\r
1948     tex.flags = g_qeglobals.d_texturewin.texdef.flags;\r
1949     tex.value = g_qeglobals.d_texturewin.texdef.value;\r
1950     tex.contents = g_qeglobals.d_texturewin.texdef.contents;\r
1951     // TTimo - shader code cleanup\r
1952     // texdef.name is the name of the shader, not the name of the actual texture file\r
1953     tex.SetName(g_qeglobals.d_texturewin.texdef.GetName());\r
1954 \r
1955     Undo_Start("set face textures");\r
1956           Undo_AddBrush(t.brush);\r
1957           SetFaceTexdef (t.face, &tex, &brushprimit_tex, false, NULL );\r
1958           Brush_Build(t.brush, false);\r
1959           Undo_EndBrush(t.brush);\r
1960           Undo_End();\r
1961 \r
1962     Sys_UpdateWindows (W_CAMERA);\r
1963     g_pParentWnd->OnTimer ();\r
1964   }\r
1965 }\r