void USwFMOD::Update( FPointRegion Region, FCoords& Coords ) { guard(USwFMOD::Update); FMOD_RESULT result; //SWF_LOG( NAME_DevSound, TEXT("%s >> %s :: [%s],[%s]"), SWF_PLOG, *ToStr(Region), *ToStr(Coords) ); if( !Viewport || !Viewport->IsValid() || !Viewport->Actor || !Viewport->Actor->IsValid() ) return; // Load geometry if( bOcclusion ) { static ULevel* level = NULL; if( Viewport->Actor->GetLevel() != level ) { level = Viewport->Actor->GetLevel(); LoadGeometry(); } } // Time passes... DOUBLE DeltaTime = appSeconds() - LastTime; LastTime += DeltaTime; DeltaTime = Clamp( DeltaTime, 0.0, 1.0 ); // Get viewactor AActor* ViewActor = Viewport->Actor->ViewTarget ? Viewport->Actor->ViewTarget : Viewport->Actor; // Is viewport realtime ? UBOOL Realtime = Viewport->IsRealtime() && Viewport->Actor->Level->Pauser == TEXT(""); // Default viewport coords FVector location = FVector(0,0,0); FVector velocity = FVector(0,0,0); FVector forward = FVector(1,0,0); FVector up = FVector(0,0,1); // // Update listener // guard(USwFMODAudio::Update::UpdateListener); // Use ViewActor coords FCoords coords = GMath.UnitCoords / ViewActor->Rotation;; coords.Origin = ViewActor->Location; // Set viewport coords location = coords.Origin; velocity = ViewActor->Velocity; forward = coords.XAxis; up = coords.ZAxis; // verify SWF_VERIFY_FVECTOR(location); SWF_VERIFY_FVECTOR(velocity); SWF_VERIFY_FVECTOR_NORMAL(forward); SWF_VERIFY_FVECTOR_NORMAL(up); // Default listener coords FMOD_VECTOR fm_pos = {0,0,0}; FMOD_VECTOR fm_vel = {0,0,0}; FMOD_VECTOR fm_fwd = {0,0,1}; FMOD_VECTOR fm_up = {0,1,0}; // Set listener coords fm_pos = ToFMODVector(location); fm_vel = ToFMODVector(velocity); fm_fwd = ToFMODNormal(forward); fm_up = ToFMODNormal(up); // verify SWF_VERIFY_FMODVECTOR(fm_pos); SWF_VERIFY_FMODVECTOR(fm_vel); SWF_VERIFY_FMODVECTOR_NORMAL(fm_fwd); SWF_VERIFY_FMODVECTOR_NORMAL(fm_up); // Update SWF_FMOD_CALL( System->set3DListenerAttributes( 0, &fm_pos, &fm_vel, &fm_fwd, &fm_up ) ); unguard; // // Zone effects // guard(USwFMODAudio::Update::UpdateZone); /*// Default zone properties UBOOL bWaterZone = 0; UBOOL bReverbZone = 0; UBOOL bRaytraceReverb = 0; BYTE MasterGain = 100; INT CutoffHz = 6000; BYTE Delay[6] = {20,34,0,0,0,0}; BYTE Gain[6] = {150,70,0,0,0,0}; // Get zone properties if( Region.Zone && Region.Zone->IsValid() ) { bWaterZone = Region.Zone->bWaterZone; bReverbZone = Region.Zone->bReverbZone; bRaytraceReverb = Region.Zone->bRaytraceReverb; MasterGain = Region.Zone->MasterGain; CutoffHz = Region.Zone->CutoffHz; appMemcpy(Delay, Region.Zone->Delay, 6*sizeof(BYTE)); appMemcpy(Gain, Region.Zone->Gain, 6*sizeof(BYTE)); }*/ unguard; // // Update sounds. // guard(USwFMODAudio::Update::UpdateSounds); // Iterate through all channels for( FSwChannelEnumerator it(System); it; ++it ) { FMOD::Channel* channel = *it; if( !IsChannelValid(channel) ) continue; // Channel data FMOD::Sound* sample = GetChannelSample(channel); if( !sample ) continue; UObject* object = GetSampleObject(sample); if( !object ) continue; USound* sound = Cast<USound>(object); FSwSoundId id = GetChannelId(channel); AActor* actor = id.GetActor(); FMOD_MODE fmode; SWF_FMOD_CALL( channel->getMode(&fmode) ); UBOOL bIs3D = HasFlag(fmode,FMOD_3D); // Sample defaults FLOAT deffrequency; FLOAT defvolume; FLOAT defpanning; INT defpriority; SWF_FMOD_CALL( sample->getDefaults( &deffrequency, &defvolume, &defpanning, &defpriority ) ); if( sound ) { if( actor && actor->IsValid() ) { // Ambient sounds if( id.GetSlot() == SLOT_Ambient ) { if( actor->AmbientSound != sound || FDist(location, actor->Location) > actor->WorldSoundRadius() + AmbientHysteresis || !Realtime ) { // Stop ambient sound //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: Ambient OUT [%d]"), SWF_PLOG, *ToStr(id) ); SWF_FMOD_CALL( channel->setUserData(NULL) ); SWF_FMOD_CALL( channel->stop() ); continue; } else { // Update ambient sound properties. FLOAT volume = actor->SoundVolume / 255.0f; FLOAT frequency = (actor->SoundPitch / 64.0f) * deffrequency; SWF_VERIFY_FLOAT(volume); SWF_VERIFY_FLOAT(frequency); SWF_FMOD_CALL( channel->setVolume( volume ) ); SWF_FMOD_CALL( channel->setFrequency( frequency ) ); if( bIs3D ) { // Update 3D sound properties FLOAT mindist = ToFMODFloat(DistanceMin); FLOAT radius = ToFMODFloat( actor->WorldSoundRadius() ); TSwSortMinMax( mindist, radius ); SWF_VERIFY_FLOAT(radius); SWF_VERIFY_FLOAT(mindist); SWF_FMOD_CALL( channel->set3DMinMaxDistance( mindist, radius ) ); } } } if( bIs3D ) { // Update 3D sound properties FMOD_VECTOR snd_pos = ToFMODVector(actor->Location); FMOD_VECTOR snd_vel = ToFMODVector(actor->Velocity); SWF_VERIFY_FMODVECTOR(snd_pos); SWF_VERIFY_FMODVECTOR(snd_vel); SWF_FMOD_CALL( channel->set3DAttributes(&snd_pos, &snd_vel) ); } } } } unguard; // // Play ambient sounds // if( Realtime ) { guard(USwFMODAudio::Update::PlayAmbient); for( INT i=0; i<Viewport->Actor->GetLevel()->Actors.Num(); ++i ) { AActor* Actor = Viewport->Actor->GetLevel()->Actors(i); if( Actor && Actor->AmbientSound && FDist(location, Actor->Location) <= Actor->WorldSoundRadius() ) { FSwSoundId ambientid = FSwSoundId(Actor,SLOT_Ambient,0); //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: Ambient TEST IN [%s]"), SWF_PLOG, *ToStr(ambientid) ); // Find this sound in currently playing ones FMOD::Channel* ambientchannel = NULL; for( FSwChannelEnumerator it(System,AmbientChannels); it; ++it ) { FMOD::Channel* channel = *it; if( IsChannelValid(channel) && GetChannelId(channel) == ambientid ) { //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: Ambient FOUND IN [%s]"), SWF_PLOG, *ToStr(GetChannelId(channel)) ); ambientchannel = channel; break; } } // If not found play ambient if( !ambientchannel ) { //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: Ambient PLAY IN [%s][%s]"), SWF_PLOG, *ToStr(ambientid), *ToStr(Actor->AmbientSound) ); PlaySound( Actor, ambientid.GetId(), Actor->AmbientSound, Actor->Location, Actor->SoundVolume/255.0f, Actor->WorldSoundRadius(), Actor->SoundPitch/64.0f ); } } } unguard; } // // Music // guard(UpdateMusic) /* REQUIREMENTS SongSection is updated at realtime by audio sys MTRAN_Fade* only fade out, not in music changes caused by transition only ttransition reset on change MTRAN_None = don't change MTRAN_Instant = instant change MTRAN_Segue = seamless? MTRAN_Fade = 1s fade MTRAN_FastFade = 1/3s fade MTRAN_SlowFade = 5s fade */ // find music channel FMOD::Channel* musicchannel = NULL; for( FSwChannelEnumerator it(System,MusicChannels); it; ++it ) { FMOD::Channel* channel = *it; if( !IsChannelValid(channel) ) continue; if( !musicchannel ) { musicchannel = channel; } else { // there can be only one music SWF_LOG( NAME_DevSound, TEXT("%s :: %s :: StopMusic %s"), SWF_PLOG, *PrintChannel(channel) ); SWF_FMOD_CALL( channel->setUserData(NULL) ); SWF_FMOD_CALL( channel->stop() ); } } if( Viewport->Actor->Transition != MTRAN_None ) { // init fading if( MusicFade < 0 ) { SWF_LOG( NAME_DevSound, TEXT("%s :: %s :: Music transition %s S:%s T:%s "), SWF_PLOG , *ToStr(Viewport->Actor->Song) , *ToStr(Viewport->Actor->SongSection) , *ToStr(Viewport->Actor->Transition)); switch( Viewport->Actor->Transition ) { case MTRAN_Instant: MusicFadeTime = -1.0f; break; // Instant case MTRAN_Segue: MusicFadeTime = -1.0f; // Instant precached if( Viewport->Actor->Song && !Viewport->Actor->Song->Handle ) RegisterMusic(Viewport->Actor->Song); break; case MTRAN_Fade: MusicFadeTime = 1.0f; break; // 1s fadeout case MTRAN_FastFade: MusicFadeTime = 0.33f; break; // 1/3s fadeout case MTRAN_SlowFade: MusicFadeTime = 5.0f; break; // 5s fadeout default: MusicFadeTime = -1.0f; break; // Unknown,instant } MusicFade = MusicFadeTime; } // deduct delta MusicFade -= DeltaTime; //SWF_LOG( NAME_DevSound, TEXT("%s << %s :: MusicFade %s %s"), SWF_PLOG, *ToStr(MusicFade), *ToStr(MusicFadeTime) ); if( MusicFade > 0 ) { // fade volume if( musicchannel && MusicFadeTime > 0 ) { SWF_FMOD_CALL( musicchannel->setVolume( MusicFade / MusicFadeTime) ); } } else { // play new MusicFade = -1; Viewport->Actor->Transition = MTRAN_None; PlayMusic( Viewport->Actor->Song, musicchannel, Viewport->Actor->SongSection, Viewport->Actor->CdTrack, static_cast<EMusicTransition>(Viewport->Actor->Transition) ); } } else { // Update section if( musicchannel ) { // update section // FIXME:: getPosition doesn't work with volume 0 (virtual?) UINT sec = 0; result = musicchannel->getPosition(&sec,FMOD_TIMEUNIT_MODORDER); if( result == FMOD_OK ) { Viewport->Actor->SongSection = sec; } // Update position if( IsChannelValid(musicchannel) ) { UINT row = 0; result = musicchannel->getPosition(&row,FMOD_TIMEUNIT_MODROW); if( result == FMOD_OK ) { // IT/MOD/XM UINT pattern = 0; result = musicchannel->getPosition(&pattern,FMOD_TIMEUNIT_MODPATTERN); if( result == FMOD_OK ) { MusicPositions(Viewport->Actor->SongSection).row = row; MusicPositions(Viewport->Actor->SongSection).pattern = pattern; } } else { // MPEG/OGG UINT ms = 0; result = musicchannel->getPosition(&ms,FMOD_TIMEUNIT_MS); if( result == FMOD_OK ) { MusicPositions(Viewport->Actor->SongSection).ms = ms; } } } } else if( Viewport->Actor->Song && VolumeMusic > 0 ) { // Restart missing/dropped song (bad channel priorities?) SWF_LOG( NAME_DevSound, TEXT("%s :: %s :: Restarting missing song %s S:%s T:%s "), SWF_PLOG , *ToStr(Viewport->Actor->Song) , *ToStr(Viewport->Actor->SongSection) , *ToStr(Viewport->Actor->Transition)); Viewport->Actor->Transition = MTRAN_Instant; } } unguard; // Update FMOD guard(UpdateFMOD); SWF_FMOD_CALL( System->update() ); unguard; //SWF_LOG( NAME_DevSound, TEXT("%s << %s :: [%s],[%s]"), SWF_PLOG, *ToStr(Region), *ToStr(Coords) ); unguard; }
void UXViewport::Tick() { guard(UXViewport::Tick); UXClient* Client = GetOuterUXClient(); if (!XWindow) return; // Keyboard. EInputKey Key; KeySym LowerCase, UpperCase; // Mouse movement management. UBOOL MouseMoved; INT BaseX = SizeX/2; INT BaseY = SizeY/2; INT DX = 0, DY = 0; XEvent Event; while( XPending(XDisplay) ) { XNextEvent(XDisplay, &Event); switch( Event.type ) { case CreateNotify: // Window has been created. ViewportStatus = X_ViewportNormal; // Make this viewport current and update its title bar. GetOuterUClient()->MakeCurrent( this ); break; case DestroyNotify: // Window has been destroyed. if( BlitFlags & BLIT_Fullscreen ) EndFullscreen(); if( ViewportStatus == X_ViewportNormal ) { // Closed normally. ViewportStatus = X_ViewportClosing; delete this; } break; case Expose: // Redraw the window. break; case KeyPress: // Reset timer. RepeatTimer = appSeconds(); LastKey = True; // Get key code. Key = (EInputKey) XKeycodeToKeysym( XDisplay, Event.xkey.keycode, 0 ); XConvertCase( Key, &LowerCase, &UpperCase ); Key = (EInputKey) UpperCase; // Check the Keysym map. if (KeysymMap[Key] != 0) Key = (EInputKey) KeysymMap[Key]; // Send key to input system. CauseInputEvent( Key, IST_Press ); // Emulate WM_CHAR. // Check for shift modifier. if (Event.xkey.state & ShiftMask) { Key = (EInputKey) UpperCase; if (ShiftMaskMap[Key] != 0) Key = (EInputKey) ShiftMaskMap[Key]; } else Key = (EInputKey) LowerCase; if (Key == XK_BackSpace) Key = IK_Backspace; if (Key == XK_Tab) Key = IK_Tab; if (Key == XK_Return) Key = IK_Enter; if (WMCharMap[Key] == 1) { KeyRepeatMap[Key] = 1; Client->Engine->Key( this, Key ); } break; case KeyRelease: // Get key code. Key = (EInputKey) XKeycodeToKeysym( XDisplay, Event.xkey.keycode, 0 ); XConvertCase( Key, &LowerCase, &UpperCase ); Key = (EInputKey) UpperCase; // Check the Keysym map. if (KeysymMap[Key] != 0) Key = (EInputKey) KeysymMap[Key]; // Send key to input system. CauseInputEvent( Key, IST_Release ); // Release all types of this key. if (Key == XK_BackSpace) Key = IK_Backspace; if (Key == XK_Tab) Key = IK_Tab; if (Key == XK_Return) Key = IK_Enter; KeyRepeatMap[Key] = 0; KeyRepeatMap[ShiftMaskMap[Key]] = 0; KeyRepeatMap[ShiftMaskMap[(EInputKey) LowerCase]] = 0; KeyRepeatMap[(EInputKey) LowerCase] = 0; break; case ButtonPress: switch (Event.xbutton.button) { case 1: Key = IK_LeftMouse; break; case 2: Key = IK_MiddleMouse; break; case 3: Key = IK_RightMouse; break; case 4: Key = IK_MouseWheelUp; break; case 5: Key = IK_MouseWheelDown; break; } // Send to input system. CauseInputEvent( Key, IST_Press ); break; case ButtonRelease: switch (Event.xbutton.button) { case 1: Key = IK_LeftMouse; break; case 2: Key = IK_MiddleMouse; break; case 3: Key = IK_RightMouse; break; case 4: Key = IK_MouseWheelUp; break; case 5: Key = IK_MouseWheelDown; break; } // Send to input system. CauseInputEvent( Key, IST_Release ); break; case MotionNotify: MouseMoved = True; if (UseDGA) { if (abs(Event.xmotion.x_root) > 1) DX += Event.xmotion.x_root * 2; else DX += Event.xmotion.x_root; if (abs(Event.xmotion.y_root) > 1) DY += Event.xmotion.y_root * 2; else DY += Event.xmotion.y_root; } else { DX += Event.xmotion.x - BaseX; DY += Event.xmotion.y - BaseY; BaseX = Event.xmotion.x; BaseY = Event.xmotion.y; } break; case ResizeRequest: // Eventually resize and setres. break; case MapNotify: if (Iconified) { guard(Uniconify); Iconified = false; // Unpause the game if applicable. Exec( TEXT("SETPAUSE 0"), *this ); // Reset the input buffer. Input->ResetInput(); // Snag the mouse again. SetMouseCapture( 1, 1, 0 ); // Make this viewport current. GetOuterUClient()->MakeCurrent( this ); // Turn off that damn auto repeat. XAutoRepeatOff( XDisplay ); // Return to fullscreen. if( BlitFlags & BLIT_Fullscreen ) TryRenderDevice( TEXT("ini:Engine.Engine.GameRenderDevice"), INDEX_NONE, INDEX_NONE, ColorBytes, 1 ); unguard; } break; case UnmapNotify: if (!Iconified) Iconify(); break; case FocusIn: break; case FocusOut: Iconify(); break; } } if (Iconified) return; // Deliver mouse behavior to the engine. if (MouseMoved) { if (!UseDGA) { XWarpPointer(XDisplay, None, XWindow, 0, 0, 0, 0, SizeX/2, SizeY/2); // Clear out the warp. XEvent MouseEvent; while( XCheckWindowEvent(XDisplay, XWindow, ButtonMotionMask | PointerMotionMask, &MouseEvent) ) { // Do Nothing. } } // Send to input subsystem. if( DX ) CauseInputEvent( IK_MouseX, IST_Axis, +DX ); if( DY ) CauseInputEvent( IK_MouseY, IST_Axis, -DY ); } // Send WM_CHAR for down keys. if ( LastKey && (appSeconds() - RepeatTimer < 0.5) ) return; LastKey = False; if ( appSeconds() - RepeatTimer < 0.1 ) return; RepeatTimer = appSeconds(); for (INT i=0; i<256; i++) if (KeyRepeatMap[i] != 0) { if (i == IK_Backspace) { CauseInputEvent( i, IST_Press ); CauseInputEvent( i, IST_Release ); } else Client->Engine->Key( this, (EInputKey) i ); } unguard; }
/** * Defragment the memory. Memory is moved around using the specified policy. * The function tries to perform non-overlapping memory transfers as much as possible. */ void FBestFitAllocator::DefragmentMemory( FDefragmentationPolicy &Policy ) { #if !FINAL_RELEASE || FINAL_RELEASE_DEBUGCONSOLE DOUBLE StartTime = appSeconds(); INT NumHolesBefore = 0; INT NumHolesAfter = 0; INT LargestHoleBefore = GetLargestAvailableAllocation(&NumHolesBefore); INT LargestHoleAfter = 0; #endif INT TotalRelocationSize = 0; INT NumRelocations = 0; // Find the first free chunk. FMemoryChunk* AvailableChunk = FirstChunk; while ( AvailableChunk && !AvailableChunk->bIsAvailable ) { AvailableChunk = AvailableChunk->NextChunk; } // Process the next used chunk. FMemoryChunk* Chunk = AvailableChunk ? AvailableChunk->NextChunk : NULL; // Relocate all subsequent used chunks to the beginning of the free chunk. while ( Chunk ) { FMemoryChunk* BestChunk = AvailableChunk; #if MINIMIZE_NUMBER_OF_OVERLAPPING_RELOCATIONS // Would this be an overlapped memory-move? if ( Chunk->Size > AvailableChunk->Size ) { // Try to move it out of the way (to the last possible free chunk)! FMemoryChunk* AnotherAvailableChunk = FirstFreeChunk; while ( AnotherAvailableChunk ) { if ( AnotherAvailableChunk->Size >= Chunk->Size && AnotherAvailableChunk->Base > BestChunk->Base ) { BestChunk = AnotherAvailableChunk; } AnotherAvailableChunk = AnotherAvailableChunk->NextFreeChunk; } } #endif UBOOL bCouldRelocate = Policy.Relocate(BestChunk->Base, Chunk->Base, Chunk->Size); if ( bCouldRelocate ) { NumRelocations++; TotalRelocationSize += Chunk->Size; // Update our book-keeping. PointerToChunkMap.Remove((PTRINT) Chunk->Base); PointerToChunkMap.Set((PTRINT) BestChunk->Base, BestChunk); BestChunk->UnlinkFree(); // Mark as being in use. if ( BestChunk->Size > Chunk->Size ) { Split(BestChunk, Chunk->Size); // Split to create a new free chunk } else if ( BestChunk->Size < Chunk->Size ) { // Overlapping relocation. We're just "sliding" memory down one step. check( Chunk->PreviousChunk == BestChunk ); INT HoleSize = BestChunk->Size; BestChunk->Size = Chunk->Size; Chunk->Base = BestChunk->Base + BestChunk->Size; Chunk->Size = HoleSize; } // Free this chunk and Coalesce. FreeChunk(Chunk); } else { // Got a non-relocatable used chunk. Try relocate as many others into the free chunk as we can and move on. FMemoryChunk* AnotherUsedChunk = Chunk->NextChunk; while ( AnotherUsedChunk && AnotherUsedChunk->bIsAvailable ) { AnotherUsedChunk = AnotherUsedChunk->NextChunk; } while ( AnotherUsedChunk && AvailableChunk && AvailableChunk->bIsAvailable ) { // Find the next used chunk now, before we free the current one. FMemoryChunk* NextUsedChunk = AnotherUsedChunk->NextChunk; while ( NextUsedChunk && NextUsedChunk->bIsAvailable ) { NextUsedChunk = NextUsedChunk->NextChunk; } if ( AnotherUsedChunk->Size <= AvailableChunk->Size ) { if ( Policy.Relocate(AvailableChunk->Base, AnotherUsedChunk->Base, AnotherUsedChunk->Size) ) { NumRelocations++; TotalRelocationSize += AnotherUsedChunk->Size; // Update our book-keeping. PointerToChunkMap.Remove((PTRINT) AnotherUsedChunk->Base); PointerToChunkMap.Set((PTRINT) AvailableChunk->Base, AvailableChunk); AvailableChunk->UnlinkFree(); // Mark as being in use. if ( AvailableChunk->Size > AnotherUsedChunk->Size ) { Split(AvailableChunk, AnotherUsedChunk->Size); // Split to create a new free chunk AvailableChunk = AvailableChunk->NextChunk; } else { check( AvailableChunk->Size == AnotherUsedChunk->Size ); } FreeChunk(AnotherUsedChunk); } } AnotherUsedChunk = NextUsedChunk; } // AvailableChunk is now filled up as much as possible. Skip it. AvailableChunk = AvailableChunk ? AvailableChunk->NextChunk : NULL; } // If we used up our current free chunk, find the next one. while ( AvailableChunk && !AvailableChunk->bIsAvailable ) { AvailableChunk = AvailableChunk->NextChunk; } // Process the next used chunk. Chunk = AvailableChunk ? AvailableChunk->NextChunk : NULL; } #if !FINAL_RELEASE DOUBLE Duration = appSeconds() - StartTime; LargestHoleAfter = GetLargestAvailableAllocation( &NumHolesAfter ); debugf( TEXT("DEFRAG: %.1f ms, Available: %.3f MB, NumRelocations: %d, Relocated: %.3f MB, NumHolesBefore: %d, NumHolesAfter: %d, LargestHoleBefore: %.3f MB, LargestHoleAfter: %.3f MB"), Duration*1000.0, AvailableMemorySize/1024.0f/1024.0f, NumRelocations, FLOAT(TotalRelocationSize)/1024.0f/1024.0f, NumHolesBefore, NumHolesAfter, FLOAT(LargestHoleBefore)/1024.f/1024.0f, FLOAT(LargestHoleAfter)/1024.0f/1024.0f ); #endif }