Browse Source

Added note that tangents are needed for normal mapping. Clean up SoundSource decoder handling to prepare for application-supplied sound stream.

Lasse Öörni 11 years ago
parent
commit
8bf5af9261
2 changed files with 38 additions and 37 deletions
  1. 2 0
      Docs/Reference.dox
  2. 36 37
      Source/Engine/Audio/SoundSource.cpp

+ 2 - 0
Docs/Reference.dox

@@ -902,6 +902,8 @@ Normal maps encode the tangent-space surface normal for normal mapping. There ar
 
 Make sure the normal map is oriented correctly: an even surface should have the color value R 0.5 G 0.5 B 1.0.
 
+Models using a normal-mapped material need to have tangent vectors in their vertex data; the easiest way to ensure this is to use the switch -t (generate tangents) when using either AssetImporter or OgreImporter to import models to Urho3D format. If there are no tangents, the light attenuation on the normal-mapped material will behave in a completely erratic fashion.
+
 Specular maps encode the specular surface color as RGB. Note that deferred rendering is only able to use monochromatic specular intensity from the G channel, while forward and light pre-pass rendering use fully colored specular. DXT1 format should suit these textures well.
 
 Textures can have an accompanying XML file which specifies load-time parameters, such as addressing, mipmapping, and number of mip levels to skip on each quality level:

+ 36 - 37
Source/Engine/Audio/SoundSource.cpp

@@ -372,59 +372,58 @@ void SoundSource::Mix(int* dest, unsigned samples, int mixRate, bool stereo, boo
     {
         if (decoder_)
         {
-            // If Decoder already exists, decode new compressed audio
+            // If decoder already exists, decode new compressed audio
             bool eof = false;
             unsigned currentPos = position_ - decodeBuffer_->GetStart();
-            if (currentPos != decodePosition_)
+            unsigned totalBytes;
+            
+            // Handle possible wraparound
+            if (currentPos >= decodePosition_)
+                totalBytes = currentPos - decodePosition_;
+            else
+                totalBytes = decodeBuffer_->GetDataSize() - decodePosition_ + currentPos;
+            
+            while (totalBytes)
             {
-                // If buffer has wrapped, decode first to the end
-                if (currentPos < decodePosition_)
+                // Calculate size of current decode work unit (may need to do in two parts if wrapping)
+                unsigned bytes = decodeBuffer_->GetDataSize() - decodePosition_;
+                if (bytes > totalBytes)
+                    bytes = totalBytes;
+                
+                unsigned outBytes = 0;
+                
+                if (!eof)
                 {
-                    unsigned bytes = decodeBuffer_->GetDataSize() - decodePosition_;
-                    unsigned outBytes = sound_->Decode(decoder_, decodeBuffer_->GetStart() + decodePosition_, bytes);
-                    // If produced less output, end of sound encountered. Fill rest with zero
+                    outBytes = sound_->Decode(decoder_, decodeBuffer_->GetStart() + decodePosition_, bytes);
+                    // If decoded less than the requested amount, has reached end. Rewind (looped) or fill rest with zero (oneshot)
                     if (outBytes < bytes)
                     {
-                        memset(decodeBuffer_->GetStart() + decodePosition_ + outBytes, 0, bytes - outBytes);
-                        eof = true;
-                    }
-                    decodePosition_ = 0;
-                }
-                if (currentPos > decodePosition_)
-                {
-                    unsigned bytes = currentPos - decodePosition_;
-                    unsigned outBytes = sound_->Decode(decoder_, decodeBuffer_->GetStart() + decodePosition_, bytes);
-                    // If produced less output, end of sound encountered. Fill rest with zero
-                    if (outBytes < bytes)
-                    {
-                        memset(decodeBuffer_->GetStart() + decodePosition_ + outBytes, 0, bytes - outBytes);
                         if (sound_->IsLooped())
+                        {
+                            sound_->RewindDecoder(decoder_);
+                            timePosition_ = 0.0f;
+                        }
+                        else
+                        {
+                            decodeBuffer_->SetLooped(false); // Stop after the current decode buffer has been played
                             eof = true;
+                        }
                     }
-
-                    // If wrote to buffer start, correct interpolation wraparound
-                    if (!decodePosition_)
-                        decodeBuffer_->FixInterpolation();
                 }
-            }
-
-            // If end of stream encountered, check whether we should rewind or stop
-            if (eof)
-            {
-                if (sound_->IsLooped())
+                else
                 {
-                    sound_->RewindDecoder(decoder_);
-                    timePosition_ = 0.0f;
+                    memset(decodeBuffer_->GetStart() + decodePosition_, 0, bytes);
+                    outBytes = bytes;
                 }
-                else
-                    decodeBuffer_->SetLooped(false); // Stop after the current decode buffer has been played
+                
+                decodePosition_ += outBytes;
+                decodePosition_ %= decodeBuffer_->GetDataSize();
+                totalBytes -= outBytes;
             }
-
-            decodePosition_ = currentPos;
         }
         else
         {
-            // Setup the decoder and decode buffer
+            // Setup the decoder and decode initial buffer
             decoder_ = sound_->AllocateDecoder();
             unsigned sampleSize = sound_->GetSampleSize();
             unsigned DecodeBufferSize = sampleSize * sound_->GetIntFrequency() * DECODE_BUFFER_LENGTH / 1000;