]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/i_linux.c
osezer patch 011
[theoddone33/hhexen.git] / base / i_linux.c
1 //**************************************************************************
2 //**
3 //** $Id$
4 //**
5 //**************************************************************************
6
7
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <sys/time.h>
11 #include "h2def.h"
12 #include "r_local.h"
13 #include "p_local.h"    // for P_AproxDistance
14 #include "sounds.h"
15 #include "i_sound.h"
16 #include "soundst.h"
17 #include "st_start.h"
18
19
20 // Macros
21
22 #define stricmp strcasecmp
23 #define DEFAULT_ARCHIVEPATH     "o:\\sound\\archive\\"
24 #define PRIORITY_MAX_ADJUST 10
25 #define DIST_ADJUST (MAX_SND_DIST/PRIORITY_MAX_ADJUST)
26
27 #define KEY_LSHIFT      0xfe
28
29 #define KEY_INS         (0x80+0x52)
30 #define KEY_DEL         (0x80+0x53)
31 #define KEY_PGUP        (0x80+0x49)
32 #define KEY_PGDN        (0x80+0x51)
33 #define KEY_HOME        (0x80+0x47)
34 #define KEY_END         (0x80+0x4f)
35
36 extern void **lumpcache;
37
38 extern void I_StartupMouse(void);
39 extern void I_ShutdownGraphics(void);
40
41 int i_Vector;
42 externdata_t *i_ExternData;
43 boolean useexterndriver;
44
45 boolean i_CDMusic;
46 int i_CDTrack;
47 int i_CDCurrentTrack;
48 int i_CDMusicLength;
49 int oldTic;
50
51 extern boolean cdaudio;
52
53 extern void I_CDMusShutdown(void);
54 extern void I_CDMusUpdate(void);
55
56 /*
57 ===============================================================================
58
59                 MUSIC & SFX API
60
61 ===============================================================================
62 */
63
64 //static channel_t channel[MAX_CHANNELS];
65
66 //static int rs; //the current registered song.
67 //int mus_song = -1;
68 //int mus_lumpnum;
69 //void *mus_sndptr;
70 //byte *soundCurve;
71
72 extern sfxinfo_t S_sfx[];
73 extern musicinfo_t S_music[];
74
75 static channel_t Channel[MAX_CHANNELS];
76 static int RegisteredSong; //the current registered song.
77 static int NextCleanup;
78 static boolean MusicPaused;
79 static int Mus_Song = -1;
80 static int Mus_LumpNum;
81 static void *Mus_SndPtr;
82 static byte *SoundCurve;
83
84 static boolean UseSndScript;
85 static char ArchivePath[128];
86
87 extern int snd_MusicDevice;
88 extern int snd_SfxDevice;
89 extern int snd_MaxVolume;
90 extern int snd_MusicVolume;
91 extern int snd_Channels;
92
93 extern int startepisode;
94 extern int startmap;
95
96 // int AmbChan;
97
98 boolean S_StopSoundID(int sound_id, int priority);
99
100 //==========================================================================
101 //
102 // S_Start
103 //
104 //==========================================================================
105
106 void S_Start(void)
107 {
108         S_StopAllSound();
109         S_StartSong(gamemap, true);
110 }
111
112 //==========================================================================
113 //
114 // S_StartSong
115 //
116 //==========================================================================
117
118 void S_StartSong(int song, boolean loop)
119 {
120         char *songLump;
121         int track;
122
123         if(i_CDMusic)
124         { // Play a CD track, instead
125                 if(i_CDTrack)
126                 { // Default to the player-chosen track
127                         track = i_CDTrack;
128                 }
129                 else
130                 {
131                         track = P_GetMapCDTrack(gamemap);
132                 }
133                 if(track == i_CDCurrentTrack && i_CDMusicLength > 0)
134                 {
135                         return;
136                 }
137                 if(!I_CDMusPlay(track))
138                 {
139 /*                      if(loop)
140                         {
141 //                              i_CDMusicLength = 35*I_CDMusTrackLength(track);
142                                 oldTic = gametic;
143                         }
144                         else
145                         {
146                                 i_CDMusicLength = -1;
147                         }
148 */
149                         i_CDCurrentTrack = track;
150                 }
151         }
152         else
153         {
154                 if(song == Mus_Song)
155                 { // don't replay an old song
156                         return;
157                 }
158                 if(RegisteredSong)
159                 {
160                         I_StopSong(RegisteredSong);
161                         I_UnRegisterSong(RegisteredSong);
162                         if(UseSndScript)
163                         {
164                                 Z_Free(Mus_SndPtr);
165                         }
166                         else
167                         {
168                                 Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
169                         } 
170                         RegisteredSong = 0;
171                 }
172                 songLump = P_GetMapSongLump(song);
173                 if(!songLump)
174                 {
175                         return;
176                 }
177                 if(UseSndScript)
178                 {
179                         char name[128];
180                         sprintf(name, "%s%s.lmp", ArchivePath, songLump);
181                         M_ReadFile(name, (byte **)&Mus_SndPtr);
182                 }
183                 else
184                 {
185                         Mus_LumpNum = W_GetNumForName(songLump);
186                         Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
187                 } 
188                 RegisteredSong = I_RegisterSong(Mus_SndPtr);
189                 I_PlaySong(RegisteredSong, loop); // 'true' denotes endless looping.
190                 Mus_Song = song;
191         }
192 }
193
194 //==========================================================================
195 //
196 // S_StartSongName
197 //
198 //==========================================================================
199
200 void S_StartSongName(char *songLump, boolean loop)
201 {
202         int cdTrack;
203
204         if(!songLump)
205         {
206                 return;
207         }
208         if(i_CDMusic)
209         {
210                 cdTrack = 0;
211
212                 if(!strcmp(songLump, "hexen"))
213                 {
214                         cdTrack = P_GetCDTitleTrack();
215                 }
216                 else if(!strcmp(songLump, "hub"))
217                 {
218                         cdTrack = P_GetCDIntermissionTrack();
219                 }
220                 else if(!strcmp(songLump, "hall"))
221                 {
222                         cdTrack = P_GetCDEnd1Track();
223                 }
224                 else if(!strcmp(songLump, "orb"))
225                 {
226                         cdTrack = P_GetCDEnd2Track();
227                 }
228                 else if(!strcmp(songLump, "chess") && !i_CDTrack)
229                 {
230                         cdTrack = P_GetCDEnd3Track();
231                 }
232 /*      Uncomment this, if Kevin writes a specific song for startup
233                 else if(!strcmp(songLump, "start"))
234                 {
235                         cdTrack = P_GetCDStartTrack();
236                 }
237 */
238                 if(!cdTrack || (cdTrack == i_CDCurrentTrack && i_CDMusicLength > 0))
239                 {
240                         return;
241                 }
242                 if(!I_CDMusPlay(cdTrack))
243                 {
244 /*                      if(loop)
245                         {
246                                 i_CDMusicLength = 35*I_CDMusTrackLength(cdTrack);
247                                 oldTic = gametic;
248                         }
249                         else
250                         {
251                                 i_CDMusicLength = -1;
252                         }
253 */
254                         i_CDCurrentTrack = cdTrack;
255                         i_CDTrack = false;
256                 }
257         }
258         else
259         {
260                 if(RegisteredSong)
261                 {
262                         I_StopSong(RegisteredSong);
263                         I_UnRegisterSong(RegisteredSong);
264                         if(UseSndScript)
265                         {
266                                 Z_Free(Mus_SndPtr);
267                         }
268                         else
269                         {
270                                 Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
271                         } 
272                         RegisteredSong = 0;
273                 }
274                 if(UseSndScript)
275                 {
276                         char name[128];
277                         sprintf(name, "%s%s.lmp", ArchivePath, songLump);
278                         M_ReadFile(name, (byte **)&Mus_SndPtr);
279                 }
280                 else
281                 {
282                         Mus_LumpNum = W_GetNumForName(songLump);
283                         Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
284                 } 
285                 RegisteredSong = I_RegisterSong(Mus_SndPtr);
286                 I_PlaySong(RegisteredSong, loop); // 'true' denotes endless looping.
287                 Mus_Song = -1;
288         }
289 }
290
291 //==========================================================================
292 //
293 // S_GetSoundID
294 //
295 //==========================================================================
296
297 int S_GetSoundID(char *name)
298 {
299         int i;
300
301         for(i = 0; i < NUMSFX; i++)
302         {
303                 if(!strcmp(S_sfx[i].tagName, name))
304                 {
305                         return i;
306                 }
307         }
308         return 0;
309 }
310
311 //==========================================================================
312 //
313 // S_StartSound
314 //
315 //==========================================================================
316
317 void S_StartSound(mobj_t *origin, int sound_id)
318 {
319         S_StartSoundAtVolume(origin, sound_id, 127);
320 }
321
322 //==========================================================================
323 //
324 // S_StartSoundAtVolume
325 //
326 //==========================================================================
327 #if 0
328 void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
329 {
330         int dist, vol;
331         int i = 0;       /* jim - initialise to avoid gcc warning */
332         int priority;
333         int sep;
334         int angle;
335         int absx;
336         int absy;
337
338         static int sndcount = 0;
339         int chan;
340
341     //printf( "S_StartSoundAtVolume: %d\n", sound_id );
342
343         if(sound_id == 0 || snd_MaxVolume == 0)
344                 return;
345         if(origin == NULL)
346         {
347                 origin = players[displayplayer].mo;
348         }
349         if(volume == 0)
350         {
351                 return;
352         }
353
354     // How does the DOS version work without this check?
355     // players[0].mo does not get set until P_SpawnPlayer. - KR
356
357     if( origin )
358     {
359         // calculate the distance before other stuff so that we can throw out
360         // sounds that are beyond the hearing range.
361         absx = abs(origin->x-players[displayplayer].mo->x);
362         absy = abs(origin->y-players[displayplayer].mo->y);
363         dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
364         dist >>= FRACBITS;
365         if(dist >= MAX_SND_DIST)
366         {
367           return; // sound is beyond the hearing range...
368         }
369         if(dist < 0)
370         {
371             dist = 0;
372         }
373         priority = S_sfx[sound_id].priority;
374         priority *= (PRIORITY_MAX_ADJUST-(dist/DIST_ADJUST));
375         if(!S_StopSoundID(sound_id, priority))
376         {
377             return; // other sounds have greater priority
378         }
379         for(i = 0; i<snd_Channels; i++)
380         {
381             if(origin->player)
382             {
383                 i = snd_Channels;
384                 break; // let the player have more than one sound.
385             }
386             if(origin == Channel[i].mo)
387             { // only allow other mobjs one sound
388                 S_StopSound(Channel[i].mo);
389                 break;
390             }
391         }
392         }
393     else
394     {
395         dist = 0;
396         priority = S_sfx[sound_id].priority;
397         if( ! S_StopSoundID( sound_id, priority ) )
398         {
399             return; // other sounds have greater priority
400         }
401     }
402
403         if(i >= snd_Channels)
404         {
405                 for(i = 0; i < snd_Channels; i++)
406                 {
407                         if(Channel[i].mo == NULL)
408                         {
409                                 break;
410                         }
411                 }
412                 if(i >= snd_Channels)
413                 {
414                         // look for a lower priority sound to replace.
415                         sndcount++;
416                         if(sndcount >= snd_Channels)
417                         {
418                                 sndcount = 0;
419                         }
420                         for(chan = 0; chan < snd_Channels; chan++)
421                         {
422                                 i = (sndcount+chan)%snd_Channels;
423                                 if(priority >= Channel[i].priority)
424                                 {
425                                         chan = -1; //denote that sound should be replaced.
426                                         break;
427                                 }
428                         }
429                         if(chan != -1)
430                         {
431                                 return; //no free channels.
432                         }
433                         else //replace the lower priority sound.
434                         {
435                                 if(Channel[i].handle)
436                                 {
437                                         if(I_SoundIsPlaying(Channel[i].handle))
438                                         {
439                                                 I_StopSound(Channel[i].handle);
440                                         }
441                                         if(S_sfx[Channel[i].sound_id].usefulness > 0)
442                                         {
443                                                 S_sfx[Channel[i].sound_id].usefulness--;
444                                         }
445                                 }
446                         }
447                 }
448         }
449         if(S_sfx[sound_id].lumpnum == 0)
450         {
451                 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
452         }
453         if(S_sfx[sound_id].snd_ptr == NULL)
454         {
455                 if(UseSndScript)
456                 {
457                         char name[128];
458                         sprintf(name, "%s%s.lmp", ArchivePath, S_sfx[sound_id].lumpname);
459                         M_ReadFile(name, (byte **)&S_sfx[sound_id].snd_ptr);
460                 }
461                 else
462                 {
463                         S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
464                                 PU_SOUND);
465                 } 
466         }
467
468         vol = (SoundCurve[dist]*(snd_MaxVolume*8)*volume)>>14;
469         if(origin == players[displayplayer].mo)
470         {
471                 sep = 128;
472 //              vol = (volume*(snd_MaxVolume+1)*8)>>7;
473         }
474         else
475         {
476 #if 1
477         // KR - Channel[i].mo = 0 here!
478         if( Channel[i].mo == NULL )
479         {
480             sep = 128;
481             //printf( " Channel[i].mo not set\n" );
482         }
483         else
484         {
485 #endif
486                 angle = R_PointToAngle2(players[displayplayer].mo->x,
487                         players[displayplayer].mo->y, Channel[i].mo->x, Channel[i].mo->y);
488                 angle = (angle-viewangle)>>24;
489                 sep = angle*2-128;
490                 if(sep < 64)
491                         sep = -sep;
492                 if(sep > 192)
493                         sep = 512-sep;
494 //              vol = SoundCurve[dist];
495 #if 1
496         }
497 #endif
498         }
499
500         if(S_sfx[sound_id].changePitch)
501         {
502                 Channel[i].pitch = (byte)(127+(M_Random()&7)-(M_Random()&7));
503         }
504         else
505         {
506                 Channel[i].pitch = 127;
507         }
508         Channel[i].handle = I_StartSound( sound_id, S_sfx[sound_id].snd_ptr, vol,
509                                           sep, Channel[i].pitch, 0 );
510         Channel[i].mo = origin;
511         Channel[i].sound_id = sound_id;
512         Channel[i].priority = priority;
513         Channel[i].volume = volume;
514         if(S_sfx[sound_id].usefulness < 0)
515         {
516                 S_sfx[sound_id].usefulness = 1;
517         }
518         else
519         {
520                 S_sfx[sound_id].usefulness++;
521         }
522 }
523 #endif
524 void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
525 {
526         int dist, vol;
527         int i;
528         int priority;
529         int sep;
530         int angle;
531         int absx;
532         int absy;
533
534         static int sndcount = 0;
535         int chan;
536
537         if(sound_id == 0 || snd_MaxVolume == 0)
538                 return;
539 #if 0
540         if(origin == NULL)
541         {
542 // origin = players[displayplayer].mo; bug -- can be uninitialized
543         }
544 #endif
545         if(volume == 0)
546         {
547                 return;
548         }
549
550         // calculate the distance before other stuff so that we can throw out
551         // sounds that are beyond the hearing range.
552         if (origin)
553         {
554         absx = abs(origin->x-players[displayplayer].mo->x);
555         absy = abs(origin->y-players[displayplayer].mo->y);
556         }
557         else
558           absx = absy = 0;
559         dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
560         dist >>= FRACBITS;
561         if(dist >= MAX_SND_DIST)
562         {
563           return; // sound is beyond the hearing range...
564         }
565         if(dist < 0)
566         {
567                 dist = 0;
568         }
569         priority = S_sfx[sound_id].priority;
570         priority *= (PRIORITY_MAX_ADJUST-(dist/DIST_ADJUST));
571         if(!S_StopSoundID(sound_id, priority))
572         {
573                 return; // other sounds have greater priority
574         }
575         for(i=0; i<snd_Channels; i++)
576         {
577                 if(!origin || origin->player)
578                 {
579                         i = snd_Channels;
580                         break; // let the player have more than one sound.
581                 }
582                 if(origin == Channel[i].mo)
583                 { // only allow other mobjs one sound
584                         S_StopSound(Channel[i].mo);
585                         break;
586                 }
587         }
588         if(i >= snd_Channels)
589         {
590                 for(i = 0; i < snd_Channels; i++)
591                 {
592                         if(Channel[i].mo == NULL)
593                         {
594                                 break;
595                         }
596                 }
597                 if(i >= snd_Channels)
598                 {
599                         // look for a lower priority sound to replace.
600                         sndcount++;
601                         if(sndcount >= snd_Channels)
602                         {
603                                 sndcount = 0;
604                         }
605                         for(chan = 0; chan < snd_Channels; chan++)
606                         {
607                                 i = (sndcount+chan)%snd_Channels;
608                                 if(priority >= Channel[i].priority)
609                                 {
610                                         chan = -1; //denote that sound should be replaced.
611                                         break;
612                                 }
613                         }
614                         if(chan != -1)
615                         {
616                                 return; //no free channels.
617                         }
618                         else //replace the lower priority sound.
619                         {
620                                 if(Channel[i].handle)
621                                 {
622                                         if(I_SoundIsPlaying(Channel[i].handle))
623                                         {
624                                                 I_StopSound(Channel[i].handle);
625                                         }
626                                         if(S_sfx[Channel[i].sound_id].usefulness > 0)
627                                         {
628                                                 S_sfx[Channel[i].sound_id].usefulness--;
629                                         }
630                                 }
631                         }
632                 }
633         }
634         if(S_sfx[sound_id].lumpnum == 0)
635         {
636                 S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
637         }
638         if(S_sfx[sound_id].snd_ptr == NULL)
639         {
640                 if(UseSndScript)
641                 {
642                         char name[128];
643                         sprintf(name, "%s%s.lmp", ArchivePath, S_sfx[sound_id].lumpname);
644                         M_ReadFile(name, (byte **)&S_sfx[sound_id].snd_ptr);
645                 }
646                 else
647                 {
648                         S_sfx[sound_id].snd_ptr = W_CacheLumpNum(S_sfx[sound_id].lumpnum,
649                                 PU_SOUND);
650                 }
651                 #ifdef __WATCOMC__
652 //                _dpmi_lockregion(S_sfx[sound_id].snd_ptr,
653 //                        lumpinfo[S_sfx[sound_id].lumpnum].size);
654                 #endif
655         }
656
657         vol = (SoundCurve[dist]*(snd_MaxVolume*8)*volume)>>14;
658         if (!origin || origin == players[displayplayer].mo)
659         {
660                 sep = 128;
661 //              vol = (volume*(snd_MaxVolume+1)*8)>>7;
662         }
663         else
664         {
665                 angle = R_PointToAngle2(players[displayplayer].mo->x,
666 // bug!                        players[displayplayer].mo->y, Channel[i].mo->x, Channel[i].mo->y);
667                         players[displayplayer].mo->y, origin->x, origin->y);
668                 angle = (angle-viewangle)>>24;
669                 sep = angle*2-128;
670                 if(sep < 64)
671                         sep = -sep;
672                 if(sep > 192)
673                         sep = 512-sep;
674 //              vol = SoundCurve[dist];
675         }
676
677         if(S_sfx[sound_id].changePitch)
678         {
679                 Channel[i].pitch = (byte)(127+(M_Random()&7)-(M_Random()&7));
680         }
681         else
682         {
683                 Channel[i].pitch = 127;
684         }
685         Channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, vol,
686                 sep, Channel[i].pitch, 0);
687         Channel[i].mo = origin;
688         Channel[i].sound_id = sound_id;
689         Channel[i].priority = priority;
690         Channel[i].volume = volume;
691         if(S_sfx[sound_id].usefulness < 0)
692         {
693                 S_sfx[sound_id].usefulness = 1;
694         }
695         else
696         {
697                 S_sfx[sound_id].usefulness++;
698         }
699 }
700 //==========================================================================
701 //
702 // S_StopSoundID
703 //
704 //==========================================================================
705
706 boolean S_StopSoundID(int sound_id, int priority)
707 {
708         int i;
709         int lp; //least priority
710         int found;
711
712         if(S_sfx[sound_id].numchannels == -1)
713         {
714                 return(true);
715         }
716         lp = -1; //denote the argument sound_id
717         found = 0;
718         for(i=0; i<snd_Channels; i++)
719         {
720                 if(Channel[i].sound_id == sound_id && Channel[i].mo)
721                 {
722                         found++; //found one.  Now, should we replace it??
723                         if(priority >= Channel[i].priority)
724                         { // if we're gonna kill one, then this'll be it
725                                 lp = i;
726                                 priority = Channel[i].priority;
727                         }
728                 }
729         }
730         if(found < S_sfx[sound_id].numchannels)
731         {
732                 return(true);
733         }
734         else if(lp == -1)
735         {
736                 return(false); // don't replace any sounds
737         }
738         if(Channel[lp].handle)
739         {
740                 if(I_SoundIsPlaying(Channel[lp].handle))
741                 {
742                         I_StopSound(Channel[lp].handle);
743                 }
744                 if(S_sfx[Channel[lp].sound_id].usefulness > 0)
745                 {
746                         S_sfx[Channel[lp].sound_id].usefulness--;
747                 }
748                 Channel[lp].mo = NULL;
749         }
750         return(true);
751 }
752
753 //==========================================================================
754 //
755 // S_StopSound
756 //
757 //==========================================================================
758
759 void S_StopSound(mobj_t *origin)
760 {
761         int i;
762
763         for(i=0;i<snd_Channels;i++)
764         {
765                 if(Channel[i].mo == origin)
766                 {
767                         I_StopSound(Channel[i].handle);
768                         if(S_sfx[Channel[i].sound_id].usefulness > 0)
769                         {
770                                 S_sfx[Channel[i].sound_id].usefulness--;
771                         }
772                         Channel[i].handle = 0;
773                         Channel[i].mo = NULL;
774                 }
775         }
776 }
777
778 //==========================================================================
779 //
780 // S_StopAllSound
781 //
782 //==========================================================================
783
784 void S_StopAllSound(void)
785 {
786         int i;
787
788         //stop all sounds
789         for(i=0; i < snd_Channels; i++)
790         {
791                 if(Channel[i].handle)
792                 {
793                         S_StopSound(Channel[i].mo);
794                 }
795         }
796         memset(Channel, 0, 8*sizeof(channel_t));
797 }
798
799 //==========================================================================
800 //
801 // S_SoundLink
802 //
803 //==========================================================================
804
805 void S_SoundLink(mobj_t *oldactor, mobj_t *newactor)
806 {
807         int i;
808
809         for(i=0;i<snd_Channels;i++)
810         {
811                 if(Channel[i].mo == oldactor)
812                         Channel[i].mo = newactor;
813         }
814 }
815
816 //==========================================================================
817 //
818 // S_PauseSound
819 //
820 //==========================================================================
821
822 void S_PauseSound(void)
823 {
824         if(i_CDMusic)
825         {
826                 I_CDMusStop();
827         }
828         else
829         {
830                 I_PauseSong(RegisteredSong);
831         }
832 }
833
834 //==========================================================================
835 //
836 // S_ResumeSound
837 //
838 //==========================================================================
839
840 void S_ResumeSound(void)
841 {
842         if(i_CDMusic)
843         {
844                 I_CDMusResume();
845         }
846         else
847         {
848                 I_ResumeSong(RegisteredSong);
849         }
850 }
851
852 //==========================================================================
853 //
854 // S_UpdateSounds
855 //
856 //==========================================================================
857
858 void S_UpdateSounds(mobj_t *listener)
859 {
860         int i, dist, vol;
861         int angle;
862         int sep;
863         int priority;
864         int absx;
865         int absy;
866
867         if(i_CDMusic)
868         {
869                 I_CDMusUpdate();
870         }
871         if(snd_MaxVolume == 0)
872         {
873                 return;
874         }
875
876         // Update any Sequences
877         SN_UpdateActiveSequences();
878
879         if(NextCleanup < gametic)
880         {
881                 if(UseSndScript)
882                 {
883                         for(i = 0; i < NUMSFX; i++)
884                         {
885                                 if(S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
886                                 {
887                                         S_sfx[i].usefulness = -1;
888                                 }
889                         }
890                 }
891                 else
892                 {
893                         for(i = 0; i < NUMSFX; i++)
894                         {
895                                 if(S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
896                                 {
897                                         if(lumpcache[S_sfx[i].lumpnum])
898                                         {
899                                                 if(((memblock_t *)((byte*)
900                                                         (lumpcache[S_sfx[i].lumpnum])-
901                                                         sizeof(memblock_t)))->id == 0x1d4a11)
902                                                 { // taken directly from the Z_ChangeTag macro
903                                                         Z_ChangeTag2(lumpcache[S_sfx[i].lumpnum],
904                                                                 PU_CACHE); 
905                                                 }
906                                         }
907                                         S_sfx[i].usefulness = -1;
908                                         S_sfx[i].snd_ptr = NULL;
909                                 }
910                         }
911                 }
912                 NextCleanup = gametic+35*30; // every 30 seconds
913         }
914         for(i=0;i<snd_Channels;i++)
915         {
916                 if(!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1)
917                 {
918                         continue;
919                 }
920                 if(!I_SoundIsPlaying(Channel[i].handle))
921                 {
922                         if(S_sfx[Channel[i].sound_id].usefulness > 0)
923                         {
924                                 S_sfx[Channel[i].sound_id].usefulness--;
925                         }
926                         Channel[i].handle = 0;
927                         Channel[i].mo = NULL;
928                         Channel[i].sound_id = 0;
929                 }
930                 if(Channel[i].mo == NULL || Channel[i].sound_id == 0
931                         || Channel[i].mo == listener)
932                 {
933                         continue;
934                 }
935                 else
936                 {
937                         absx = abs(Channel[i].mo->x-listener->x);
938                         absy = abs(Channel[i].mo->y-listener->y);
939                         dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
940                         dist >>= FRACBITS;
941
942                         if(dist >= MAX_SND_DIST)
943                         {
944                                 S_StopSound(Channel[i].mo);
945                                 continue;
946                         }
947                         if(dist < 0)
948                         {
949                                 dist = 0;
950                         }
951                         //vol = SoundCurve[dist];
952                         vol = (SoundCurve[dist]*(snd_MaxVolume*8)*Channel[i].volume)>>14;
953                         if(Channel[i].mo == listener)
954                         {
955                                 sep = 128;
956                         }
957                         else
958                         {
959                                 angle = R_PointToAngle2(listener->x, listener->y,
960                                                                 Channel[i].mo->x, Channel[i].mo->y);
961                                 angle = (angle-viewangle)>>24;
962                                 sep = angle*2-128;
963                                 if(sep < 64)
964                                         sep = -sep;
965                                 if(sep > 192)
966                                         sep = 512-sep;
967                         }
968                         I_UpdateSoundParams(Channel[i].handle, vol, sep,
969                                 Channel[i].pitch);
970                         priority = S_sfx[Channel[i].sound_id].priority;
971                         priority *= PRIORITY_MAX_ADJUST-(dist/DIST_ADJUST);
972                         Channel[i].priority = priority;
973                 }
974         }
975 }
976
977 //==========================================================================
978 //
979 // S_Init
980 //
981 //==========================================================================
982
983 void S_Init(void)
984 {
985         SoundCurve = W_CacheLumpName("SNDCURVE", PU_STATIC);
986 //      SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
987         I_StartupSound();
988         if(snd_Channels > 8)
989         {
990                 snd_Channels = 8;
991         }
992         I_SetChannels(snd_Channels);
993         I_SetMusicVolume(snd_MusicVolume);
994
995         // Attempt to setup CD music
996         if(cdaudio == true)
997         {
998                 ST_Message("  Attempting to initialize CD Music: ");
999                 if(!cdrom)
1000                 {
1001                         i_CDMusic = (I_CDMusInit() != -1);
1002                 }
1003                 else
1004                 { // The user is trying to use the cdrom for both game and music
1005                         i_CDMusic = false;
1006                 }
1007                 if(i_CDMusic)
1008                 {
1009                         ST_Message("initialized.\n");
1010                 }
1011                 else
1012                 {
1013                         ST_Message("failed.\n");
1014                 }
1015         }
1016 }
1017
1018 //==========================================================================
1019 //
1020 // S_GetChannelInfo
1021 //
1022 //==========================================================================
1023
1024 void S_GetChannelInfo(SoundInfo_t *s)
1025 {
1026         int i;
1027         ChanInfo_t *c;
1028
1029         s->channelCount = snd_Channels;
1030         s->musicVolume = snd_MusicVolume;
1031         s->soundVolume = snd_MaxVolume;
1032         for(i = 0; i < snd_Channels; i++)
1033         {
1034                 c = &s->chan[i];
1035                 c->id = Channel[i].sound_id;
1036                 c->priority = Channel[i].priority;
1037                 c->name = S_sfx[c->id].lumpname;
1038                 c->mo = Channel[i].mo;
1039                 c->distance = P_AproxDistance(c->mo->x-viewx, c->mo->y-viewy)
1040                         >>FRACBITS;
1041         }
1042 }
1043
1044 //==========================================================================
1045 //
1046 // S_GetSoundPlayingInfo
1047 //
1048 //==========================================================================
1049
1050 boolean S_GetSoundPlayingInfo(mobj_t *mobj, int sound_id)
1051 {
1052         int i;
1053
1054         for(i = 0; i < snd_Channels; i++)
1055         {
1056                 if(Channel[i].sound_id == sound_id && Channel[i].mo == mobj)
1057                 {
1058                         if(I_SoundIsPlaying(Channel[i].handle))
1059                         {
1060                                 return true;
1061                         }
1062                 }
1063         }
1064         return false;
1065 }
1066
1067 //==========================================================================
1068 //
1069 // S_SetMusicVolume
1070 //
1071 //==========================================================================
1072
1073 void S_SetMusicVolume(void)
1074 {
1075         if(i_CDMusic)
1076         {
1077                 I_CDMusSetVolume(snd_MusicVolume*16); // 0-255
1078         }
1079         else
1080         {
1081                 I_SetMusicVolume(snd_MusicVolume);
1082         }
1083         if(snd_MusicVolume == 0)
1084         {
1085                 if(!i_CDMusic)
1086                 {
1087                         I_PauseSong(RegisteredSong);
1088                 }
1089                 MusicPaused = true;
1090         }
1091         else if(MusicPaused)
1092         {
1093                 if(!i_CDMusic)
1094                 {
1095                         I_ResumeSong(RegisteredSong);
1096                 }
1097                 MusicPaused = false;
1098         }
1099 }
1100
1101 //==========================================================================
1102 //
1103 // S_ShutDown
1104 //
1105 //==========================================================================
1106
1107 void S_ShutDown(void)
1108 {
1109         extern int tsm_ID;
1110         if(tsm_ID != -1)
1111         {
1112                 I_StopSong(RegisteredSong);
1113                 I_UnRegisterSong(RegisteredSong);
1114                 I_ShutdownSound();
1115         }
1116         if(i_CDMusic)
1117         {
1118                 I_CDMusStop();
1119         }
1120         I_CDMusShutdown();
1121 }
1122
1123 //==========================================================================
1124 //
1125 // S_InitScript
1126 //
1127 //==========================================================================
1128
1129 void S_InitScript(void)
1130 {
1131         int p;
1132         int i;
1133
1134         strcpy(ArchivePath, DEFAULT_ARCHIVEPATH);
1135         if(!(p = M_CheckParm("-devsnd")))
1136         {
1137                 UseSndScript = false;
1138                 SC_OpenLump("sndinfo");
1139         }
1140         else
1141         {
1142                 UseSndScript = true;
1143                 SC_OpenFile(myargv[p+1]);
1144         }
1145         while(SC_GetString())
1146         {
1147                 if(*sc_String == '$')
1148                 {
1149                         if(!stricmp(sc_String, "$ARCHIVEPATH"))
1150                         {
1151                                 SC_MustGetString();
1152                                 strcpy(ArchivePath, sc_String);
1153                         }
1154                         else if(!stricmp(sc_String, "$MAP"))
1155                         {
1156                                 SC_MustGetNumber();
1157                                 SC_MustGetString();
1158                                 if(sc_Number)
1159                                 {
1160                                         P_PutMapSongLump(sc_Number, sc_String);
1161                                 }
1162                         }
1163                         continue;
1164                 }
1165                 else
1166                 {
1167                         for(i = 0; i < NUMSFX; i++)
1168                         {
1169                                 if(!strcmp(S_sfx[i].tagName, sc_String))
1170                                 {
1171                                         SC_MustGetString();
1172                                         if(*sc_String != '?')
1173                                         {
1174                                                 strcpy(S_sfx[i].lumpname, sc_String);
1175                                         }
1176                                         else
1177                                         {
1178                                                 strcpy(S_sfx[i].lumpname, "default");
1179                                         }
1180                                         break;
1181                                 }
1182                         }
1183                         if(i == NUMSFX)
1184                         {
1185                                 SC_MustGetString();
1186                         }
1187                 }
1188         }
1189         SC_Close();
1190
1191         for(i = 0; i < NUMSFX; i++)
1192         {
1193                 if(!strcmp(S_sfx[i].lumpname, ""))
1194                 {
1195                         strcpy(S_sfx[i].lumpname, "default");
1196                 }
1197         }
1198 }
1199
1200
1201 //==================================================
1202
1203
1204 int ticcount;
1205
1206 boolean novideo; // if true, stay in text mode for debugging
1207
1208
1209 //==========================================================================
1210
1211
1212 static long _startSec;
1213
1214 void I_StartupTimer(void)
1215 {
1216    struct timeval tv;
1217     gettimeofday( &tv, 0 ); 
1218     _startSec = tv.tv_sec;
1219 }
1220
1221 //--------------------------------------------------------------------------
1222 //
1223 // FUNC I_GetTime
1224 //
1225 // Returns time in 1/35th second tics.
1226 //
1227 //--------------------------------------------------------------------------
1228
1229 int I_GetTime (void)
1230 {
1231     struct timeval tv;
1232     gettimeofday( &tv, 0 ); 
1233
1234     //printf( "GT: %lx %lx\n", tv.tv_sec, tv.tv_usec );
1235
1236 //  ticcount = ((tv.tv_sec * 1000000) + tv.tv_usec) / 28571;
1237     ticcount = ((tv.tv_sec - _startSec) * 35) + (tv.tv_usec / 28571);
1238         return( ticcount );
1239 }
1240
1241
1242 /*
1243 ============================================================================
1244
1245                                         JOYSTICK
1246
1247 ============================================================================
1248 */
1249
1250 //==================================================
1251 //
1252 // joystick vars
1253 //
1254 //==================================================
1255
1256 extern int usejoystick;
1257 boolean joystickpresent;
1258 unsigned joystickx, joysticky;
1259
1260 // returns false if not connected
1261 boolean I_ReadJoystick (void)
1262 {
1263     return false;
1264 }
1265
1266
1267 int     joyxl, joyxh, joyyl, joyyh;
1268
1269 boolean WaitJoyButton (void)
1270 {
1271 #if 0
1272         int             oldbuttons, buttons;
1273
1274         oldbuttons = 0;
1275         do
1276         {
1277                 I_WaitVBL (1);
1278                 buttons =  ((inp(0x201) >> 4)&1)^1;
1279                 if (buttons != oldbuttons)
1280                 {
1281                         oldbuttons = buttons;
1282                         continue;
1283                 }
1284
1285                 if ( (lastpress& 0x7f) == 1 )
1286                 {
1287                         joystickpresent = false;
1288                         return false;
1289                 }
1290         } while ( !buttons);
1291
1292         do
1293         {
1294                 I_WaitVBL (1);
1295                 buttons =  ((inp(0x201) >> 4)&1)^1;
1296                 if (buttons != oldbuttons)
1297                 {
1298                         oldbuttons = buttons;
1299                         continue;
1300                 }
1301
1302                 if ( (lastpress& 0x7f) == 1 )
1303                 {
1304                         joystickpresent = false;
1305                         return false;
1306                 }
1307         } while ( buttons);
1308
1309 #endif
1310         return true;
1311 }
1312
1313
1314
1315 /*
1316 ===============
1317 =
1318 = I_StartupJoystick
1319 =
1320 ===============
1321 */
1322
1323 int             basejoyx, basejoyy;
1324
1325 void I_StartupJoystick (void)
1326 {
1327         int     center_x, center_y;
1328
1329         joystickpresent = 0;
1330         if ( M_CheckParm ("-nojoy") || !usejoystick )
1331                 return;
1332
1333         if (!I_ReadJoystick ())
1334         {
1335                 joystickpresent = false;
1336                 ST_Message("joystick not found\n ");
1337                 return;
1338         }
1339         ST_Message("joystick found\n");
1340         joystickpresent = true;
1341
1342         ST_RealMessage("CENTER the joystick and press button 1:");
1343         if (!WaitJoyButton ())
1344                 return;
1345         I_ReadJoystick ();
1346         center_x = joystickx;
1347         center_y = joysticky;
1348
1349         ST_RealMessage("\nPush the joystick to the UPPER LEFT corner and press button 1:");
1350         if (!WaitJoyButton ())
1351                 return;
1352         I_ReadJoystick ();
1353         joyxl = (center_x + joystickx)/2;
1354         joyyl = (center_x + joysticky)/2;
1355
1356         ST_RealMessage("\nPush the joystick to the LOWER RIGHT corner and press button 1:");
1357         if (!WaitJoyButton ())
1358                 return;
1359         I_ReadJoystick ();
1360         joyxh = (center_x + joystickx)/2;
1361         joyyh = (center_y + joysticky)/2;
1362         ST_RealMessage("\n");
1363 }
1364
1365 /*
1366 ===============
1367 =
1368 = I_JoystickEvents
1369 =
1370 ===============
1371 */
1372
1373 void I_JoystickEvents (void)
1374 {
1375         event_t ev;
1376
1377 //
1378 // joystick events
1379 //
1380         if (!joystickpresent)
1381                 return;
1382
1383         I_ReadJoystick();
1384         ev.type = ev_joystick;
1385         ev.data1 =  0;  //((inp(0x201) >> 4)&15)^15;
1386
1387         if (joystickx < joyxl)
1388                 ev.data2 = -1;
1389         else if (joystickx > joyxh)
1390                 ev.data2 = 1;
1391         else
1392                 ev.data2 = 0;
1393         if (joysticky < joyyl)
1394                 ev.data3 = -1;
1395         else if (joysticky > joyyh)
1396                 ev.data3 = 1;
1397         else
1398                 ev.data3 = 0;
1399
1400         H2_PostEvent (&ev);
1401 }
1402
1403
1404 /*
1405    ===============
1406    =
1407    = I_StartFrame
1408    =
1409    ===============
1410    */
1411  
1412 void I_StartFrame (void)
1413 {
1414     I_JoystickEvents();
1415 }
1416
1417
1418 /*
1419 ============================================================================
1420
1421                                         DPMI STUFF
1422
1423 ============================================================================
1424 */
1425
1426 void I_DivException (void);
1427 int I_SetDivException (void);
1428
1429
1430
1431 /*
1432 ============================================================================
1433
1434                                         TIMER INTERRUPT
1435
1436 ============================================================================
1437 */
1438
1439
1440 /*
1441 ===============
1442 =
1443 = I_Init
1444 =
1445 = hook interrupts and set graphics mode
1446 =
1447 ===============
1448 */
1449
1450 void I_Init (void)
1451 {
1452         void I_StartupTimer(void);
1453
1454         novideo = M_CheckParm("novideo");
1455         //ST_Message("  I_StartupMouse ");
1456         I_StartupMouse();
1457 //      tprintf("I_StartupJoystick ",1);
1458 //      I_StartupJoystick();
1459         ST_Message("  S_Init... ");
1460         S_Init();
1461         S_Start();
1462
1463     I_StartupTimer();
1464 }
1465
1466
1467 /*
1468 ===============
1469 =
1470 = I_Shutdown
1471 =
1472 = return to default system state
1473 =
1474 ===============
1475 */
1476
1477 void I_Shutdown (void)
1478 {
1479         I_ShutdownGraphics ();
1480         S_ShutDown ();
1481 }
1482
1483
1484 /*
1485 ================
1486 =
1487 = I_Error
1488 =
1489 ================
1490 */
1491
1492 void I_Error (char *error, ...)
1493 {
1494         va_list argptr;
1495
1496         D_QuitNetGame ();
1497         I_Shutdown ();
1498         va_start (argptr,error);
1499         vprintf (error, argptr);
1500         va_end (argptr);
1501         printf ("\n");
1502         exit (1);
1503 }
1504
1505 //--------------------------------------------------------------------------
1506 //
1507 // I_Quit
1508 //
1509 // Shuts down net game, saves defaults, prints the exit text message,
1510 // goes to text mode, and exits.
1511 //
1512 //--------------------------------------------------------------------------
1513
1514 void I_Quit(void)
1515 {
1516         D_QuitNetGame();
1517         M_SaveDefaults();
1518         I_Shutdown();
1519
1520 //      scr = (byte *)W_CacheLumpName("ENDTEXT", PU_CACHE);
1521 /*
1522         memcpy((void *)0xb8000, scr, 80*25*2);
1523         regs.w.ax = 0x0200;
1524         regs.h.bh = 0;
1525         regs.h.dl = 0;
1526         regs.h.dh = 23;
1527         int386(0x10, (const union REGS *)&regs, &regs); // Set text pos
1528         _settextposition(24, 1);
1529 */
1530         printf("\nHexen: Beyond Heretic\n");
1531         exit(0);
1532 }
1533
1534 /*
1535 ===============
1536 =
1537 = I_ZoneBase
1538 =
1539 ===============
1540 */
1541
1542 byte *I_ZoneBase (int *size)
1543 {
1544         byte *ptr;
1545     int heap = 0x800000;
1546
1547     ptr = malloc ( heap );
1548
1549         ST_Message ("  0x%x allocated for zone, ", heap);
1550         ST_Message ("ZoneBase: 0x%X\n", (int)ptr);
1551
1552         if ( ! ptr )
1553                 I_Error ("  Insufficient DPMI memory!");
1554
1555         *size = heap;
1556         return ptr;
1557 }
1558
1559 /*
1560 =============
1561 =
1562 = I_AllocLow
1563 =
1564 =============
1565 */
1566
1567 byte *I_AllocLow (int length)
1568 {
1569         return malloc( length );
1570 }
1571
1572 /*
1573 ============================================================================
1574
1575                                                 NETWORKING
1576
1577 ============================================================================
1578 */
1579
1580 /* // FUCKED LINES
1581 typedef struct
1582 {
1583         char    priv[508];
1584 } doomdata_t;
1585 */ // FUCKED LINES
1586
1587 #define DOOMCOM_ID              0x12345678l
1588
1589 /* // FUCKED LINES
1590 typedef struct
1591 {
1592         long    id;
1593         short   intnum;                 // DOOM executes an int to execute commands
1594
1595 // communication between DOOM and the driver
1596         short   command;                // CMD_SEND or CMD_GET
1597         short   remotenode;             // dest for send, set by get (-1 = no packet)
1598         short   datalength;             // bytes in doomdata to be sent
1599
1600 // info common to all nodes
1601         short   numnodes;               // console is allways node 0
1602         short   ticdup;                 // 1 = no duplication, 2-5 = dup for slow nets
1603         short   extratics;              // 1 = send a backup tic in every packet
1604         short   deathmatch;             // 1 = deathmatch
1605         short   savegame;               // -1 = new game, 0-5 = load savegame
1606         short   episode;                // 1-3
1607         short   map;                    // 1-9
1608         short   skill;                  // 1-5
1609
1610 // info specific to this node
1611         short   consoleplayer;
1612         short   numplayers;
1613         short   angleoffset;    // 1 = left, 0 = center, -1 = right
1614         short   drone;                  // 1 = drone
1615
1616 // packet data to be sent
1617         doomdata_t      data;
1618 } doomcom_t;
1619 */ // FUCKED LINES
1620
1621 extern  doomcom_t               *doomcom;
1622
1623 /*
1624 ====================
1625 =
1626 = I_InitNetwork
1627 =
1628 ====================
1629 */
1630
1631 void I_InitNetwork (void)
1632 {
1633         int             i;
1634
1635         i = M_CheckParm ("-net");
1636         if (!i)
1637         {
1638         //
1639         // single player game
1640         //
1641                 doomcom = malloc (sizeof (*doomcom) );
1642                 memset (doomcom, 0, sizeof(*doomcom) );
1643                 netgame = false;
1644                 doomcom->id = DOOMCOM_ID;
1645                 doomcom->numplayers = doomcom->numnodes = 1;
1646                 doomcom->deathmatch = false;
1647                 doomcom->consoleplayer = 0;
1648                 doomcom->ticdup = 1;
1649                 doomcom->extratics = 0;
1650                 return;
1651         }
1652         netgame = true;
1653         doomcom = (doomcom_t *)atoi(myargv[i+1]);
1654 //DEBUG
1655 doomcom->skill = startskill;
1656 doomcom->episode = startepisode;
1657 doomcom->map = startmap;
1658 doomcom->deathmatch = deathmatch;
1659 }
1660
1661 void I_NetCmd (void)
1662 {
1663         if (!netgame)
1664                 I_Error ("I_NetCmd when not in netgame");
1665 }
1666
1667 //=========================================================================
1668 //
1669 // I_CheckExternDriver
1670 //
1671 //              Checks to see if a vector, and an address for an external driver
1672 //                      have been passed.
1673 //=========================================================================
1674
1675 void I_CheckExternDriver(void)
1676 {
1677         int i;
1678
1679         if(!(i = M_CheckParm("-externdriver")))
1680         {
1681                 return;
1682         }
1683         i_ExternData = (externdata_t *)atoi(myargv[i+1]);
1684         i_Vector = i_ExternData->vector;
1685
1686         useexterndriver = true;
1687 }
1688
1689 void PrintHelp(char *name)
1690 {
1691         printf ("HHexen (%s %d.%d)\n", VERSION_PLATFORM,
1692                         VERSION_MAJ,VERSION_MIN);
1693         printf ("http://icculus.org/hast/\n");
1694         printf ("Please send bug reports or patches to:\n");
1695         printf ("             Dan Olson <theoddone33@icculus.org>\n");
1696         printf ("\n");
1697         printf ("Usage: %s [options]\n", name);
1698         printf ("     [ -h | --help]           Display this help message\n");
1699         printf ("     [ -v | --version]        Display the game version\n");
1700         printf ("     [ -f | --fullscreen]     Run the game fullscreen\n");
1701         printf ("     [ -w | --windowed]       Run the game windowed\n");
1702         printf ("     [ -s | --nosound]        Run the game without sound\n");
1703         printf ("     [ -g | --nograb]         Disable mouse grabbing\n");
1704 #ifdef RENDER3D
1705         //printf ("     [ -l | --gllibrary]      Select 3D rendering library\n");
1706 #endif
1707         printf ("\n");
1708         printf ("You can use the HHEXEN_DATA environment variable to force the\n");
1709         printf ("HHexen data directory.\n");
1710         printf ("\n");
1711 }
1712
1713 void PrintVersion (void)
1714 {
1715         printf ("HHexen (%s %d.%d)\n", VERSION_PLATFORM,
1716                         VERSION_MAJ,VERSION_MIN);
1717 }
1718
1719 int main( int argc, char** argv )
1720 {
1721         myargc = argc;
1722         myargv = argv;
1723         if (M_CheckParm("--help") || M_CheckParm("-h"))
1724         {
1725                 PrintHelp (argv[0]);
1726                 return 0;
1727         }
1728         if (M_CheckParm("--version") || M_CheckParm("-v"))
1729         {
1730                 PrintVersion ();
1731                 return 0;
1732         }
1733         H2_Main();
1734         return 0;
1735 }
1736
1737
1738 //EOF
1739 fixed_t FixedMul (fixed_t a, fixed_t b)
1740 {
1741         fixed_t retval;
1742         __asm__ __volatile__(
1743                 "imull  %%edx                   \n\t"
1744                 "shrdl  $16, %%edx, %%eax       \n\t"
1745                 : "=a" (retval)
1746                 : "a" (a), "d" (b)
1747                 : "cc"
1748         );
1749         return retval;
1750 }
1751 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
1752 {
1753         fixed_t retval;
1754         __asm__ __volatile__(
1755                 "cdq                            \n\t"
1756                 "shldl  $16, %%eax, %%edx       \n\t"
1757                 "sall   $16, %%eax              \n\t"
1758                 "idivl  %%ebx                   \n\t"
1759                 : "=a" (retval)
1760                 : "a" (a), "b" (b)
1761                 : "%edx", "cc"
1762         );
1763         return retval;
1764 }