/* =========================================================================== Copyright (C) 1997-2006 Id Software, Inc. This file is part of Quake 2 Tools source code. Quake 2 Tools source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Quake 2 Tools source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Quake 2 Tools source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "texpaint.h" #define SKIN_WINDOW_CLASS "TPSkin" HDC skindc; int skinw_width, skinw_height; // size of the window float skin_x = 128, skin_y = 128, skin_z = 100; qboolean skin_lines = false; char tri_filename[1024]; char skin_filename[1024]; int skin_width, skin_height; // size of the .lbm image unsigned index_texture[1024*512]; void UpdateTexture (int offset) { int x, y; y = offset / width2; x = offset % width2; BindTextureEXT (GL_TEXTURE_2D, TEXTURE_SKIN); // glTexImage2D (GL_TEXTURE_2D, 0, 3, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgb); glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgb+offset); } /* =================================================================== TEXEL MODIFICATION =================================================================== */ #define MAX_MODIFY 8192 typedef struct { int offset; int oldvalue; } modify_t; int modify_index; int undo_index; modify_t modify[MAX_MODIFY]; void SetSkinModified (void) { char text[1024]; if (modified && modified_past_autosave) return; modified = true; modified_past_autosave = true; sprintf (text, "%s *", skin_filename); SetWindowText (skinwindow, text); } void SetSkin (int index, int pixel) { modify_t *m; if (!modified) SetSkinModified (); // save undo info m = &modify[undo_index]; m->offset = index; m->oldvalue = pic[index]; modify_index = (++undo_index)&(MAX_MODIFY-1); // modify it rgb[index] = selected_rgb; pic[index] = selected_index; UpdateTexture (index); InvalidateRect (skinwindow, NULL, false); InvalidateRect (camerawindow, NULL, false); } void Undo (void) { modify_t *m; int temp; if (!undo_index) return; if (!--undo_index) { // back to unmodified state modified = false; SetWindowText (skinwindow, skin_filename); } m = &modify[undo_index]; // modify it temp = pic[m->offset]; pic[m->offset] = m->oldvalue; rgb[m->offset] = palette[m->oldvalue*3] + (palette[m->oldvalue*3+1]<<8) + (palette[m->oldvalue*3+2]<<16); m->oldvalue = temp; UpdateTexture (m->offset); InvalidateRect (skinwindow, NULL, false); InvalidateRect (camerawindow, NULL, false); } void Redo (void) { modify_t *m; int temp; if (undo_index == modify_index) return; m = &modify[undo_index]; // modify it temp = pic[m->offset]; pic[m->offset] = m->oldvalue; rgb[m->offset] = palette[m->oldvalue*3] + (palette[m->oldvalue*3+1]<<8) + (palette[m->oldvalue*3+2]<<16); m->oldvalue = temp; UpdateTexture (m->offset); InvalidateRect (skinwindow, NULL, false); InvalidateRect (camerawindow, NULL, false); if (!undo_index++) { // modified again char text[1024]; modified = true; sprintf (text, "%s *", skin_filename); SetWindowText (skinwindow, text); } } //=================================================================== /* ============= Skin_SaveFile Load a skin texture and the base.tri from the same directory ============= */ void Skin_SaveFile (char *name) { byte *data; int i, j; char backup[1024]; // back up the current file if it exists sprintf (backup, "%s.bak", name); remove (backup); rename (name, backup); modified = false; modified_past_autosave = false; modify_index = undo_index = 0; SetWindowText (skinwindow, skin_filename); data = malloc(skin_width*skin_height); for (i=0 ; i 1024 || skin_height > 512) Sys_Error ("Skin file is too large"); width2 = 1; height2 = 1; for (i=0 ; i<12 ; i++) { if (width2 < skin_width) width2<<=1; if (height2 < skin_height) height2<<=1; } // compatability shit for auto sizing of old skins if (skin_width != 320 || skin_height != 200) { skinwidth = skin_width; skinheight = skin_height; } else { skinwidth = 0; skinheight = 0; } } /* ============= Skin_LoadFile Load a skin texture and the base.tri from the same directory ============= */ void Skin_LoadFile (char *name) { int i, j, p; byte *lbmpic; byte *lbmpal; char trifile[1024]; int width, height; modified = false; modified_past_autosave = false; modify_index = undo_index = 0; strcpy (skin_filename, name); SetWindowText (skinwindow, skin_filename); // // read the texture // Load256Image (skin_filename, &lbmpic, &lbmpal, &width, &height); memcpy (palette, lbmpal, sizeof(palette)); free (lbmpal); SetSizes (width, height); memset (pic, 0, sizeof(pic)); for (i=0 ; i= width2*height2) return; if (index == skin_last_index) return; // in same pixel skin_last_index = index; if (shift) { Pal_SetIndex (pic[index]); return; } SetSkin (index, selected_index); UpdateWindow (skinwindow); } void DrawModelST (void) { int i, j; glColor4f (1,1,1,1); glBegin (GL_TRIANGLES); for (i=0 ; i abs(dy)) skin_z += 0.25*dx; else skin_z += 0.25*dy; InvalidateRect (skinwindow, NULL, false); } if (wParam == MK_RBUTTON) { skin_x -= 0.25*dx; skin_y -= 0.25*dy; InvalidateRect (skinwindow, NULL, false); } } break; case WM_SIZE: InvalidateRect(camerawindow, NULL, false); break; case WM_NCCALCSIZE:// don't let windows copy pixels lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); return WVR_REDRAW; case WM_CLOSE: DestroyWindow (hWnd); break; default: /* pass all unhandled messages to DefWindowProc */ lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); break; } /* return 1 if handled message, 0 if not */ return lRet; } /* ============== WSkin_Create ============== */ void WSkin_Create (HINSTANCE hInstance) { WNDCLASS wc; /* Register the camera class */ memset (&wc, 0, sizeof(wc)); wc.style = 0; wc.lpfnWndProc = (WNDPROC)Skin_WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = 0; wc.hCursor = LoadCursor (NULL,IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = 0; wc.lpszClassName = SKIN_WINDOW_CLASS; if (!RegisterClass (&wc) ) Sys_Error ("RegisterClass failed"); skinwindow = CreateWindow (SKIN_WINDOW_CLASS , "Skin View", QE3_STYLE, (int)(screen_width*0.5), (int)(screen_height*0.2), (int)(screen_width*0.5), (int)(screen_height*0.8), // size mainwindow, // parent window 0, // no menu hInstance, 0); if (!skinwindow) Error ("Couldn't create skinwindow"); // RestoreWindowState(palettewindow, "palettewindow"); ShowWindow (skinwindow, SW_SHOWDEFAULT); } /* =================================================================== SKIN RESAMPLING =================================================================== */ HWND resamplewindow; HDC resampledc; #define RESAMPLE_WINDOW_CLASS "TPResample" /* ============ Resample_WndProc ============ */ LONG WINAPI Resample_WndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: resampledc = GetDC(hWnd); bSetupPixelFormat(resampledc); break; } return DefWindowProc (hWnd, uMsg, wParam, lParam); } /* ============== ResampleWindow ============== */ void ResampleWindow (HINSTANCE hInstance) { WNDCLASS wc; static qboolean registered; if (!registered) { registered = true; /* Register the camera class */ memset (&wc, 0, sizeof(wc)); wc.style = 0; wc.lpfnWndProc = (WNDPROC)Resample_WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = 0; wc.hCursor = LoadCursor (NULL,IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = 0; wc.lpszClassName = RESAMPLE_WINDOW_CLASS; if (!RegisterClass (&wc) ) Sys_Error ("RegisterClass failed"); } resamplewindow = CreateWindow (RESAMPLE_WINDOW_CLASS , "ResampleWindow", WS_OVERLAPPED, 0, 0, width2+32, height2+32, // size NULL, // parent window 0, // no menu hInstance, 0); if (!resamplewindow) Error ("Couldn't create skinwindow"); ShowWindow (resamplewindow, SW_SHOWDEFAULT); } void OutlineTexture (byte *pic) { int i, j; int x, y; int empty; byte oldpic[1024*512]; memcpy (oldpic, pic, width2*height2); empty = oldpic[0]; for (i=0 ; i= height2) continue; if (j+x < 0 || j+x >= width2) continue; if (oldpic[(i+y)*width2 + j+x] != empty) { pic[i*width2+j] = oldpic[(i+y)*width2 + j+x]; goto done; } } } done: ; } } } void ResampleSkin (void) { int i, j; static float oldtmcoords[10000][3][2]; static int newindex[1024*512]; static byte oldpic[1024*512]; // open a window of the texture size ResampleWindow (main_instance); // get new S/T from current frame memcpy (oldtmcoords, tmcoords, numfaces*3*2*4); CalcTmCoords (); // draw all the triangles with the index texture if (!wglMakeCurrent( resampledc, baseRC )) Sys_Error ("wglMakeCurrent failed"); glViewport (0,0,width2, height2); glClearColor (0,0,0,0); glClear (GL_COLOR_BUFFER_BIT); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0, width2, 0, height2, -100, 100); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glColor4f (1,1,1,1); glDisable (GL_DEPTH_TEST); glDisable (GL_CULL_FACE); BindTextureEXT (GL_TEXTURE_2D, TEXTURE_INDEX); #if 0 glDisable(GL_TEXTURE_2D); glBegin (GL_LINE_LOOP); glVertex3f (1,1,10); glVertex3f (skin_width-1,0,10); glVertex3f (skin_width-1,skin_height-1,10); glVertex3f (1,skin_height-1,10); glEnd (); glEnable(GL_TEXTURE_2D); #endif glBegin (GL_TRIANGLES); for (i=0 ; i