2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\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
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
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
25 // Leonardo Zide (leo@lokigames.com)
\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
36 //#include <gdk/win32/gdkwin32.h>
\r
37 #include <gdk/gdkwin32.h>
\r
39 #if defined (__linux__) || defined (__APPLE__)
\r
40 #include <gdk/gdkx.h>
\r
43 #include <gtk/gtk.h>
\r
45 #include <sys/stat.h>
\r
47 #include "texwindow.h"
\r
49 #include "missing.h"
\r
50 #include "texmanip.h"
\r
52 #define TYP_MIPTEX 68
\r
53 static unsigned tex_palette[256];
\r
55 #define FONT_HEIGHT 10
\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
64 int g_nTextureOffset = 0;
\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
73 bool g_bFilterEnabled = false;
\r
74 CString g_strFilter;
\r
76 // texture layout functions
\r
77 // TTimo: now based on shaders
\r
78 int nActiveShadersCount;
\r
80 IShader* pCurrentShader;
\r
81 qtexture_t *current_texture = NULL;
\r
82 int current_x, current_y, current_row;
\r
84 // globals for textures
\r
85 int texture_nummenus;
\r
86 char texture_menunames[MAX_TEXTUREDIRS][128];
\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
94 void SelectTexture (int mx, int my, bool bShift, bool bFitScale=false);
\r
96 void Texture_MouseDown (int x, int y, int buttons);
\r
97 void Texture_MouseMoved (int x, int y, int buttons);
\r
99 CPtrArray g_lstSkinCache;
\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
106 int m_nTextureBind;
\r
107 qtexture_t *m_qtex;
\r
108 SkinInfo(const char *pName, int n, qtexture_t *qtex)
\r
111 m_nTextureBind = n;
\r
117 // =============================================================================
\r
118 // global functions
\r
120 // gets active texture extension
\r
122 // FIXME: fix this to be generic from project file
\r
124 int GetTextureExtensionCount()
\r
126 // hardcoded hack for png support
\r
127 if (g_pGameDescription->mGameFile == "sof2.game")
\r
133 const char* GetTextureExtension(int nIndex)
\r
153 Texture_InitPalette
\r
156 void Texture_InitPalette (byte *pal)
\r
161 byte gammatable[256];
\r
164 gamma = g_qeglobals.d_savedinfo.fGamma;
\r
168 for (i=0 ; i<256 ; i++)
\r
172 for (i=0 ; i<256 ; i++)
\r
174 inf = (int)( 255.0f * pow( ( i + 0.5f ) / 255.5f , gamma ) + 0.5f );
\r
179 gammatable[i] = inf;
\r
183 for (i=0 ; i<256 ; i++)
\r
185 r = gammatable[pal[0]];
\r
186 g = gammatable[pal[1]];
\r
187 b = gammatable[pal[2]];
\r
190 //v = (r<<24) + (g<<16) + (b<<8) + 255;
\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
200 void SetTexParameters (void)
\r
202 qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_mode );
\r
204 switch ( texture_mode )
\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
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
224 void Texture_SetMode(int iMenu)
\r
227 qboolean texturing = true;
\r
228 gpointer item = NULL;
\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
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
240 case ID_VIEW_LINEAR:
\r
241 item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_linear");
\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
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
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
256 case ID_TEXTURES_WIREFRAME:
\r
257 item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_wireframe");
\r
261 case ID_TEXTURES_FLATSHADE:
\r
262 item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_flatshade");
\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
272 g_bIgnoreCommands++;
\r
274 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
\r
275 g_bIgnoreCommands--;
\r
278 SetTexParameters ();
\r
280 if ( !texturing && iMenu == ID_TEXTURES_WIREFRAME)
\r
282 g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_wire;
\r
283 Map_BuildBrushData();
\r
284 Sys_UpdateWindows (W_ALL);
\r
286 } else if ( !texturing && iMenu == ID_TEXTURES_FLATSHADE)
\r
288 g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_solid;
\r
289 Map_BuildBrushData();
\r
290 Sys_UpdateWindows (W_ALL);
\r
294 for (qtexture_t *q = g_qeglobals.d_qtextures; q; q = q->next)
\r
296 qglBindTexture (GL_TEXTURE_2D, q->texture_number);
\r
297 SetTexParameters ();
\r
300 // select the default texture
\r
301 qglBindTexture( GL_TEXTURE_2D, 0 );
\r
305 if (g_pParentWnd->GetCamWnd()->Camera()->draw_mode != cd_texture)
\r
307 g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_texture;
\r
308 Map_BuildBrushData();
\r
311 Sys_UpdateWindows (W_ALL);
\r
315 gamma correction stuff
\r
316 took out of QERApp_LoadTextureRGBA for clarity
\r
318 byte g_gammatable[256];
\r
319 void ResampleGamma(float fGamma)
\r
324 for (i = 0; i < 256; i++)
\r
325 g_gammatable[i] = i;
\r
328 for (i = 0; i < 256; i++)
\r
330 inf = (int)( 255.0f * pow( (i + 0.5f) / 255.5f , fGamma ) + 0.5f );
\r
335 g_gammatable[i] = inf;
\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
345 qtexture_t *QERApp_LoadTextureRGBA(unsigned char* pPixels, int nWidth, int nHeight)
\r
347 static float fGamma = -1;
\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
354 if (fGamma != g_qeglobals.d_savedinfo.fGamma)
\r
356 fGamma = g_qeglobals.d_savedinfo.fGamma;
\r
357 ResampleGamma(fGamma);
\r
360 qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
\r
362 max_tex_size = 1024;
\r
364 qtexture_t *q = (qtexture_t*)g_malloc(sizeof(*q));
\r
366 q->height = nHeight;
\r
368 total[0] = total[1] = total[2] = 0.0f;
\r
370 // resample texture gamma according to user settings
\r
371 for (i = 0; i < (nCount * 4); i += 4)
\r
373 for (j = 0; j < 3; j++)
\r
375 total[j] += (pPixels + i)[j];
\r
376 byte b = (pPixels + i)[j];
\r
377 (pPixels + i)[j] = g_gammatable[b];
\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
385 qglGenTextures (1, &q->texture_number);
\r
387 qglBindTexture( GL_TEXTURE_2D, q->texture_number );
\r
389 SetTexParameters();
\r
391 width2 = 1; while (width2 < nWidth) width2 <<= 1;
\r
392 height2 = 1; while (height2 < nHeight) height2 <<= 1;
\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
401 if (!(width2 == nWidth && height2 == nHeight)) {
\r
403 outpixels = (byte *)malloc(width2 * height2 * 4);
\r
404 R_ResampleTexture(pPixels, nWidth, nHeight, outpixels, width2, height2, 4);
\r
407 outpixels = pPixels;
\r
410 while (width2 > width3 || height2 > height3)
\r
412 GL_MipReduce(outpixels, outpixels, width2, height2, width3, height3);
\r
414 if (width2 > width3)
\r
416 if (height2 > height3)
\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
423 GL_MipReduce(outpixels, outpixels, width2, height2, 1, 1);
\r
430 qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels);
\r
433 qglBindTexture(GL_TEXTURE_2D, 0);
\r
442 DumpUnreferencedShaders
\r
443 usefull function: dumps the list of .shader files that are not referenced to the console
\r
446 void DumpUnreferencedShaders()
\r
448 GSList *lst, *sh, *files;
\r
449 bool bFound = false;
\r
451 files = vfsGetFileList ("scripts", "shader");
\r
452 for (lst = files; lst; lst = lst->next)
\r
454 bool listed = false;
\r
456 for (sh = l_shaderfiles; sh != NULL; sh = g_slist_next (sh))
\r
457 if (!strcmp ((char*)sh->data, (char*)lst->data))
\r
468 Sys_FPrintf (SYS_WRN, "Following shader files are not referenced in shaderlist.txt:\n");
\r
470 Sys_FPrintf (SYS_WRN, "%s\n", (char*)lst->data);
\r
474 vfsClearFileDirList (&files);
\r
480 build a CStringList of shader names
\r
483 void BuildShaderList()
\r
486 char filename[1024];
\r
488 char dirstring[NAME_MAX];
\r
490 if (l_shaderfiles!=NULL)
\r
492 g_slist_free(l_shaderfiles);
\r
493 l_shaderfiles = NULL;
\r
496 if (g_pGameDescription->mGameFile != "hl.game")
\r
498 strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer());
\r
499 count = vfsGetFileCount(filename, 0 );
\r
502 Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer());
\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
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
514 Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0));
\r
515 nLen = vfsLoadFile (filename, reinterpret_cast<void**>(&pBuff), 0);
\r
518 StartTokenParsing(pBuff);
\r
520 while (GetToken(true))
\r
523 bool found = false;
\r
525 // each token should be a shader filename
\r
526 sprintf(dirstring, "%s.shader", token);
\r
528 for (tmp = l_shaderfiles; tmp != NULL; tmp = tmp->next)
\r
530 if (!strcmp (dirstring, (char*)tmp->data))
\r
533 Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data);
\r
540 l_shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring));
\r
555 void ClearGSList (GSList* lst)
\r
561 p = g_slist_remove (p, p->data);
\r
565 void FillTextureMenu (GSList** pArray)
\r
567 GtkWidget *menu, *sep, *item; // point to the Textures GtkMenu and to the last separator
\r
569 GSList *texdirs = NULL;
\r
570 GSList *texdirs_tmp = NULL;
\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
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
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
589 texture_nummenus = 0;
\r
592 if (!g_qeglobals.d_project_entity)
\r
595 // scan texture dirs and pak files only if not restricting to shaderlist
\r
596 if (!g_PrefsDlg.m_bTexturesShaderlistOnly)
\r
598 texdirs_tmp = vfsGetDirList ("textures/");
\r
599 for (p=texdirs_tmp; p; p=g_slist_next(p))
\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
606 vfsClearFileDirList (&texdirs_tmp);
\r
609 // scan the shaders in shaderlist.txt
\r
610 BuildShaderList ();
\r
612 DumpUnreferencedShaders ();
\r
613 while (l_shaderfiles != NULL)
\r
615 char shaderfile[PATH_MAX];
\r
616 gboolean found = FALSE;
\r
618 ExtractFileName ((char*)l_shaderfiles->data, shaderfile);
\r
619 StripExtension (shaderfile);
\r
620 g_strdown (shaderfile);
\r
622 for (GSList *tmp = texdirs; tmp; tmp = g_slist_next (tmp))
\r
623 if (!strcasecmp ((char*)tmp->data, shaderfile))
\r
630 texdirs = g_slist_prepend (texdirs, strdup (shaderfile));
\r
632 free (l_shaderfiles->data);
\r
633 l_shaderfiles = g_slist_remove (l_shaderfiles, l_shaderfiles->data);
\r
637 texdirs = g_slist_sort (texdirs, (GCompareFunc)strcmp);
\r
639 GSList *temp = texdirs;
\r
642 char* ptr = strchr ((char*)temp->data, '_');
\r
644 // do we shrink the menus?
\r
647 // extract the root
\r
648 strcpy (dirRoot, (char*)temp->data);
\r
649 dirRoot[ptr - (char*)temp->data + 1] = 0;
\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
654 GtkWidget *pSubMenu = gtk_menu_new ();
\r
655 GtkWidget *pSubMenuRef = pSubMenu;
\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
666 strcpy (texture_menunames[texture_nummenus], (char*)temp->data);
\r
667 strcat (texture_menunames[texture_nummenus], "/");
\r
669 *pArray = g_slist_append (*pArray, strdup ((char*)temp->data));
\r
670 if (++texture_nummenus == MAX_TEXTUREDIRS)
\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
683 while (temp && (strstr((char*)temp->data, dirRoot)==temp->data));
\r
685 ptr = strchr (dirRoot, '_');
\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
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
703 strcpy (texture_menunames[texture_nummenus], (char*)temp->data);
\r
704 strcat (texture_menunames[texture_nummenus], "/");
\r
706 *pArray = g_slist_append (*pArray, strdup ((char*)temp->data));
\r
707 if (++texture_nummenus == MAX_TEXTUREDIRS)
\r
709 Sys_Printf("WARNING: max texture directories count has been reached!\n");
\r
710 ClearGSList (texdirs);
\r
716 ClearGSList (texdirs);
\r
721 Texture_ShowDirectory
\r
722 relies on texture_directory global for the directory to use
\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
736 void Texture_ShowDirectory ()
\r
739 char dirstring[1024];
\r
741 int shaders_count = 0;
\r
742 int textures_count = 0;
\r
743 GSList *files = NULL, *temp;
\r
745 g_bScreenUpdates = false;
\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
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
765 // need this function "GSList *lst SynapseServer::GetMinorList(char *major_name);"
\r
767 sprintf (dirstring, "textures/%s", texture_directory);
\r
768 g_ImageManager.BeginExtensionsScan();
\r
770 while(ext=g_ImageManager.GetNextExtension())
\r
772 files = g_slist_concat(files, vfsGetFileList (dirstring, ext));
\r
775 for (temp = files; temp; temp = temp->next)
\r
777 sprintf(name, "%s%s", texture_directory, (char*)temp->data);
\r
779 StripExtension (name);
\r
781 strTemp.MakeLower();
\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
791 // avoid ever loading a texture name with spaces
\r
792 if (strTemp.Find(" ") >= 0)
\r
794 Sys_FPrintf(SYS_WRN, "WARNING: Skipping texture name with spaces [%s]\n", strTemp.GetBuffer());
\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
804 QERApp_CreateShader_ForTextureName (stdName);
\r
809 Sys_Printf("Loaded %d shaders and created default shader for %d orphan textures.\n",
\r
810 shaders_count, textures_count );
\r
812 vfsClearFileDirList (&files);
\r
814 // sort for displaying
\r
815 QERApp_SortActiveShaders();
\r
817 sprintf (name, "Textures: %s", texture_directory);
\r
818 gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name);
\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
824 g_bScreenUpdates = true;
\r
826 Sys_UpdateWindows (W_TEXTURE);
\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
838 void Texture_ShowDirectory (int menunum)
\r
840 strcpy (texture_directory, texture_menunames[menunum-CMD_TEXTUREWAD]);
\r
841 Texture_ShowDirectory();
\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
851 //this shouldn't ever happen, we startup with notex
\r
852 if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) {
\r
856 // otherwise position with current texture shown
\r
857 // this used to be in Texture_SetTexture
\r
858 Texture_StartPos ();
\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
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
874 // take care of calls before initialized
\r
875 if ( !g_qeglobals.d_texturewin.height) {
\r
876 g_qeglobals.d_texturewin.originy = 0;
\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
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
889 g_qeglobals.d_texturewin.originy = y;
\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
896 g_qeglobals.d_texturewin.originy = y-nHeight-2*FONT_HEIGHT+g_qeglobals.d_texturewin.height;
\r
899 // if we made it here, it should already be in view
\r
903 Sys_UpdateWindows (W_TEXTURE);
\r
909 will set the IsDisplayed flag on all the active shaders, so we see everything that's currently in memory
\r
912 void Texture_ShowAll()
\r
917 if (g_bShowAllShaders)
\r
918 Sys_Printf("WARNING: already showing all shaders\n");
\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
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
936 void WINAPI Texture_ShowInuse (void)
\r
942 g_qeglobals.d_texturewin.originy = 0;
\r
945 QERApp_ActiveShaders_SetDisplayed(false);
\r
946 // scan and only display in-use stuff
\r
947 Sys_Status("Selecting active textures", 0);
\r
949 for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next)
\r
953 b->pPatch->pShader->SetInUse(true);
\r
956 for (f=b->brush_faces ; f ; f=f->next)
\r
958 f->pShader->SetInUse(true);
\r
962 for (b=selected_brushes.next ; b != NULL && b != &selected_brushes ; b=b->next)
\r
966 b->pPatch->pShader->SetInUse(true);
\r
969 for (f=b->brush_faces ; f ; f=f->next)
\r
971 f->pShader->SetInUse(true);
\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
983 // select the first texture in the list
\r
984 if (!g_qeglobals.d_texturewin.texdef.GetName()[0])
\r
986 SelectTexture (16, g_qeglobals.d_texturewin.height -16, false);
\r
990 void Texture_ShowStartupShaders()
\r
992 if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_COMMON)
\r
995 // HACK FOR JK2 SUPPORT
\r
996 if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game")
\r
998 strcpy (texture_directory, "system/");
\r
1001 // HACK FOR SOF2 SUPPORT
\r
1002 else if (g_pGameDescription->mGameFile == "sof2.game")
\r
1004 strcpy (texture_directory, "tools/");
\r
1006 else strcpy (texture_directory, "common/");
\r
1007 Texture_ShowDirectory ();
\r
1010 if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_ALL) {
\r
1012 char filename[1024];
\r
1014 char dirstring[NAME_MAX];
\r
1016 GSList *shaderfiles = NULL;
\r
1018 strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer());
\r
1019 count = vfsGetFileCount(filename, 0);
\r
1022 Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer());
\r
1026 if (!vfsGetFullPath(filename, 0, 0))
\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
1033 Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0));
\r
1034 nLen = vfsLoadFile (filename, reinterpret_cast<void**>(&pBuff), 0);
\r
1037 StartTokenParsing(pBuff);
\r
1039 while (GetToken(true))
\r
1042 bool found = false;
\r
1044 // each token should be a shader filename
\r
1045 sprintf(dirstring, "%s.shader", token);
\r
1047 for (tmp = shaderfiles; tmp != NULL; tmp = tmp->next)
\r
1049 if (!strcmp (dirstring, (char*)tmp->data))
\r
1052 Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data);
\r
1059 shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring));
\r
1060 strcpy (texture_directory, dirstring);
\r
1061 Texture_ShowDirectory ();
\r
1071 ============================================================================
\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
1084 void Texture_StartPos (void)
\r
1086 //++timo TODO: check use of current_texture and current_row?
\r
1090 nActiveShadersCount = QERApp_GetActiveShaderCount();
\r
1091 nCurrentShader = -1;
\r
1092 current_texture = NULL;
\r
1093 pCurrentShader = NULL;
\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
1103 if (nCurrentShader >= nActiveShadersCount - 1)
\r
1105 // no more shaders
\r
1106 current_texture = NULL;
\r
1107 pCurrentShader = NULL;
\r
1111 pCurrentShader = QERApp_ActiveShader_ForIndex(nCurrentShader);
\r
1112 if (pCurrentShader == NULL)
\r
1114 Sys_Printf("ERROR: unexpected pCurrentShader == NULL in Texture_NextPos\n");
\r
1117 current_texture = pCurrentShader->getTexture();
\r
1118 q = current_texture;
\r
1122 Sys_Printf("WARNING: found an IShader without qtexture_t in Texture_NextPos\n");
\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
1130 if(strncmp(pCurrentShader->getName(), "textures/", 9) != 0)
\r
1133 // don't show shaders?
\r
1134 if (!(g_PrefsDlg.m_bShowShaders || pCurrentShader->IsDefault()))
\r
1137 if (g_PrefsDlg.m_bTextureWindow)
\r
1139 // some basic filtering
\r
1140 if (!g_pParentWnd->GetTexWnd()->CheckFilter( pCurrentShader->getName() ))
\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
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
1157 current_y -= current_row + FONT_HEIGHT + 4;
\r
1164 // Is our texture larger than the row? If so, grow the
\r
1165 // row height to match it
\r
1167 if (current_row < nHeight)
\r
1168 current_row = nHeight;
\r
1170 // never go less than 64, or the names get all crunched up
\r
1171 current_x += nWidth < 64 ? 64 : nWidth;
\r
1174 return pCurrentShader;
\r
1178 ============================================================================
\r
1182 ============================================================================
\r
1185 static int textures_cursorx, textures_cursory;
\r
1189 Texture_SetTexture
\r
1191 brushprimit_texdef must be understood as a qtexture_t with width=2 height=2 ( the default one )
\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
1199 if (texdef->GetName()[0] == '(')
\r
1201 Sys_Status("Can't select an entity texture", 0);
\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
1218 g_qeglobals.d_texturewin.brushprimit_texdef = *brushprimit_texdef;
\r
1221 g_dlgFind.updateTextures(texdef->GetName());
\r
1222 if (!g_dlgFind.isOpen() && bSetSelection)
\r
1224 Select_SetTexture(texdef,brushprimit_texdef,bFitScale);
\r
1227 //plugins: send a message telling that the selected texture may have changed
\r
1228 DispatchRadiantMsg( RADIANT_TEXTURE );
\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
1235 void ViewShader(const char *pFile, const char *pName)
\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
1242 Sys_FPrintf (SYS_ERR, "Couldn't get a full path to the shader file: %s\n", pFile);
\r
1246 char* pBuff = NULL;
\r
1247 int nSize = vfsLoadFullPathFile(fullName, reinterpret_cast<void**>(&pBuff));
\r
1250 Sys_FPrintf (SYS_ERR, "Failed to load shader file %s\n", fullName);
\r
1253 // look for the shader declaration
\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
1263 nStart = strLook.Find(strFind, nOffset);
\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
1274 delete[] strCheck;
\r
1275 nOffset = nStart + 1;
\r
1278 delete[] strCheck;
\r
1282 // now close the file
\r
1285 DoTextEditor (fullName, nOffset);
\r
1295 void SelectTexture (int mx, int my, bool bShift, bool bFitScale)
\r
1300 brushprimit_texdef_t brushprimit_tex;
\r
1302 my += g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height;
\r
1304 Texture_StartPos ();
\r
1307 // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture
\r
1308 Texture_NextPos (&x, &y);
\r
1309 q = current_texture;
\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
1319 if (pCurrentShader->IsDefault())
\r
1320 Sys_Printf("ERROR: %s is not a shader, it's a texture.\n", pCurrentShader->getName() );
\r
1322 ViewShader( pCurrentShader->getShaderFileName(), pCurrentShader->getName() );
\r
1326 memset (&tex, 0, sizeof(tex));
\r
1327 memset (&brushprimit_tex, 0, sizeof(brushprimit_tex));
\r
1328 if (g_qeglobals.m_bBrushPrimitMode)
\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
1336 tex.scale[0] = g_pGameDescription->mTextureDefaultScale;
\r
1337 tex.scale[1] = g_pGameDescription->mTextureDefaultScale;
\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
1350 // if shader, print shader name, otherwise texture name
\r
1351 //++timo FIXME: maybe CShader needs some properties between color / default / actual shader
\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
1357 // NOTE: IsColor is false, IsDefault the only remaining property
\r
1358 if (pAuxShader->IsDefault())
\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
1367 strName = pAuxShader->getName();
\r
1369 strTex.Format("%s W: %i H: %i", strName.GetBuffer(), q->width, q->height);
\r
1370 g_pParentWnd->SetStatusText(3, strTex);
\r
1376 Sys_Status("Did not select a texture", 0);
\r
1384 void Texture_MouseDown (int x, int y, int buttons)
\r
1386 Sys_GetCursorPos (&textures_cursorx, &textures_cursory);
\r
1388 // lbutton = select texture
\r
1389 if (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_SHIFT) || buttons == (MK_LBUTTON | MK_CONTROL))
\r
1391 SelectTexture (x, g_qeglobals.d_texturewin.height - 1 - y, buttons & MK_SHIFT, buttons & MK_CONTROL);
\r
1392 UpdateSurfaceDialog();
\r
1393 UpdatePatchInspector();
\r
1399 Texture_MouseMoved
\r
1403 void Texture_MouseMoved (int x, int y, int buttons)
\r
1407 if ( buttons & MK_SHIFT )
\r
1410 // rbutton = drag texture origin
\r
1411 if (buttons & MK_RBUTTON)
\r
1413 Sys_GetCursorPos (&x, &y);
\r
1414 if ( y != textures_cursory)
\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
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
1432 ============================================================================
\r
1436 ============================================================================
\r
1439 int imax(int iFloor, int i) { if (i>iFloor) return iFloor;return i;}
\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
1449 void Texture_Draw (int width, int height)
\r
1451 int x, y, last_y = 0, last_height = 0, nWidth, nHeight;
\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
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
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
1472 Texture_StartPos();
\r
1475 // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture
\r
1476 Texture_NextPos (&x, &y);
\r
1477 q = current_texture;
\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
1489 last_height = MAX (nHeight, last_height);
\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
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
1503 qglColor3f (1,0,0);
\r
1504 qglDisable (GL_TEXTURE_2D);
\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
1513 qglEnable (GL_TEXTURE_2D);
\r
1520 if (!pCurrentShader->IsDefault())
\r
1522 qglColor3f (1,1,1);
\r
1523 qglDisable (GL_TEXTURE_2D);
\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
1531 qglEnable (GL_TEXTURE_2D);
\r
1534 // highlight in-use textures
\r
1535 if (pCurrentShader->IsInUse())
\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
1545 qglEnable (GL_TEXTURE_2D);
\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
1564 // draw the texture name
\r
1565 qglDisable (GL_TEXTURE_2D);
\r
1566 qglColor3f (1,1,1);
\r
1568 qglRasterPos2f (x, y-FONT_HEIGHT+2);
\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
1576 gtk_glwidget_print_string(name);
\r
1577 qglEnable (GL_TEXTURE_2D);
\r
1581 g_qeglobals.d_texturewin.m_nTotalHeight = abs(y) + last_height + FONT_HEIGHT + 4;
\r
1583 // reset the current texture
\r
1584 qglBindTexture(GL_TEXTURE_2D, 0);
\r
1588 //++timo seems we only know hard inits now..
\r
1589 //void Texture_Init (bool bHardInit)
\r
1590 void Texture_Init()
\r
1592 g_qeglobals.d_qtextures = NULL;
\r
1593 // initialize the qtexture map
\r
1594 if (g_qeglobals.d_qtexmap)
\r
1596 Sys_FPrintf(SYS_ERR, "TODO: delete g_qeglobals.d_qtexmap in Texture_Init\n");
\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
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
1609 GSList *lst = l_shaderfiles;
\r
1613 shadername = g_pGameDescription->mShaderPath;
\r
1614 shadername += (char*)lst->data;
\r
1615 QERApp_LoadShaderFile(shadername.GetBuffer());
\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
1629 // byte *pic = NULL;
\r
1630 // byte *pic32 = NULL;
\r
1634 const char *pCleanName;
\r
1636 int nSize = g_lstSkinCache.GetSize();
\r
1637 pCleanName = QERApp_CleanTextureName( pName, false );
\r
1638 for (int i = 0; i < nSize; i++)
\r
1640 SkinInfo *pInfo = reinterpret_cast<SkinInfo*>(g_lstSkinCache.GetAt(i));
\r
1643 if (stricmp(pCleanName, pInfo->m_strName) == 0)
\r
1645 return pInfo->m_nTextureBind;
\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
1656 nTex = qtex->texture_number;
\r
1657 pInfo = new SkinInfo(qtex->name, nTex, qtex);
\r
1660 pInfo = new SkinInfo(pCleanName, -1, NULL);
\r
1662 g_lstSkinCache.Add(pInfo);
\r
1667 bool TexWnd::CheckFilter( const char* name )
\r
1669 const char* buf = gtk_entry_get_text (GTK_ENTRY (m_pFilter));
\r
1670 if (strstr( name, buf ) != 0)
\r
1675 // =============================================================================
\r
1676 // static functions
\r
1678 static void vertical_scroll (GtkWidget *widget, gpointer data)
\r
1680 ((TexWnd*)data)->OnVScroll ();
\r
1683 static void filter_changed (GtkWidget *widget, gpointer data)
\r
1686 str = gtk_entry_get_text (GTK_ENTRY (widget));
\r
1687 ((TexWnd*)data)->UpdateFilter (str);
\r
1690 // =============================================================================
\r
1694 : GLWindow (FALSE)
\r
1697 m_bNeedRange = true;
\r
1704 void TexWnd::OnCreate ()
\r
1706 if (!MakeCurrent ())
\r
1707 Error ("glMakeCurrent in TexWnd::OnCreate failed");
\r
1709 g_qeglobals_gui.d_texture = m_pWidget;
\r
1710 g_nTextureOffset = 0;
\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
1715 if (g_PrefsDlg.m_bTextureScrollbar)
\r
1716 gtk_widget_show (g_qeglobals_gui.d_texture_scroll);
\r
1718 gtk_widget_hide (g_qeglobals_gui.d_texture_scroll);
\r
1719 m_bNeedRange = true;
\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
1726 void TexWnd::UpdateFilter(const char* pFilter)
\r
1728 g_bFilterEnabled = false;
\r
1731 g_strFilter = pFilter;
\r
1732 if (g_strFilter.GetLength() > 0)
\r
1733 g_bFilterEnabled = true;
\r
1734 QERApp_SortActiveShaders();
\r
1736 Sys_UpdateWindows (W_TEXTURE);
\r
1739 void TexWnd::OnSize (int cx, int cy)
\r
1741 m_bNeedRange = true;
\r
1744 void TexWnd::OnExpose ()
\r
1746 int nOld = g_qeglobals.d_texturewin.m_nTotalHeight;
\r
1747 if (!MakeCurrent ())
\r
1749 Sys_Printf("ERROR: glXMakeCurrent failed..\n ");
\r
1750 Sys_Printf("Please restart Radiant if the Texture view is not working\n");
\r
1753 QE_CheckOpenGLForErrors();
\r
1754 Texture_Draw (m_pWidget->allocation.width, m_pWidget->allocation.height - g_nTextureOffset);
\r
1755 QE_CheckOpenGLForErrors();
\r
1758 if (g_PrefsDlg.m_bTextureScrollbar && (m_bNeedRange || g_qeglobals.d_texturewin.m_nTotalHeight != nOld))
\r
1760 GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll));
\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
1769 gtk_signal_emit_by_name (GTK_OBJECT (vadjustment), "changed");
\r
1771 m_bNeedRange = false;
\r
1775 void TexWnd::OnLButtonDown (guint32 flags, int pointx, int pointy)
\r
1778 Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags);
\r
1781 void TexWnd::OnRButtonDown (guint32 flags, int pointx, int pointy)
\r
1784 Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags);
\r
1787 void TexWnd::OnMButtonDown (guint32 flags, int pointx, int pointy)
\r
1790 Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags);
\r
1793 void TexWnd::OnLButtonUp (guint32 flags, int pointx, int pointy)
\r
1795 ReleaseCapture ();
\r
1796 // NOTE TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23
\r
1797 DragDropTexture (flags, pointx, pointy);
\r
1800 void TexWnd::OnRButtonUp (guint32 flags, int pointx, int pointy)
\r
1802 ReleaseCapture ();
\r
1805 void TexWnd::OnMButtonUp (guint32 flags, int pointx, int pointy)
\r
1807 ReleaseCapture ();
\r
1810 void TexWnd::OnMouseMove (guint32 flags, int pointx, int pointy)
\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
1818 void TexWnd::OnVScroll ()
\r
1820 GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll));
\r
1822 g_qeglobals.d_texturewin.originy = - (int)vadjustment->value;
\r
1826 void TexWnd::UpdatePrefs()
\r
1828 if (g_PrefsDlg.m_bTextureWindow)
\r
1829 gtk_widget_show (m_pFilter);
\r
1831 gtk_widget_hide (m_pFilter);
\r
1833 if (g_PrefsDlg.m_bTextureScrollbar)
\r
1834 gtk_widget_show (g_qeglobals_gui.d_texture_scroll);
\r
1836 gtk_widget_hide (g_qeglobals_gui.d_texture_scroll);
\r
1837 m_bNeedRange = true;
\r
1841 void TexWnd::FocusEdit()
\r
1843 if (GTK_WIDGET_VISIBLE (m_pFilter))
\r
1844 gtk_window_set_focus (GTK_WINDOW (g_pParentWnd->m_pWidget), m_pFilter);
\r
1847 void TexWnd::OnMouseWheel(bool bUp)
\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
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
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
1871 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23
\r
1872 void TexWnd::DragDropTexture (guint32 flags, int pointx, int pointy)
\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
1878 int m_ptXcheck, m_ptYcheck;
\r
1880 GtkWidget *widget;
\r
1886 // we only want to catch a plain mouseevent
\r
1890 // see if we are above the camwindow
\r
1891 Sys_GetCursorPos (&m_ptX, &m_ptY);
\r
1893 if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating)
\r
1894 widget = g_pParentWnd->GetCamWnd()->m_pParent;
\r
1896 widget = g_pParentWnd->GetCamWnd()->GetWidget();
\r
1898 get_window_pos (widget, &x, &y);
\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
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
1910 if( g_pParentWnd->GetCamWnd()->GetWidget()->window != gdk_window_at_pointer( &m_ptXcheck, &m_ptYcheck ) )
\r
1913 // calc ray direction
\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
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
1926 // do a trace for a surface
\r
1929 t = Test_Ray (g_pParentWnd->GetCamWnd()->Camera()->origin, dir, SF_SINGLEFACE);
\r
1934 brushprimit_texdef_t brushprimit_tex;
\r
1936 memset (&tex, 0, sizeof(tex));
\r
1937 memset (&brushprimit_tex, 0, sizeof(brushprimit_tex));
\r
1938 if (g_qeglobals.m_bBrushPrimitMode)
\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
1945 tex.scale[0] = g_pGameDescription->mTextureDefaultScale;
\r
1946 tex.scale[1] = g_pGameDescription->mTextureDefaultScale;
\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
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
1962 Sys_UpdateWindows (W_CAMERA);
\r
1963 g_pParentWnd->OnTimer ();
\r