/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ /* * $Logfile: /Freespace2/code/OsApi/OutWnd.cpp $ * $Revision: 2.14 $ * $Date: 2005-04-20 04:34:42 $ * $Author: phreak $ * * Routines for debugging output * * $Log: not supported by cvs2svn $ * Revision 2.13 2005/03/03 06:05:30 wmcoolmon * Merge of WMC's codebase. "Features and bugs, making Goober say "Grr!", as release would be stalled now for two months for sure" * * Revision 2.12 2004/07/26 20:47:46 Kazan * remove MCD complete * * Revision 2.11 2004/07/12 16:33:01 Kazan * MCD - define _MCD_CHECK to use memory tracking * * Revision 2.10 2004/03/31 05:42:28 Goober5000 * got rid of all those nasty warnings from xlocale and so forth; also added comments * for #pragma warning disable to indicate the message being disabled * --Goober5000 * * Revision 2.9 2004/03/06 23:28:23 bobboau * fixed motion debris * animated laser textures * and added a new error check called a safepoint, mostly for tracking the 'Y bug' * * Revision 2.8 2004/03/05 09:02:08 Goober5000 * Uber pass at reducing #includes * --Goober5000 * * Revision 2.7 2004/02/14 00:18:35 randomtiger * Please note that from now on OGL will only run with a registry set by Launcher v4. See forum for details. * OK, these changes effect a lot of file, I suggest everyone updates ASAP: * Removal of many files from project. * Removal of meanless Gr_bitmap_poly variable. * Removal of glide, directdraw, software modules all links to them, and all code specific to those paths. * Removal of redundant Fred paths that arent needed for Fred OGL. * Have seriously tidied the graphics initialisation code and added generic non standard mode functionality. * Fixed many D3D non standard mode bugs and brought OGL up to the same level. * Removed texture section support for D3D8, voodoo 2 and 3 cards will no longer run under fs2_open in D3D, same goes for any card with a maximum texture size less than 1024. * * Revision 2.6 2004/02/04 09:02:44 Goober5000 * got rid of unnecessary double semicolons * --Goober5000 * * Revision 2.5 2003/03/18 10:07:05 unknownplayer * The big DX/main line merge. This has been uploaded to the main CVS since I can't manage to get it to upload to the DX branch. Apologies to all who may be affected adversely, but I'll work to debug it as fast as I can. * * Revision 2.4 2003/03/02 06:04:00 penguin * Added versions of _outp() and _inp() for gcc. * Revision 2.1.2.3 2002/11/09 19:28:15 randomtiger * * Fixed small gfx initialisation bug that wasnt actually causing any problems. * Tided DX code, shifted stuff around, removed some stuff and documented some stuff. * * Revision 2.1.2.2 2002/11/04 21:25:00 randomtiger * * When running in D3D all ani's are memory mapped for speed, this takes up more memory but stops gametime locking of textures which D3D8 hates. * Added new command line tag Cmdline_d3dlowmem for people who dont want to make use of this because they have no memory. * Cleaned up some more texture stuff enabled console debug for D3D. * * Revision 2.1.2.1 2002/10/08 14:33:27 randomtiger * OK, I've fixed the z-buffer problem. * However I have abandoned using w-buffer for now because of problems. * I think I know how to solve it but Im not sure it would make much difference given the way FS2 engine works. * I have left code in there of use if anyone wants to turn their hand to it. However for now * we just need to crack of the alpha problem then we will have FS2 fully wokring in DX8 on GF4 in 32 bit. * * Revision 2.1 2002/08/01 01:41:09 penguin * The big include file move * * Revision 2.3 2002/11/14 04:18:17 bobboau * added warp model and type 1 glow points * and well as made the new glow file type, * some general improvement to fighter beams, * * * 6 6/03/99 6:37p Dave * More TNT fun. Made perspective bitmaps more flexible. * * 5 6/02/99 6:18p Dave * Fixed TNT lockup problems! Wheeeee! * * 4 12/14/98 12:13p Dave * Spiffed up xfer system a bit. Put in support for squad logo file xfer. * Need to test now. * * 3 10/08/98 2:38p Dave * Cleanup up OsAPI code significantly. Removed old functions, centralized * registry functions. * * 2 10/07/98 10:53a Dave * Initial checkin. * * 1 10/07/98 10:50a Dave * * 49 5/15/98 3:36p John * Fixed bug with new graphics window code and standalone server. Made * hwndApp not be a global anymore. * * 48 5/14/98 5:42p John * Revamped the whole window position/mouse code for the graphics windows. * * 47 5/14/98 11:24a Allender * throw mprints to outtext regardless of gr mode * * 46 4/30/98 4:53p John * Restructured and cleaned up cfile code. Added capability to read off * of CD-ROM drive and out of multiple pack files. * * 45 4/16/98 6:31p Dave * Doubled MAX_FILTERS to 48 * * 44 3/31/98 5:18p John * Removed demo/save/restore. Made NDEBUG defined compile. Removed a * bunch of debug stuff out of player file. Made model code be able to * unload models and malloc out only however many models are needed. * * * 43 3/11/98 12:06p John * Made it so output window never gets focus upon startup * * 42 2/16/98 9:47a John * Made so only error, general, and warning are shown if no * debug_filter.cfg and .cfg file isn't saved if so. * * 41 2/05/98 9:21p John * Some new Direct3D code. Added code to monitor a ton of stuff in the * game. * * 40 1/15/98 9:14p John * Made it so general, error and warning can't be turned off. * * 39 9/13/97 10:44a Lawrance * allow logging of nprintf output to file * * 38 8/23/97 11:32a Dave * Made debug window size correctly in standalone mode. * * 37 8/22/97 3:42p Hoffoss * Lowered the filter limit to 24, and added support for filter recycling, * instead of the rather nasty Assert if we should happen to exceed this * limit. * * 36 8/05/97 4:29p Dave * Futzed with window sizes/placements for standalone mode. * * 35 8/04/97 3:15p Dave * Added an include for systemvars.h * * 34 5/20/97 1:13p Allender * fixes to make outwnd work better under Win95 * * 33 5/14/97 11:08a John * fixed bug under 95 that occasionally hung program. * * 32 5/07/97 3:01p Lawrance * check for NT in mono_init * * 31 5/07/97 3:06p John * disabled new mono direct stuff under NT. * * 30 5/07/97 2:59p John * Made so mono driver works under '95. * * 29 4/22/97 10:56a John * fixed some resource leaks. * * $NoKeywords: $ */ #ifndef NDEBUG #include #include #include #include // to disable otherwise well-lodged compiler warning #pragma warning(disable: 4201) // nameless struct/union #include #include #include "osapi/OsApi.h" #include "osapi/outwnd.h" #include "osapi/monopub.h" #include "graphics/2d.h" #include "freespace2/freespaceresource.h" #include "globalincs/systemvars.h" #define MAX_FILTERS 48 #define SCROLL_BUFFER_SIZE 512 #define MAX_LINE_WIDTH 128 #define TASKBAR_HEIGHT 30 #define ID_COPY 32000 #define ID_FIND 32010 #define ID_FILTER 32100 #define TIMER1 1 #define UP_FAST 65537 #define DOWN_FAST 65538 HANDLE hOutputThread=NULL; DWORD OutputThreadID; HWND hOutputWnd; char szOutputClass[] = "OutputWindow"; char spaces[MAX_LINE_WIDTH + 1]; int outwnd_filter_count = 0; int outwnd_filter_loaded = 0; char find_text[85]; struct outwnd_filter_struct { char name[FILTER_NAME_LENGTH]; int state; } *outwnd_filter[MAX_FILTERS], real_outwnd_filter[MAX_FILTERS]; int mprintf_last_line = -1; char outtext[SCROLL_BUFFER_SIZE][MAX_LINE_WIDTH]; int old_scroll_pos = -32768; int nTextHeight=0, nTextWidth=0, nCharRows=0; int outwnd_inited = FALSE; int outwnd_disabled = TRUE; int max_scroll_pos = SCROLL_BUFFER_SIZE - 1; static int marked = 0; int marked_top, marked_bottom, marked_left, marked_right; int old_marked = 0, old_marked_top, old_marked_bottom, old_marked_left, old_marked_right; int marking_started_x, marking_started_y, client_top_yoffset, cur_line_index, marking_active = 0; int scroll_wait = 1; BOOL OutputActive = FALSE; LPARAM last_mousemove; int Outwnd_changed = 0; int find_line = -1, find_pos; // monochrome screen info HANDLE mono_driver=NULL; // handle to the monochrome driver void outwnd_print(char *id, char *tmp); BOOL CALLBACK find_dlg_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam); void find_text_in_outwindow(int n, int p); void outwnd_copy_marked_selection(HWND hwnd); void outwnd_update_marking(LPARAM l_parm, HWND hwnd); void outwnd_paint(HWND hwnd); int Outwnd_no_filter_file = 0; // 0 = .cfg file found, 1 = not found and warning not printed yet, 2 = not found and warning printed // used for file logging #ifndef NDEBUG int Log_debug_output_to_file = 1; FILE *Log_fp; char *Freespace_logfilename = "fs.log"; #endif #ifndef _MSC_VER inline void _outp(unsigned short port, unsigned char value) { asm( "mov %0,%%al;" "mov %1,%%dx;" "out %%al,%%dx;" : : "g" (value), "g" (port) : "al", "dx"); } inline unsigned char _inp(unsigned short port) { unsigned char value; asm( "mov %1,%%dx;" "in %%dx,%%al;" "mov %%al,%0" : "=g"(value) : "g" (port) : "al", "dx"); return value; } #endif inline void text_hilight(HDC &hdc) { SetBkColor(hdc, RGB(0, 0, 0)); SetTextColor(hdc, RGB(255, 255, 255)); } inline void text_normal(HDC &hdc) { SetBkColor(hdc, RGB(255, 255, 255)); SetTextColor(hdc, RGB(0, 0, 0)); } inline void fix_marking_coords(int &x, int &y, LPARAM l_parm) { x = (signed short) LOWORD(l_parm) / nTextWidth; y = ((signed short) HIWORD(l_parm) - client_top_yoffset) / nTextHeight + cur_line_index; if (y < 0) y = x = 0; if (y > SCROLL_BUFFER_SIZE) { y = SCROLL_BUFFER_SIZE; x = 0; } if (x < 0) x = -1; if (x > MAX_LINE_WIDTH) { y++; x = 0; // marks to end of line } } // InvalidateRect(hOutputWnd,NULL,0); void load_filter_info(void) { FILE *fp; char pathname[256], inbuf[FILTER_NAME_LENGTH+4]; int z; outwnd_filter_loaded = 1; outwnd_filter_count = 0; strcpy(pathname, "Debug_filter.cfg" ); fp = fopen(pathname, "rt"); if (!fp) { Outwnd_no_filter_file = 1; outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count]; strcpy( outwnd_filter[outwnd_filter_count]->name, "error" ); outwnd_filter[outwnd_filter_count]->state = 1; outwnd_filter_count++; outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count]; strcpy( outwnd_filter[outwnd_filter_count]->name, "general" ); outwnd_filter[outwnd_filter_count]->state = 1; outwnd_filter_count++; outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count]; strcpy( outwnd_filter[outwnd_filter_count]->name, "warning" ); outwnd_filter[outwnd_filter_count]->state = 1; outwnd_filter_count++; return; } Outwnd_no_filter_file = 0; while (fgets(inbuf, FILTER_NAME_LENGTH+3, fp)) { if (outwnd_filter_count == MAX_FILTERS) break; outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count]; if (*inbuf == '+') outwnd_filter[outwnd_filter_count]->state = 1; else if (*inbuf == '-') outwnd_filter[outwnd_filter_count]->state = 0; else continue; // skip everything else z = strlen(inbuf) - 1; if (inbuf[z] == '\n') inbuf[z] = 0; Assert(strlen(inbuf+1) < FILTER_NAME_LENGTH); strcpy(outwnd_filter[outwnd_filter_count]->name, inbuf + 1); if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "error" ) ) { outwnd_filter[outwnd_filter_count]->state = 1; } else if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "general" ) ) { outwnd_filter[outwnd_filter_count]->state = 1; } else if ( !stricmp( outwnd_filter[outwnd_filter_count]->name, "warning" ) ) { outwnd_filter[outwnd_filter_count]->state = 1; } outwnd_filter_count++; } if (ferror(fp) && !feof(fp)) nprintf(("Error", "Error reading \"%s\"\n", pathname)); fclose(fp); } void save_filter_info(void) { FILE *fp; int i; char pathname[256]; if (!outwnd_filter_loaded) return; if ( Outwnd_no_filter_file ) { return; // No file, don't save } strcpy(pathname, "Debug_filter.cfg" ); fp = fopen(pathname, "wt"); if (fp) { for (i=0; istate ? '+' : '-', outwnd_filter[i]->name); fclose(fp); } } #include "debugconsole/dbugfile.h" void outwnd_printf2(char *format, ...) { char tmp[MAX_LINE_WIDTH*4]; va_list args; va_start(args, format); vsprintf(tmp, format, args); va_end(args); outwnd_print("General", tmp); // DBUGFILE_OUTPUT_0(tmp); } char mono_ram[80*25*2]; int mono_x, mono_y; int mono_found = 0; void mono_flush() { if ( !mono_found ) return; memcpy( (void *)0xb0000, mono_ram, 80*25*2 ); } void mono_init() { int i; OSVERSIONINFO ver; ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&ver); if ( ver.dwPlatformId == VER_PLATFORM_WIN32_NT ) { mono_found = 0; return; } _outp( 0x3b4, 0x0f ); _outp( 0x3b4+1, 0x55 ); if ( _inp( 0x3b4+1 ) == 0x55 ) { mono_found = 1; _outp( 0x3b4+1, 0 ); } else { mono_found = 0; return; } for (i=0; i<80*25; i++ ) { mono_ram[i*2+0] = ' '; mono_ram[i*2+1] = 0x07; } mono_flush(); mono_x = mono_y = 0; } void mono_print( char * text, int len ) { int i, j; if ( !mono_found ) return; for (i=0; iname)) break; if (i == outwnd_filter_count) // new id found that's not yet in filter list { // Only create new filters if there was a filter file if ( Outwnd_no_filter_file ) { return; } if (outwnd_filter_count >= MAX_FILTERS) { Assert(outwnd_filter_count == MAX_FILTERS); // how did it get over the max? Very bad.. outwnd_printf("General", "Outwnd filter limit reached. Recycling \"%s\" to add \"%s\"", outwnd_filter[MAX_FILTERS - 1]->name, id); i--; // overwrite the last element (oldest used filter in the list) } Assert(strlen(id) < FILTER_NAME_LENGTH); outwnd_filter[i] = &real_outwnd_filter[i]; // note: this assumes the list doesn't have gaps (from deleting an element for example) strcpy(outwnd_filter[i]->name, id); outwnd_filter[i]->state = 1; outwnd_filter_count = i + 1; save_filter_info(); } // sort the filters from most recently used to oldest, so oldest ones will get recycled first temp = outwnd_filter[i]; while (i--) outwnd_filter[i + 1] = outwnd_filter[i]; i++; outwnd_filter[i] = temp; if (!outwnd_filter[i]->state) return; if (mprintf_last_line == -1 ) { for (i=0; i= MAX_LINE_WIDTH-1 ) ) { nrows++; mprintf_last_line++; if (mprintf_last_line >= SCROLL_BUFFER_SIZE ) mprintf_last_line = 0; ccol = 0; if ( *sptr != '\n' ) { outtext[mprintf_last_line][ccol] = *sptr; ccol++; } outtext[mprintf_last_line][ccol] = '\0'; dptr = &outtext[mprintf_last_line][ccol]; } else { *dptr++ = *sptr; *dptr = '\0'; ccol++; } sptr++; } if ( outwnd_disabled ){ return; } if ( !OutputActive ) { int oldpos = GetScrollPos( hOutputWnd, SB_VERT ); if ( oldpos != max_scroll_pos ) { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; si.nPos = max_scroll_pos; SetScrollInfo(hOutputWnd, SB_VERT, &si, 1 ); InvalidateRect(hOutputWnd,NULL,0); UpdateWindow(hOutputWnd); } else { if ( nrows ) { RECT client; ScrollWindow(hOutputWnd,0,-nTextHeight*nrows,NULL,NULL); GetClientRect(hOutputWnd, &client); client.top = client.bottom - nTextHeight*(nrows+1); InvalidateRect(hOutputWnd,&client,0); UpdateWindow(hOutputWnd); } else { Outwnd_changed++; } } } } LRESULT CALLBACK outwnd_handler(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_ACTIVATEAPP: // The application z-ordering has change // foreground application wParm will be OutputActive = (BOOL)wParam; break; case WM_CREATE: { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE | SIF_POS; si.nMin = 0; si.nMax = max_scroll_pos; si.nPos = max_scroll_pos; SetScrollInfo(hwnd, SB_VERT, &si, 1 ); } break; case WM_TIMER: if (scroll_wait) PostMessage(hwnd, WM_MOUSEMOVE, 0, last_mousemove); if ( Outwnd_changed ) { RECT client; GetClientRect(hOutputWnd, &client); client.top = client.bottom - nTextHeight; InvalidateRect(hOutputWnd,&client,0); } scroll_wait = 0; break; case WM_COMMAND: { int z; z = LOWORD(wParam); if (z >= ID_FILTER && z < ID_FILTER + outwnd_filter_count) { z -= ID_FILTER; outwnd_filter[z]->state = !outwnd_filter[z]->state; if ( !stricmp( outwnd_filter[z]->name, "error" ) ) { outwnd_filter[z]->state = 1; } else if ( !stricmp( outwnd_filter[z]->name, "general" ) ) { outwnd_filter[z]->state = 1; } else if ( !stricmp( outwnd_filter[z]->name, "warning" ) ) { outwnd_filter[z]->state = 1; } save_filter_info(); break; } switch (z) { case ID_COPY: outwnd_copy_marked_selection(hwnd); break; /* case ID_FIND: if (DialogBox(GetModuleHandle(NULL), "FIND_DIALOG", hOutputWnd, (int (__stdcall *)(void)) find_dlg_handler) == IDOK) { find_text_in_outwindow(mprintf_last_line, 0); } break; */ } break; } case WM_RBUTTONDOWN: { HMENU h_menu = CreatePopupMenu(); HMENU h_sub_menu = CreatePopupMenu(); POINT pt; int i; for (i=0; iname, "error" ) ) { flags |= MF_GRAYED; } else if ( !stricmp( outwnd_filter[i]->name, "general" ) ) { flags |= MF_GRAYED; } else if ( !stricmp( outwnd_filter[i]->name, "warning" ) ) { flags |= MF_GRAYED; } if (outwnd_filter[i]->state) AppendMenu(h_sub_menu, flags | MF_CHECKED, ID_FILTER + i, outwnd_filter[i]->name); else AppendMenu(h_sub_menu, flags, ID_FILTER + i, outwnd_filter[i]->name); } AppendMenu(h_menu, MFT_STRING, ID_COPY, "&Copy\tEnter"); AppendMenu(h_menu, MFT_STRING, ID_FIND, "&Find Text"); AppendMenu(h_menu, MF_POPUP, (unsigned int) h_sub_menu, "Filter &Messages"); pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); ClientToScreen(hwnd, &pt); TrackPopupMenu(h_menu, 0, pt.x, pt.y, 0, hwnd, NULL); DestroyMenu(h_menu); break; } case WM_LBUTTONDOWN: fix_marking_coords(marking_started_x, marking_started_y, lParam); SetCapture(hwnd); // monopolize mouse marking_active = 1; outwnd_update_marking(lParam, hwnd); break; case WM_MOUSEMOVE: last_mousemove = lParam; if (marking_active){ outwnd_update_marking(lParam, hwnd); } break; case WM_LBUTTONUP: if (marking_active) { ReleaseCapture(); marking_active = 0; outwnd_update_marking(lParam, hwnd); } break; case WM_VSCROLL: { SCROLLINFO si; int vpos = GetScrollPos( hwnd, SB_VERT ); int old_vpos=vpos; switch (LOWORD(wParam)) { case SB_LINEDOWN: vpos++; break; case SB_LINEUP: vpos--; break; case SB_THUMBPOSITION: vpos = HIWORD(wParam); break; case SB_THUMBTRACK: vpos = HIWORD(wParam); break; case SB_PAGEDOWN: vpos += nCharRows; break; case SB_PAGEUP: vpos -= nCharRows; break; } if ( vpos < 0 ) vpos = 0; else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; si.nPos = vpos; SetScrollInfo(hwnd, SB_VERT, &si, 1 ); ScrollWindow(hwnd,0,(old_vpos-vpos)*nTextHeight,NULL,NULL); UpdateWindow(hOutputWnd); //InvalidateRect(hOutputWnd,NULL,0); } break; case WM_KEYDOWN: { SCROLLINFO si; int vpos = GetScrollPos( hwnd, SB_VERT ); int old_vpos=vpos; int nVirtKey = (int) wParam; // virtual-key code switch(nVirtKey) { case VK_DOWN: case VK_RIGHT: vpos++; break; case VK_UP: case VK_LEFT: vpos--; break; case VK_NEXT: vpos += nCharRows; break; case VK_PRIOR: vpos -= nCharRows; break; case VK_END: vpos = 0; break; case VK_HOME: vpos = max_scroll_pos; break; case VK_RETURN: outwnd_copy_marked_selection(hwnd); break; case UP_FAST: // special value we define vpos -= 5; break; case DOWN_FAST: // special value we define vpos += 5; break; } if ( vpos < 0 ) vpos = 0; else if ( vpos > max_scroll_pos ) vpos = max_scroll_pos; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; si.nPos = vpos; SetScrollInfo(hwnd, SB_VERT, &si, 1 ); ScrollWindow(hwnd, 0, (old_vpos-vpos)*nTextHeight, NULL, NULL); UpdateWindow(hOutputWnd); //InvalidateRect(hOutputWnd,NULL,0); } break; case WM_SIZE: InvalidateRect(hOutputWnd,NULL,0); break; case WM_PAINT: outwnd_paint(hwnd); break; case WM_DESTROY: outwnd_disabled = 1; PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); break; } return 0; } void outwnd_copy_marked_selection(HWND hwnd) { HGLOBAL h_text; int i, size = 1; char *ptr; if (marked_top == marked_bottom) { size += marked_right - marked_left; } else { i = marked_top; size += strlen(outtext[i++]) - marked_left + 2; while (i < marked_bottom) size += strlen(outtext[i++]) + 2; size += marked_right; } h_text = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size); ptr = (char *) GlobalLock(h_text); if (marked_top == marked_bottom) { i = marked_right - marked_left; memcpy(ptr, outtext[marked_top] + marked_left, i); ptr[i] = 0; } else { i = marked_top; strcpy(ptr, outtext[i] + marked_left); strcat(ptr, "\r\n"); i++; while (i < marked_bottom) { strcat(ptr, outtext[i++]); strcat(ptr, "\r\n"); } ptr[strlen(ptr) + marked_right] = 0; strncat(ptr, outtext[i], marked_right); } GlobalUnlock(h_text); OpenClipboard(hwnd); EmptyClipboard(); SetClipboardData(CF_TEXT, h_text); CloseClipboard(); marked = 0; InvalidateRect(hwnd, NULL, 0); } void outwnd_paint(HWND hwnd) { int i, n, x, y, len; int old_nrows, scroll_pos; HDC hdc; PAINTSTRUCT ps; RECT client; TEXTMETRIC tm; HFONT newfont, oldfont; HBRUSH newbrush, oldbrush; Outwnd_changed = 0; hdc = BeginPaint(hwnd, &ps); GetClientRect(hOutputWnd, &client); newfont = (HFONT)GetStockObject(ANSI_FIXED_FONT); oldfont = (HFONT)SelectObject(hdc,newfont); GetTextMetrics(hdc, &tm); nTextHeight = tm.tmHeight + tm.tmExternalLeading; nTextWidth = tm.tmAveCharWidth; old_nrows = nCharRows; nCharRows = ((client.bottom-client.top)/nTextHeight)+1; newbrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); oldbrush = (HBRUSH)SelectObject(hdc,newbrush); y = client.bottom - nTextHeight * nCharRows; // starting y position at top client_top_yoffset = y - nTextHeight; scroll_pos = (max_scroll_pos - GetScrollPos( hOutputWnd, SB_VERT )); cur_line_index = x = mprintf_last_line - scroll_pos - nCharRows; if (x >= marked_top && x < marked_bottom) // starting in marked area text_hilight(hdc); else text_normal(hdc); if (scroll_pos != old_scroll_pos) { if (!scroll_pos) { char tmp[1024]; sprintf( tmp, "Debug Spew"); SetWindowText( hOutputWnd, tmp ); } else { char tmp[1024]; sprintf( tmp, "Debug Spew [Scrolled back %d lines]", scroll_pos ); SetWindowText( hOutputWnd, tmp ); } old_scroll_pos = scroll_pos; } i = nCharRows; while (i--) { n = mprintf_last_line - scroll_pos - i; if (n < 0) n += SCROLL_BUFFER_SIZE; if (n >= 0 && n < SCROLL_BUFFER_SIZE) { len = strlen(outtext[n]); if (marked) { if (n == marked_top && n == marked_bottom) // special 1 line case { if (marked_left) TextOut(hdc, 0, y, outtext[n], marked_left); text_hilight(hdc); x = marked_left * nTextWidth; TextOut(hdc, x, y, outtext[n] + marked_left, marked_right - marked_left); text_normal(hdc); x = marked_right * nTextWidth; if (marked_right < len) TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right); x = len * nTextWidth; TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len); } else if (n == marked_top) { // start marked on this line if (marked_left) TextOut(hdc, 0, y, outtext[n], marked_left); text_hilight(hdc); x = marked_left * nTextWidth; TextOut(hdc, x, y, outtext[n] + marked_left, len - marked_left); x = len * nTextWidth; if (marked_left < MAX_LINE_WIDTH) TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - marked_left); } else if (n == marked_bottom) { // end marked on this line if (marked_right) TextOut(hdc, 0, y, outtext[n], marked_right); text_normal(hdc); x = marked_right * nTextWidth; if (marked_right < len) TextOut(hdc, x, y, outtext[n] + marked_right, len - marked_right); x = len * nTextWidth; TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len); } else { // whole line marked TextOut(hdc, 0, y, outtext[n], len); x = len * nTextWidth; TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len); } } else { TextOut(hdc, 0, y, outtext[n], len); x = len * nTextWidth; TextOut(hdc, x, y, spaces, MAX_LINE_WIDTH - len); } } else TextOut(hdc, 0, y, spaces, MAX_LINE_WIDTH); y += nTextHeight; } text_normal(hdc); SelectObject(hdc, oldfont); SelectObject(hdc, oldbrush); DeleteObject(newbrush); if ( old_nrows != nCharRows ) { SCROLLINFO si; max_scroll_pos = SCROLL_BUFFER_SIZE-nCharRows - 1; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE; si.nMin = 0; si.nMax = max_scroll_pos; SetScrollInfo(hwnd, SB_VERT, &si, 1 ); } EndPaint(hwnd, &ps); } void outwnd_update_marking(LPARAM l_parm, HWND hwnd) { int x, y; RECT rect; if (!scroll_wait) { y = (signed short) HIWORD(l_parm); GetClientRect(hwnd, &rect); if (y < -150) { SendMessage(hwnd, WM_KEYDOWN, UP_FAST, 0); scroll_wait = 1; } else if (y < 0) { SendMessage(hwnd, WM_KEYDOWN, VK_UP, 0); scroll_wait = 1; } if (y >= rect.bottom + 150) { SendMessage(hwnd, WM_KEYDOWN, DOWN_FAST, 0); scroll_wait = 1; } else if (y >= rect.bottom) { SendMessage(hwnd, WM_KEYDOWN, VK_DOWN, 0); scroll_wait = 1; } } fix_marking_coords(x, y, l_parm); marked = 1; marked_top = marked_bottom = marking_started_y; marked_left = marking_started_x; marked_right = marking_started_x + 1; if (y < marked_top) { marked_top = y; marked_left = x; } else if (y > marked_bottom) { marked_bottom = y; marked_right = x + 1; } else { // must be single line case if (x < marked_left) marked_left = x; if (x >= marked_right) marked_right = x + 1; if (marked_left >= (signed int) strlen(outtext[y])) { marked = 0; // this isn't going to even show up return; } } if (marked_left >= (signed int) strlen(outtext[marked_top])) { marked_top++; marked_left = 0; } if (marked_right > (signed int) strlen(outtext[marked_bottom])) marked_right = strlen(outtext[marked_bottom]); if (marked && (marked_top > marked_bottom || (marked_top == marked_bottom && marked_left >= marked_right))) { char msg[1024]; sprintf(msg, "Marking limits invalid!\n" "(%d,%d) to (%d,%d)", marked_left, marked_top, marked_right, marked_bottom); MessageBox(hwnd, msg, "Error", MB_OK | MB_ICONERROR); marked = 0; } if (marked != old_marked || marked_top != old_marked_top || marked_bottom != old_marked_bottom || marked_left != old_marked_left || marked_right != old_marked_right) { old_marked = marked; old_marked_left = marked_left; old_marked_right = marked_right; old_marked_top = marked_top; old_marked_bottom = marked_bottom; InvalidateRect(hwnd, NULL, 0); } } BOOL outwnd_create(int display_under_freespace_window) { int x; WNDCLASSEX wclass; HINSTANCE hInst = GetModuleHandle(NULL); RECT rect; DWORD style; wclass.hInstance = hInst; wclass.lpszClassName = szOutputClass; wclass.lpfnWndProc = (WNDPROC) outwnd_handler; wclass.style = CS_BYTEALIGNCLIENT | CS_OWNDC; //CS_DBLCLKS | CS_PARENTDC| CS_VREDRAW | CS_HREDRAW |; wclass.cbSize = sizeof(WNDCLASSEX); wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wclass.hCursor = LoadCursor(NULL, IDC_ARROW); wclass.lpszMenuName = NULL; //"FreeSpaceMenu"; wclass.cbClsExtra = 0; wclass.cbWndExtra = 0; wclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //(HBRUSH)NULL; if (!RegisterClassEx(&wclass)) return FALSE; if (display_under_freespace_window) { style = WS_OVERLAPPEDWINDOW; RECT client_rect; client_rect.left = client_rect.top = 0; client_rect.right = 640; client_rect.bottom = 480; AdjustWindowRect(&client_rect,WS_CAPTION | WS_SYSMENU,FALSE); int x = (GetSystemMetrics( SM_CXSCREEN )-(client_rect.right - client_rect.left))/2; int y = 0; if ( x < 0 ) x = 0; rect.left = x; rect.top = y; rect.right = x + client_rect.right - client_rect.left - 1; rect.bottom = y + client_rect.bottom - client_rect.top - 1; if(!Is_standalone){ rect.top = rect.bottom; rect.bottom = GetSystemMetrics(SM_CYSCREEN) - TASKBAR_HEIGHT - rect.top; rect.right -= rect.left; } else { rect.left += 350; rect.right = 550; rect.bottom = 400; } } else { style = WS_OVERLAPPEDWINDOW | WS_MINIMIZE; rect.top = rect.bottom = rect.left = rect.right = CW_USEDEFAULT; } // Create Game Window hOutputWnd = CreateWindow(szOutputClass, "Debug Spew", style, rect.left, rect.top, rect.right, rect.bottom, NULL, NULL, hInst, NULL); // Show it, but don't activate it. If you activate it, it cause problems // with fullscreen startups in main window. SetWindowPos( hOutputWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW ); outwnd_disabled = FALSE; SetTimer(hOutputWnd, TIMER1, 50, NULL); for (x=0; x= 0); if (pos >= nCharRows - 1) // outside of window viewport, so scroll { SCROLLINFO si; pos = mprintf_last_line - n - nCharRows / 2; if (pos < 0) pos += SCROLL_BUFFER_SIZE; if (pos > max_scroll_pos) pos = max_scroll_pos; scroll_pos = max_scroll_pos - GetScrollPos(hOutputWnd, SB_VERT); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; si.nPos = max_scroll_pos - pos; SetScrollInfo(hOutputWnd, SB_VERT, &si, 1); ScrollWindow(hOutputWnd, 0, (scroll_pos - pos) * nTextHeight, NULL, NULL); } InvalidateRect(hOutputWnd, NULL, 0); UpdateWindow(hOutputWnd); return; } n--; if (n < 0) n += SCROLL_BUFFER_SIZE; if (n == mprintf_last_line) { MessageBox(hOutputWnd, "Search text not found", "Find Error", MB_OK | MB_ICONERROR); find_line = -1; return; } str = outtext[n]; } } void outwnd_close() { #ifndef NDEBUG if ( Log_fp != NULL ) { fclose(Log_fp); Log_fp = NULL; } #endif } #endif //NDEBUG #include "debugconsole/dbugfile.h" #include #include #include #include char safe_string[512] = {0}; void safe_point_print(char *format, ...){ char tmp[512]; va_list args; va_start(args, format); vsprintf(tmp, format, args); va_end(args); strcpy(safe_string, tmp); } void safe_point(char *file, int line, char *format, ...) { safe_point_print("last safepoint: %s, %d; [%s]", file, line, format); }