void DoRBFDialog(const char *FileName) { RBFName = FileName; Sys_GrabMouseCursor( false ); DialogBox(0, MAKEINTRESOURCE(IDD_RENDERBUMPFLAT), 0, (DLGPROC)RBFProc); Sys_GrabMouseCursor( true ); }
/* =============== idCommonLocal::UpdateScreen This is an out-of-sequence screen update, not the normal game rendering =============== */ void idCommonLocal::UpdateScreen( bool captureToImage ) { if ( insideUpdateScreen ) { return; } insideUpdateScreen = true; // make sure the game / draw thread has completed gameThread.WaitForThread(); // release the mouse capture back to the desktop Sys_GrabMouseCursor( false ); // build all the draw commands without running a new game tic Draw(); if ( captureToImage ) { renderSystem->CaptureRenderToImage( "_currentRender", false ); } // this should exit right after vsync, with the GPU idle and ready to draw const emptyCommand_t * cmd = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu ); // get the GPU busy with new commands renderSystem->RenderCommandBuffers( cmd ); insideUpdateScreen = false; }
/** * Initializes the material editor tool. */ void MaterialEditorInit( void ) { InitPropTree(win32.hInstance); com_editors = EDITOR_MATERIAL; Sys_GrabMouseCursor( false ); InitAfx(); InitCommonControls(); // Initialize OLE libraries if (!AfxOleInit()) { return; } AfxEnableControlContainer(); NONCLIENTMETRICS info; info.cbSize = sizeof(info); ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0); LOGFONT lf; memset(&lf, 0, sizeof (LOGFONT)); CWindowDC dc(NULL); lf.lfCharSet = (BYTE)GetTextCharsetInfo(dc.GetSafeHdc(), NULL, 0); lf.lfHeight = info.lfMenuFont.lfHeight; lf.lfWeight = info.lfMenuFont.lfWeight; lf.lfItalic = info.lfMenuFont.lfItalic; // check if we should use system font _tcscpy(lf.lfFaceName, info.lfMenuFont.lfFaceName); materialEditorFont = new CFont; materialEditorFont->CreateFontIndirect(&lf); // To create the main window, this code creates a new frame window // object and then sets it as the application's main window object meMainFrame = new MEMainFrame; // create and load the frame with its resources meMainFrame->LoadFrame(IDR_ME_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL); // hide the doom window by default ::ShowWindow ( win32.hWnd, SW_HIDE ); // The one and only window has been initialized, so show and update it meMainFrame->ShowWindow(SW_SHOW); meMainFrame->UpdateWindow(); }
/* =========== Sys_InitInput =========== */ void Sys_InitInput( void ) { common->Printf ("\n------- Input Initialization -------\n"); IN_InitDirectInput(); if ( win32.in_mouse.GetBool() ) { IN_InitDIMouse(); // don't grab the mouse on initialization Sys_GrabMouseCursor( false ); } else { common->Printf ("Mouse control not active.\n"); } IN_StartupKeyboard(); common->Printf ("------------------------------------\n"); win32.in_mouse.ClearModified(); }
/* ================= RadiantInit This is also called when you 'quit' in doom ================= */ void RadiantInit( void ) { // make sure the renderer is initialized if ( !renderSystem->IsOpenGLRunning() ) { common->Printf( "no OpenGL running\n" ); return; } g_editorAlive = true; // allocate a renderWorld and a soundWorld if ( g_qeglobals.rw == NULL ) { g_qeglobals.rw = renderSystem->AllocRenderWorld(); g_qeglobals.rw->InitFromMap( NULL ); } if ( g_qeglobals.sw == NULL ) { g_qeglobals.sw = soundSystem->AllocSoundWorld( g_qeglobals.rw ); } if ( g_DoomInstance ) { if ( ::IsWindowVisible( win32.hWnd ) ) { ::ShowWindow( win32.hWnd, SW_HIDE ); g_pParentWnd->ShowWindow( SW_SHOW ); g_pParentWnd->SetFocus(); } } else { Sys_GrabMouseCursor( false ); g_DoomInstance = win32.hInstance; CWinApp* pApp = AfxGetApp(); CWinThread *pThread = AfxGetThread(); InitAfx(); // App global initializations (rare) pApp->InitApplication(); // Perform specific initializations pThread->InitInstance(); qglFinish(); //qwglMakeCurrent(0, 0); qwglMakeCurrent(win32.hDC, win32.hGLRC); // hide the doom window by default ::ShowWindow( win32.hWnd, SW_HIDE ); } }
/* =============== GLX_Init =============== */ int GLX_Init(glimpParms_t a) { int attrib[] = { GLX_RGBA, // 0 GLX_RED_SIZE, 8, // 1, 2 GLX_GREEN_SIZE, 8, // 3, 4 GLX_BLUE_SIZE, 8, // 5, 6 GLX_DOUBLEBUFFER, // 7 GLX_DEPTH_SIZE, 24, // 8, 9 GLX_STENCIL_SIZE, 8, // 10, 11 GLX_ALPHA_SIZE, 8, // 12, 13 None }; // these match in the array #define ATTR_RED_IDX 2 #define ATTR_GREEN_IDX 4 #define ATTR_BLUE_IDX 6 #define ATTR_DEPTH_IDX 9 #define ATTR_STENCIL_IDX 11 #define ATTR_ALPHA_IDX 13 Window root; XVisualInfo *visinfo; XSetWindowAttributes attr; XSizeHints sizehints; unsigned long mask; int colorbits, depthbits, stencilbits; int tcolorbits, tdepthbits, tstencilbits; int actualWidth, actualHeight; int i; const char *glstring; if ( !GLimp_OpenDisplay() ) { return false; } common->Printf( "Initializing OpenGL display\n" ); root = RootWindow( dpy, scrnum ); actualWidth = glConfig.vidWidth; actualHeight = glConfig.vidHeight; // Get video mode list if ( !XF86VidModeQueryVersion( dpy, &vidmode_MajorVersion, &vidmode_MinorVersion ) ) { vidmode_ext = false; common->Printf("XFree86-VidModeExtension not available\n"); } else { vidmode_ext = true; common->Printf("Using XFree86-VidModeExtension Version %d.%d\n", vidmode_MajorVersion, vidmode_MinorVersion); } GLX_TestDGA(); if ( vidmode_ext ) { int best_fit, best_dist, dist, x, y; XF86VidModeGetAllModeLines( dpy, scrnum, &num_vidmodes, &vidmodes ); // Are we going fullscreen? If so, let's change video mode if ( a.fullScreen ) { best_dist = 9999999; best_fit = -1; for (i = 0; i < num_vidmodes; i++) { if (a.width > vidmodes[i]->hdisplay || a.height > vidmodes[i]->vdisplay) continue; x = a.width - vidmodes[i]->hdisplay; y = a.height - vidmodes[i]->vdisplay; dist = (x * x) + (y * y); if (dist < best_dist) { best_dist = dist; best_fit = i; } } if (best_fit != -1) { actualWidth = vidmodes[best_fit]->hdisplay; actualHeight = vidmodes[best_fit]->vdisplay; // change to the mode XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]); vidmode_active = true; // Move the viewport to top left // FIXME: center? XF86VidModeSetViewPort(dpy, scrnum, 0, 0); common->Printf( "Free86-VidModeExtension Activated at %dx%d\n", actualWidth, actualHeight ); } else { a.fullScreen = false; common->Printf( "Free86-VidModeExtension: No acceptable modes found\n" ); } } else { common->Printf( "XFree86-VidModeExtension: not fullscreen, ignored\n" ); } } // color, depth and stencil colorbits = 24; depthbits = 24; stencilbits = 8; for (i = 0; i < 16; i++) { // 0 - default // 1 - minus colorbits // 2 - minus depthbits // 3 - minus stencil if ((i % 4) == 0 && i) { // one pass, reduce switch (i / 4) { case 2: if (colorbits == 24) colorbits = 16; break; case 1: if (depthbits == 24) depthbits = 16; else if (depthbits == 16) depthbits = 8; case 3: if (stencilbits == 24) stencilbits = 16; else if (stencilbits == 16) stencilbits = 8; } } tcolorbits = colorbits; tdepthbits = depthbits; tstencilbits = stencilbits; if ((i % 4) == 3) // reduce colorbits { if (tcolorbits == 24) tcolorbits = 16; } if ((i % 4) == 2) // reduce depthbits { if (tdepthbits == 24) tdepthbits = 16; else if (tdepthbits == 16) tdepthbits = 8; } if ((i % 4) == 1) // reduce stencilbits { if (tstencilbits == 24) tstencilbits = 16; else if (tstencilbits == 16) tstencilbits = 8; else tstencilbits = 0; } if (tcolorbits == 24) { attrib[ATTR_RED_IDX] = 8; attrib[ATTR_GREEN_IDX] = 8; attrib[ATTR_BLUE_IDX] = 8; } else { // must be 16 bit attrib[ATTR_RED_IDX] = 4; attrib[ATTR_GREEN_IDX] = 4; attrib[ATTR_BLUE_IDX] = 4; } attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth attrib[ATTR_STENCIL_IDX] = tstencilbits; visinfo = qglXChooseVisual(dpy, scrnum, attrib); if (!visinfo) { continue; } common->Printf( "Using %d/%d/%d Color bits, %d Alpha bits, %d depth, %d stencil display.\n", attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX], attrib[ATTR_ALPHA_IDX], attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]); glConfig.colorBits = tcolorbits; glConfig.depthBits = tdepthbits; glConfig.stencilBits = tstencilbits; break; } if (!visinfo) { common->Printf("Couldn't get a visual\n"); return false; } // window attributes attr.background_pixel = BlackPixel(dpy, scrnum); attr.border_pixel = 0; attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone); attr.event_mask = X_MASK; if (vidmode_active) { mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | CWEventMask | CWOverrideRedirect; attr.override_redirect = True; attr.backing_store = NotUseful; attr.save_under = False; } else { mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; } win = XCreateWindow(dpy, root, 0, 0, actualWidth, actualHeight, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr); XStoreName(dpy, win, GAME_NAME); // don't let the window be resized // FIXME: allow resize (win32 does) sizehints.flags = PMinSize | PMaxSize; sizehints.min_width = sizehints.max_width = actualWidth; sizehints.min_height = sizehints.max_height = actualHeight; XSetWMNormalHints(dpy, win, &sizehints); XMapWindow( dpy, win ); if ( vidmode_active ) { XMoveWindow( dpy, win, 0, 0 ); } XFlush(dpy); XSync(dpy, False); ctx = qglXCreateContext(dpy, visinfo, NULL, True); XSync(dpy, False); // Free the visinfo after we're done with it XFree(visinfo); qglXMakeCurrent(dpy, win, ctx); glstring = (const char *) qglGetString(GL_RENDERER); common->Printf("GL_RENDERER: %s\n", glstring); glstring = (const char *) qglGetString(GL_EXTENSIONS); common->Printf("GL_EXTENSIONS: %s\n", glstring); // FIXME: here, software GL test glConfig.isFullscreen = a.fullScreen; if ( glConfig.isFullscreen ) { Sys_GrabMouseCursor( true ); } return true; }
/* ================= idCommonLocal::Frame ================= */ void idCommonLocal::Frame() { try { SCOPED_PROFILE_EVENT( "Common::Frame" ); // This is the only place this is incremented idLib::frameNumber++; // allow changing SIMD usage on the fly if ( com_forceGenericSIMD.IsModified() ) { idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() ); com_forceGenericSIMD.ClearModified(); } // Do the actual switch between Doom 3 and the classics here so // that things don't get confused in the middle of the frame. PerformGameSwitch(); // pump all the events Sys_GenerateEvents(); // write config file if anything changed WriteConfiguration(); eventLoop->RunEventLoop(); // Activate the shell if it's been requested if ( showShellRequested && game ) { game->Shell_Show( true ); showShellRequested = false; } // if the console or another gui is down, we don't need to hold the mouse cursor bool chatting = false; if ( console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing() || ( game && game->InhibitControls() && !IsPlayingDoomClassic() ) ) { Sys_GrabMouseCursor( false ); usercmdGen->InhibitUsercmd( INHIBIT_SESSION, true ); chatting = true; } else { Sys_GrabMouseCursor( true ); usercmdGen->InhibitUsercmd( INHIBIT_SESSION, false ); } const bool pauseGame = ( !mapSpawned || ( !IsMultiplayer() && ( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || ( game && game->Shell_IsActive() ) ) ) ) && !IsPlayingDoomClassic(); // save the screenshot and audio from the last draw if needed if ( aviCaptureMode ) { idStr name = va("demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviDemoFrameCount++ ); renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); // remove any printed lines at the top before taking the screenshot console->ClearNotifyLines(); // this will call Draw, possibly multiple times if com_aviDemoSamples is > 1 renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); } //-------------------------------------------- // wait for the GPU to finish drawing // // It is imporant to minimize the time spent between this // section and the call to renderSystem->RenderCommandBuffers(), // because the GPU is completely idle. //-------------------------------------------- // this should exit right after vsync, with the GPU idle and ready to draw // This may block if the GPU isn't finished renderng the previous frame. frameTiming.startSyncTime = Sys_Microseconds(); const emptyCommand_t * renderCommands = NULL; if ( com_smp.GetBool() ) { renderCommands = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } else { // the GPU will stay idle through command generation for minimal // input latency renderSystem->SwapCommandBuffers_FinishRendering( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } frameTiming.finishSyncTime = Sys_Microseconds(); //-------------------------------------------- // Determine how many game tics we are going to run, // now that the previous frame is completely finished. // // It is important that any waiting on the GPU be done // before this, or there will be a bad stuttering when // dropping frames for performance management. //-------------------------------------------- // input: // thisFrameTime // com_noSleep // com_engineHz // com_fixedTic // com_deltaTimeClamp // IsMultiplayer // // in/out state: // gameFrame // gameTimeResidual // lastFrameTime // syncNextFrame // // Output: // numGameFrames // How many game frames to run int numGameFrames = 0; for(;;) { const int thisFrameTime = Sys_Milliseconds(); static int lastFrameTime = thisFrameTime; // initialized only the first time const int deltaMilliseconds = thisFrameTime - lastFrameTime; lastFrameTime = thisFrameTime; // if there was a large gap in time since the last frame, or the frame // rate is very very low, limit the number of frames we will run const int clampedDeltaMilliseconds = Min( deltaMilliseconds, com_deltaTimeClamp.GetInteger() ); gameTimeResidual += clampedDeltaMilliseconds * timescale.GetFloat(); // don't run any frames when paused if ( pauseGame ) { gameFrame++; gameTimeResidual = 0; break; } // debug cvar to force multiple game tics if ( com_fixedTic.GetInteger() > 0 ) { numGameFrames = com_fixedTic.GetInteger(); gameFrame += numGameFrames; gameTimeResidual = 0; break; } if ( syncNextGameFrame ) { // don't sleep at all syncNextGameFrame = false; gameFrame++; numGameFrames++; gameTimeResidual = 0; break; } for ( ;; ) { // How much time to wait before running the next frame, // based on com_engineHz const int frameDelay = FRAME_TO_MSEC( gameFrame + 1 ) - FRAME_TO_MSEC( gameFrame ); if ( gameTimeResidual < frameDelay ) { break; } gameTimeResidual -= frameDelay; gameFrame++; numGameFrames++; // if there is enough residual left, we may run additional frames } if ( numGameFrames > 0 ) { // ready to actually run them break; } // if we are vsyncing, we always want to run at least one game // frame and never sleep, which might happen due to scheduling issues // if we were just looking at real time. if ( com_noSleep.GetBool() ) { numGameFrames = 1; gameFrame += numGameFrames; gameTimeResidual = 0; break; } // not enough time has passed to run a frame, as might happen if // we don't have vsync on, or the monitor is running at 120hz while // com_engineHz is 60, so sleep a bit and check again Sys_Sleep( 0 ); } //-------------------------------------------- // It would be better to push as much of this as possible // either before or after the renderSystem->SwapCommandBuffers(), // because the GPU is completely idle. //-------------------------------------------- // Update session and syncronize to the new session state after sleeping session->UpdateSignInManager(); session->Pump(); session->ProcessSnapAckQueue(); if ( session->GetState() == idSession::LOADING ) { // If the session reports we should be loading a map, load it! ExecuteMapChange(); mapSpawnData.savegameFile = NULL; mapSpawnData.persistentPlayerInfo.Clear(); return; } else if ( session->GetState() != idSession::INGAME && mapSpawned ) { // If the game is running, but the session reports we are not in a game, disconnect // This happens when a server disconnects us or we sign out LeaveGame(); return; } if ( mapSpawned && !pauseGame ) { if ( IsClient() ) { RunNetworkSnapshotFrame(); } } ExecuteReliableMessages(); // send frame and mouse events to active guis GuiFrameEvents(); //-------------------------------------------- // Prepare usercmds and kick off the game processing // in a background thread //-------------------------------------------- // get the previous usercmd for bypassed head tracking transform const usercmd_t previousCmd = usercmdGen->GetCurrentUsercmd(); // build a new usercmd int deviceNum = session->GetSignInManager().GetMasterInputDevice(); usercmdGen->BuildCurrentUsercmd( deviceNum ); if ( deviceNum == -1 ) { for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) { Sys_PollJoystickInputEvents( i ); Sys_EndJoystickInputEvents(); } } if ( pauseGame ) { usercmdGen->Clear(); } usercmd_t newCmd = usercmdGen->GetCurrentUsercmd(); // Store server game time - don't let time go past last SS time in case we are extrapolating if ( IsClient() ) { newCmd.serverGameMilliseconds = std::min( Game()->GetServerGameTimeMs(), Game()->GetSSEndTime() ); } else { newCmd.serverGameMilliseconds = Game()->GetServerGameTimeMs(); } userCmdMgr.MakeReadPtrCurrentForPlayer( Game()->GetLocalClientNum() ); // Stuff a copy of this userCmd for each game frame we are going to run. // Ideally, the usercmds would be built in another thread so you could // still get 60hz control accuracy when the game is running slower. for ( int i = 0 ; i < numGameFrames ; i++ ) { newCmd.clientGameMilliseconds = FRAME_TO_MSEC( gameFrame-numGameFrames+i+1 ); userCmdMgr.PutUserCmdForPlayer( game->GetLocalClientNum(), newCmd ); } // If we're in Doom or Doom 2, run tics and upload the new texture. if ( ( GetCurrentGame() == DOOM_CLASSIC || GetCurrentGame() == DOOM2_CLASSIC ) && !( Dialog().IsDialogPausing() || session->IsSystemUIShowing() ) ) { RunDoomClassicFrame(); } // start the game / draw command generation thread going in the background gameReturn_t ret = gameThread.RunGameAndDraw( numGameFrames, userCmdMgr, IsClient(), gameFrame - numGameFrames ); if ( !com_smp.GetBool() ) { // in non-smp mode, run the commands we just generated, instead of // frame-delayed ones from a background thread renderCommands = renderSystem->SwapCommandBuffers_FinishCommandBuffers(); } //---------------------------------------- // Run the render back end, getting the GPU busy with new commands // ASAP to minimize the pipeline bubble. //---------------------------------------- frameTiming.startRenderTime = Sys_Microseconds(); renderSystem->RenderCommandBuffers( renderCommands ); if ( com_sleepRender.GetInteger() > 0 ) { // debug tool to test frame adaption Sys_Sleep( com_sleepRender.GetInteger() ); } frameTiming.finishRenderTime = Sys_Microseconds(); // make sure the game / draw thread has completed // This may block if the game is taking longer than the render back end gameThread.WaitForThread(); // Send local usermds to the server. // This happens after the game frame has run so that prediction data is up to date. SendUsercmds( Game()->GetLocalClientNum() ); // Now that we have an updated game frame, we can send out new snapshots to our clients session->Pump(); // Pump to get updated usercmds to relay SendSnapshots(); // Render the sound system using the latest commands from the game thread if ( pauseGame ) { soundWorld->Pause(); soundSystem->SetPlayingSoundWorld( menuSoundWorld ); } else { soundWorld->UnPause(); soundSystem->SetPlayingSoundWorld( soundWorld ); } soundSystem->Render(); // process the game return for map changes, etc ProcessGameReturn( ret ); idLobbyBase & lobby = session->GetActivePlatformLobbyBase(); if ( lobby.HasActivePeers() ) { if ( net_drawDebugHud.GetInteger() == 1 ) { lobby.DrawDebugNetworkHUD(); } if ( net_drawDebugHud.GetInteger() == 2 ) { lobby.DrawDebugNetworkHUD2(); } lobby.DrawDebugNetworkHUD_ServerSnapshotMetrics( net_drawDebugHud.GetInteger() == 3 ); } // report timing information if ( com_speeds.GetBool() ) { static int lastTime = Sys_Milliseconds(); int nowTime = Sys_Milliseconds(); int com_frameMsec = nowTime - lastTime; lastTime = nowTime; Printf( "frame:%d all:%3d gfr:%3d rf:%3lld bk:%3lld\n", idLib::frameNumber, com_frameMsec, time_gameFrame, time_frontend / 1000, time_backend / 1000 ); time_gameFrame = 0; time_gameDraw = 0; } // the FPU stack better be empty at this point or some bad code or compiler bug left values on the stack if ( !Sys_FPU_StackIsEmpty() ) { Printf( Sys_FPU_GetState() ); FatalError( "idCommon::Frame: the FPU stack is not empty at the end of the frame\n" ); } mainFrameTiming = frameTiming; session->GetSaveGameManager().Pump(); } catch( idException & ) { return; // an ERP_DROP was thrown } }
/* ================ rvGEApp::Initialize Initialize the gui editor application ================ */ bool rvGEApp::Initialize ( void ) { mOptions.Init(); // Mutually exclusive com_editors = EDITOR_GUI; Sys_GrabMouseCursor( false ); // Load the options mOptions.Load ( ); mInstance = win32.hInstance; // Create the accelerators mAccelerators = LoadAccelerators ( mInstance, MAKEINTRESOURCE(IDR_GUIED_ACCELERATORS) ); // Register the window classes for the main frame and the mdi child window WNDCLASSEX wndClass; memset ( &wndClass, 0, sizeof(wndClass) ); wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.lpszClassName = "QUAKE4_GUIEDITOR_CLASS"; wndClass.lpfnWndProc = FrameWndProc; wndClass.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1); wndClass.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_GUIED_MAIN); wndClass.hInstance = mInstance; RegisterClassEx ( &wndClass ); wndClass.lpszMenuName = NULL; wndClass.lpfnWndProc = MDIChildProc; wndClass.lpszClassName = "QUAKE4_GUIEDITOR_CHILD_CLASS"; wndClass.style = CS_OWNDC|CS_DBLCLKS|CS_BYTEALIGNWINDOW|CS_VREDRAW|CS_HREDRAW; wndClass.hbrBackground = (HBRUSH)GetStockObject( LTGRAY_BRUSH ); RegisterClassEx ( &wndClass ); // Create the main window mMDIFrame = CreateWindow ( "QUAKE4_GUIEDITOR_CLASS", "Quake IV GUI Editor", WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, mInstance, (LPVOID)this ); if ( !mMDIFrame ) { return false; } SetClassLong( mMDIFrame, GCL_HICON, ( LONG )LoadIcon( win32.hInstance, MAKEINTRESOURCE( IDI_GUIED ) ) ); // Create the MDI window CLIENTCREATESTRUCT ccs; ccs.hWindowMenu = GetSubMenu ( GetMenu ( mMDIFrame ), 5 ); ccs.idFirstChild = IDM_WINDOWCHILD; mMDIClient = CreateWindow ( "MDICLIENT", NULL, WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 1000, 1000, mMDIFrame, NULL, mInstance, &ccs ); if ( !mMDIClient ) { DestroyWindow ( mMDIFrame ); return false; } // hide the doom window by default ::ShowWindow ( win32.hWnd, SW_HIDE ); // Show both windows mOptions.GetWindowPlacement ( "mdiframe", mMDIFrame ); ShowWindow ( mMDIFrame, SW_SHOW ); UpdateWindow ( mMDIFrame ); ShowWindow ( mMDIClient, SW_SHOW ); UpdateWindow ( mMDIClient ); return true; }
/* ================ rvDebuggerServer::Break Halt execution of the game threads and inform the debugger client that the game has been halted ================ */ void rvDebuggerServer::Break ( idInterpreter* interpreter, idProgram* program, int instructionPointer ) { msg_t msg; byte buffer[MAX_MSGLEN]; const statement_t* st; const char* filename; // Clear all the break types mBreakStepOver = false; mBreakStepInto = false; mBreakNext = false; // Grab the current statement and the filename that it came from st = &program->GetStatement ( instructionPointer ); filename = program->GetFilename ( st->file ); idStr qpath; OSPathToRelativePath(filename, qpath); qpath.BackSlashesToSlashes ( ); // Give the mouse cursor back to the world Sys_GrabMouseCursor( false ); // Set the break variable so we know the main thread is stopped mBreak = true; mBreakProgram = program; mBreakInterpreter = interpreter; mBreakInstructionPointer = instructionPointer; // Inform the debugger of the breakpoint hit MSG_Init( &msg, buffer, sizeof( buffer ) ); MSG_WriteShort ( &msg, (int)DBMSG_BREAK ); MSG_WriteLong ( &msg, st->linenumber ); MSG_WriteString ( &msg, qpath ); SendPacket ( msg.data, msg.cursize ); // Suspend the game thread. Since this will be called from within the main game thread // execution wont return until after the thread is resumed SuspendThread ( mGameThread ); // Let the debugger client know that we have started back up again SendMessage ( DBMSG_RESUMED ); // This is to give some time between the keypress that // told us to resume and the setforeground window. Otherwise the quake window // would just flash Sleep ( 150 ); // Bring the window back to the foreground SetForegroundWindow ( win32.hWnd ); SetActiveWindow ( win32.hWnd ); UpdateWindow ( win32.hWnd ); SetFocus ( win32.hWnd ); // Give the mouse cursor back to the game Sys_GrabMouseCursor( true ); // Clear all commands that were generated before we went into suspended mode. This is // to ensure we dont have mouse downs with no ups because the context was changed. idKeyInput::ClearStates(); }
/* =============== idCommonLocal::ExecuteMapChange Performs the initialization of a game based on session match parameters, used for both single player and multiplayer, but not for renderDemos, which don't create a game at all. Exits with mapSpawned = true =============== */ void idCommonLocal::ExecuteMapChange() { if ( session->GetState() != idSession::LOADING ) { idLib::Warning( "Session state is not LOADING in ExecuteMapChange" ); return; } // Clear all dialogs before beginning the load common->Dialog().ClearDialogs( true ); // Remember the current load ID. // This is so we can tell if we had a new loadmap request from within an existing loadmap call const int cachedLoadingID = session->GetLoadingID(); const idMatchParameters & matchParameters = session->GetActingGameStateLobbyBase().GetMatchParms(); if ( matchParameters.numSlots <= 0 ) { idLib::Warning( "numSlots <= 0 in ExecuteMapChange" ); return; } insideExecuteMapChange = true; common->Printf( "--------- Execute Map Change ---------\n" ); common->Printf( "Map: %s\n", matchParameters.mapName.c_str() ); // ensure that r_znear is reset to the default value // this fixes issues with the projection matrix getting messed up when switching maps or loading a saved game // while an in-game cinematic is playing. cvarSystem->SetCVarFloat( "r_znear", 1.0f ); // reset all cheat cvars for a multiplayer game if ( IsMultiplayer() ) { cvarSystem->ResetFlaggedVariables( CVAR_CHEAT ); } int start = Sys_Milliseconds(); for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) { Sys_SetRumble( i, 0, 0 ); } // close console and remove any prints from the notify lines console->Close(); // clear all menu sounds soundWorld->Pause(); menuSoundWorld->ClearAllSoundEmitters(); soundSystem->SetPlayingSoundWorld( menuSoundWorld ); soundSystem->Render(); // extract the map name from serverinfo currentMapName = matchParameters.mapName; currentMapName.StripFileExtension(); idStrStatic< MAX_OSPATH > fullMapName = "maps/"; fullMapName += currentMapName; fullMapName.SetFileExtension( "map" ); if ( mapSpawnData.savegameFile ) { fileSystem->BeginLevelLoad( currentMapName, NULL, 0 ); } else { fileSystem->BeginLevelLoad( currentMapName, saveFile.GetDataPtr(), saveFile.GetAllocated() ); } // capture the current screen and start a wipe // immediately complete the wipe to fade out the level transition // run the wipe to completion StartWipe( "wipeMaterial", true ); CompleteWipe(); int sm = Sys_Milliseconds(); // shut down the existing game if it is running UnloadMap(); int ms = Sys_Milliseconds() - sm; common->Printf( "%6d msec to unload map\n", ms ); // Free media from previous level and // note which media we are going to need to load sm = Sys_Milliseconds(); renderSystem->BeginLevelLoad(); soundSystem->BeginLevelLoad(); declManager->BeginLevelLoad(); uiManager->BeginLevelLoad(); ms = Sys_Milliseconds() - sm; common->Printf( "%6d msec to free assets\n", ms ); //Sys_DumpMemory( true ); // load / program a gui to stay up on the screen while loading // set the loading gui that we will wipe to bool hellMap = false; LoadLoadingGui( currentMapName, hellMap ); // Stop rendering the wipe ClearWipe(); if ( fileSystem->UsingResourceFiles() ) { idStrStatic< MAX_OSPATH > manifestName = currentMapName; manifestName.Replace( "game/", "maps/" ); manifestName.Replace( "/mp/", "/" ); manifestName += ".preload"; idPreloadManifest manifest; manifest.LoadManifest( manifestName ); renderSystem->Preload( manifest, currentMapName ); soundSystem->Preload( manifest ); game->Preload( manifest ); } if ( common->IsMultiplayer() ) { // In multiplayer, make sure the player is either 60Hz or 120Hz // to avoid potential issues. const float mpEngineHz = ( com_engineHz.GetFloat() < 90.0f ) ? 60.0f : 120.0f; com_engineHz_denominator = 100LL * mpEngineHz; com_engineHz_latched = mpEngineHz; } else { // allow com_engineHz to be changed between map loads com_engineHz_denominator = 100LL * com_engineHz.GetFloat(); com_engineHz_latched = com_engineHz.GetFloat(); } // note any warning prints that happen during the load process common->ClearWarnings( currentMapName ); // release the mouse cursor // before we do this potentially long operation Sys_GrabMouseCursor( false ); // let the renderSystem load all the geometry if ( !renderWorld->InitFromMap( fullMapName ) ) { common->Error( "couldn't load %s", fullMapName.c_str() ); } // for the synchronous networking we needed to roll the angles over from // level to level, but now we can just clear everything usercmdGen->InitForNewMap(); // load and spawn all other entities ( from a savegame possibly ) if ( mapSpawnData.savegameFile ) { if ( !game->InitFromSaveGame( fullMapName, renderWorld, soundWorld, mapSpawnData.savegameFile, mapSpawnData.stringTableFile, mapSpawnData.savegameVersion ) ) { // If the loadgame failed, end the session, which will force us to go back to the main menu session->QuitMatchToTitle(); } } else { if ( !IsMultiplayer() ) { assert( game->GetLocalClientNum() == 0 ); assert( matchParameters.gameMode == GAME_MODE_SINGLEPLAYER ); assert( matchParameters.gameMap == GAME_MAP_SINGLEPLAYER ); game->SetPersistentPlayerInfo( 0, mapSpawnData.persistentPlayerInfo ); } game->SetServerInfo( matchParameters.serverInfo ); game->InitFromNewMap( fullMapName, renderWorld, soundWorld, matchParameters.gameMode, Sys_Milliseconds() ); } game->Shell_CreateMenu( true ); // Reset some values important to multiplayer ResetNetworkingState(); // If the session state is not loading here, something went wrong. if ( session->GetState() == idSession::LOADING && session->GetLoadingID() == cachedLoadingID ) { // Notify session we are done loading session->LoadingFinished(); while ( session->GetState() == idSession::LOADING ) { Sys_GenerateEvents(); session->UpdateSignInManager(); session->Pump(); Sys_Sleep( 10 ); } } if ( !mapSpawnData.savegameFile ) { // run a single frame to catch any resources that are referenced by events posted in spawn idUserCmdMgr emptyCommandManager; gameReturn_t emptyGameReturn; for ( int playerIndex = 0; playerIndex < MAX_PLAYERS; ++playerIndex ) { emptyCommandManager.PutUserCmdForPlayer( playerIndex, usercmd_t() ); } if ( IsClient() ) { game->ClientRunFrame( emptyCommandManager, false, emptyGameReturn ); } else { game->RunFrame( emptyCommandManager, emptyGameReturn ); } } renderSystem->EndLevelLoad(); soundSystem->EndLevelLoad(); declManager->EndLevelLoad(); uiManager->EndLevelLoad( currentMapName ); fileSystem->EndLevelLoad(); if ( !mapSpawnData.savegameFile && !IsMultiplayer() ) { common->Printf( "----- Running initial game frames -----\n" ); // In single player, run a bunch of frames to make sure ragdolls are settled idUserCmdMgr emptyCommandManager; gameReturn_t emptyGameReturn; for ( int i = 0; i < 100; i++ ) { for ( int playerIndex = 0; playerIndex < MAX_PLAYERS; ++playerIndex ) { emptyCommandManager.PutUserCmdForPlayer( playerIndex, usercmd_t() ); } game->RunFrame( emptyCommandManager, emptyGameReturn ); } // kick off an auto-save of the game (so we can always continue in this map if we die before hitting an autosave) common->Printf( "----- Saving Game -----\n" ); SaveGame( "autosave" ); } common->Printf( "----- Generating Interactions -----\n" ); // let the renderSystem generate interactions now that everything is spawned renderWorld->GenerateAllInteractions(); { int vertexMemUsedKB = vertexCache.staticData.vertexMemUsed.GetValue() / 1024; int indexMemUsedKB = vertexCache.staticData.indexMemUsed.GetValue() / 1024; idLib::Printf( "Used %dkb of static vertex memory (%d%%)\n", vertexMemUsedKB, vertexMemUsedKB * 100 / ( STATIC_VERTEX_MEMORY / 1024 ) ); idLib::Printf( "Used %dkb of static index memory (%d%%)\n", indexMemUsedKB, indexMemUsedKB * 100 / ( STATIC_INDEX_MEMORY / 1024 ) ); } if ( common->JapaneseCensorship() ) { if ( currentMapName.Icmp( "game/mp/d3xpdm3" ) == 0 ) { const idMaterial * gizpool2 = declManager->FindMaterial( "textures/hell/gizpool2" ); idMaterial * chiglass1bluex = const_cast<idMaterial *>( declManager->FindMaterial( "textures/sfx/chiglass1bluex" ) ); idTempArray<char> text( gizpool2->GetTextLength() ); gizpool2->GetText( text.Ptr() ); chiglass1bluex->Parse( text.Ptr(), text.Num(), false ); } } common->PrintWarnings(); session->Pump(); if ( session->GetState() != idSession::INGAME ) { // Something went wrong, don't process stale reliables that have been queued up. reliableQueue.Clear(); } usercmdGen->Clear(); // remove any prints from the notify lines console->ClearNotifyLines(); Sys_SetPhysicalWorkMemory( -1, -1 ); // at this point we should be done with the loading gui so we kill it delete loadGUI; loadGUI = NULL; // capture the current screen and start a wipe StartWipe( "wipe2Material" ); // we are valid for game draws now insideExecuteMapChange = false; mapSpawned = true; Sys_ClearEvents(); int msec = Sys_Milliseconds() - start; common->Printf( "%6d msec to load %s\n", msec, currentMapName.c_str() ); //Sys_DumpMemory( false ); // Issue a render at the very end of the load process to update soundTime before the first frame soundSystem->Render(); }
bool Console::ProcessEvent( const sysEvent_t* event, bool forceAccept ) { if( isInitialized() ) { const bool consoleKey = event->evType == SE_KEY && event->evValue == K_GRAVE && com_allowConsole.GetBool(); const bool tabKey = event->evType == SE_KEY && event->evValue == K_TAB; // we always catch the console key event if( !forceAccept && consoleKey ) { // ignore up events if( event->evValue2 == 0 ) { return true; } // if window is Active we close it with consoleKey if( Active() ) { Close(); Sys_GrabMouseCursor( true ); } else { Open(); Sys_GrabMouseCursor( false ); } return true; } // return event as processed when console open // aka don't pass the input further if( Active() ) { if( tabKey ) { // ignore up events if( event->evValue2 == 0 ) { return true; } TabComplete(); } return true; } // if we aren't Active, dump all the other events if( !forceAccept && !Active() ) { return false; } if( forceAccept ) { // a dummy here return true; } // we don't handle things like mouse, joystick, and network packets return false; } return false; }
/* ============== ProcessEvent ============== */ bool idConsoleLocal::ProcessEvent( const sysEvent_t* event, bool forceAccept ) { const bool consoleKey = event->evType == SE_KEY && event->evValue == K_GRAVE && com_allowConsole.GetBool(); // we always catch the console key event if( !forceAccept && consoleKey ) { // ignore up events if( event->evValue2 == 0 ) { return true; } consoleField.ClearAutoComplete(); // a down event will toggle the destination lines if( keyCatching ) { Close(); Sys_GrabMouseCursor( true ); } else { consoleField.Clear(); keyCatching = true; if( idKeyInput::IsDown( K_LSHIFT ) || idKeyInput::IsDown( K_RSHIFT ) ) { // if the shift key is down, don't open the console as much SetDisplayFraction( 0.2f ); } else { SetDisplayFraction( 0.5f ); } } return true; } // if we aren't key catching, dump all the other events if( !forceAccept && !keyCatching ) { return false; } // handle key and character events if( event->evType == SE_CHAR ) { // never send the console key as a character if( event->evValue != '`' && event->evValue != '~' ) { consoleField.CharEvent( event->evValue ); } return true; } if( event->evType == SE_KEY ) { // ignore up key events if( event->evValue2 == 0 ) { return true; } KeyDownEvent( event->evValue ); return true; } // we don't handle things like mouse, joystick, and network packets return false; }