ref: 19687e3b456448a7650706ace7bf31f210a6dfde
parent: 05c4f601bbbbe2f1943b25dab7ad7b6eca5e7182
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Dec 29 10:53:22 EST 2023
rearrange and rename files
--- a/Makefile
+++ b/Makefile
@@ -43,6 +43,7 @@
i_resize.o\
i_tga.o\
i_wad.o\
+ in_sdl.o\
keys.o\
m_dotproduct.o\
mathlib.o\
@@ -56,6 +57,7 @@
model_sprite.o\
net_loop.o\
net_main.o\
+ net_udp_unix.o\
pal.o\
pr_cmds.o\
pr_edict.o\
@@ -77,6 +79,8 @@
r_surf.o\
sbar.o\
screen.o\
+ seprint.o\
+ snd_openal.o\
softfloat.o\
span.o\
span_alpha.o\
@@ -84,12 +88,8 @@
sv_move.o\
sv_phys.o\
sv_user.o\
- unix/in.o\
- unix/net_udp.o\
- unix/qk1.o\
- unix/seprint.o\
- unix/snd_openal.o\
- unix/vid.o\
+ sys_unix.o\
+ vid_sdl.o\
view.o\
wav.o\
world.o\
--- a/in.c
+++ /dev/null
@@ -1,348 +1,0 @@
-#include "quakedef.h"
-#include <bio.h>
-#include <draw.h>
-#include <thread.h>
-#include <mouse.h>
-#include <keyboard.h>
-
-/* vid.c */
-extern int resized;
-extern Point center;
-extern Rectangle grabr;
-
-typedef struct Kev Kev;
-
-enum{
- Nbuf = 20
-};
-struct Kev{
- int key;
- int down;
-};
-static Channel *inchan;
-static QLock mlck;
-
-static cvar_t m_windowed = {"m_windowed", "1", true};
-static cvar_t m_filter = {"m_filter", "0", true};
-static int mouseon, fixms;
-static int oldmwin;
-static float olddx, olddy;
-static int mΔx, mΔy, mb, oldmb;
-
-void
-conscmd(void)
-{
- char *p;
-
- if(cls.state != ca_dedicated)
- return;
- while(p = nbrecvp(inchan), p != nil){
- Cbuf_AddText(p);
- free(p);
- }
-}
-
-static void
-cproc(void *)
-{
- char *s;
- Biobuf *bf;
-
- if(bf = Bfdopen(0, OREAD), bf == nil)
- sysfatal("Bfdopen: %r");
- for(;;){
- if(s = Brdstr(bf, '\n', 1), s == nil)
- break;
- if(sendp(inchan, s) < 0){
- free(s);
- break;
- }
- }
- Bterm(bf);
-}
-
-void
-Sys_SendKeyEvents(void)
-{
- Kev ev;
- int r;
-
- if(cls.state == ca_dedicated)
- return;
- if(oldmwin != (int)m_windowed.value){
- oldmwin = (int)m_windowed.value;
- IN_Grabm(oldmwin);
- }
-
- while(r = nbrecv(inchan, &ev), r > 0)
- Key_Event(ev.key, ev.down);
- if(r < 0)
- Con_DPrintf("Sys_SendKeyEvents: %r\n");
-}
-
-void
-IN_Commands(void)
-{
- int b, i, k, r;
-
- if(!mouseon || cls.state == ca_dedicated)
- return;
- qlock(&mlck);
- b = mb;
- qunlock(&mlck);
- b = b & 0x19 | (b & 2) << 1 | (b & 4) >> 1;
- for(i=0, k=K_MOUSE1; i<5; i++, k++){
- if(i == 3)
- k = K_MWHEELUP;
- r = b & 1<<i;
- if(r ^ oldmb & 1<<i)
- Key_Event(k, r);
- }
- oldmb = b & 7;
-}
-
-void
-IN_Move(usercmd_t *cmd)
-{
- float dx, dy;
-
- if(!mouseon)
- return;
- qlock(&mlck);
- dx = mΔx;
- dy = mΔy;
- mΔx = 0;
- mΔy = 0;
- qunlock(&mlck);
- if(m_filter.value){
- dx = (dx + olddx) * 0.5;
- dy = (dy + olddy) * 0.5;
- }
- olddx = dx;
- olddy = dy;
- dx *= sensitivity.value;
- dy *= sensitivity.value;
- if(in_strafe.state & 1 || lookstrafe.value && in_mlook.state & 1)
- cmd->sidemove += m_side.value * dx;
- else
- cl.viewangles[YAW] -= m_yaw.value * dx;
- if(in_mlook.state & 1)
- V_StopPitchDrift();
- if(in_mlook.state & 1 && ~in_strafe.state & 1){
- cl.viewangles[PITCH] += m_pitch.value * dy;
- if(cl.viewangles[PITCH] > 80)
- cl.viewangles[PITCH] = 80;
- if(cl.viewangles[PITCH] < -70)
- cl.viewangles[PITCH] = -70;
- }else{
- if(in_strafe.state & 1 && noclip_anglehack)
- cmd->upmove -= m_forward.value * dy;
- else
- cmd->forwardmove -= m_forward.value * dy;
- }
-}
-
-static int
-runetokey(Rune r)
-{
- int k = 0;
-
- switch(r){
- case Kpgup: k = K_PGUP; break;
- case Kpgdown: k = K_PGDN; break;
- case Khome: k = K_HOME; break;
- case Kend: k = K_END; break;
- case Kleft: k = K_LEFTARROW; break;
- case Kright: k = K_RIGHTARROW; break;
- case Kdown: k = K_DOWNARROW; break;
- case Kup: k = K_UPARROW; break;
- case Kesc: k = K_ESCAPE; break;
- case '\n': k = K_ENTER; break;
- case '\t': k = K_TAB; break;
- case KF|1: k = K_F1; break;
- case KF|2: k = K_F2; break;
- case KF|3: k = K_F3; break;
- case KF|4: k = K_F4; break;
- case KF|5: k = K_F5; break;
- case KF|6: k = K_F6; break;
- case KF|7: k = K_F7; break;
- case KF|8: k = K_F8; break;
- case KF|9: k = K_F9; break;
- case KF|10: k = K_F10; break;
- case KF|11: k = K_F11; break;
- case KF|12: k = K_F12; break;
- case Kbs: k = K_BACKSPACE; break;
- case Kdel: k = K_DEL; break;
- case Kbreak: k = K_PAUSE; break;
- case Kshift: k = K_SHIFT; break;
- case Kctl: k = K_CTRL; break;
- case Kalt:
- case Kaltgr: k = K_ALT; break;
- case Kins: k = K_INS; break;
- case L'§': k = '~'; break;
- default:
- if(r < 0x80)
- k = r;
- }
- return k;
-}
-
-static void
-kproc(void *)
-{
- int n, k, fd;
- char buf[256], kdown[128], *s, *p;
- Rune r;
- Kev ev, evc;
-
- fd = open("/dev/kbd", OREAD);
- if(fd < 0)
- sysfatal("open /dev/kbd: %r");
- memset(buf, 0, sizeof buf);
- memset(kdown, 0, sizeof kdown);
- evc.key = K_ENTER;
- evc.down = true;
- for(;;){
- if(buf[0] != 0){
- n = strlen(buf)+1;
- memmove(buf, buf+n, sizeof(buf)-n);
- }
- if(buf[0] == 0){
- if(n = read(fd, buf, sizeof(buf)-1), n <= 0)
- break;
- buf[n-1] = 0;
- buf[n] = 0;
- }
- switch(buf[0]){
- case 'c':
- if(send(inchan, &evc) < 0)
- threadexits(nil);
- default:
- continue;
- case 'k':
- ev.down = true;
- s = buf+1;
- p = kdown+1;
- break;
- case 'K':
- ev.down = false;
- s = kdown+1;
- p = buf+1;
- break;
- }
- while(*s != 0){
- s += chartorune(&r, s);
- if(utfrune(p, r) == nil){
- k = runetokey(r);
- if(k == 0)
- continue;
- ev.key = k;
- if(send(inchan, &ev) < 0)
- threadexits(nil);
- if(ev.down)
- evc.key = k;
- }
- }
- strcpy(kdown, buf);
- }
-}
-
-static void
-mproc(void *)
-{
- int b, n, nerr, fd;
- char buf[1+5*12];
- Point p, o;
-
- fd = open("/dev/mouse", ORDWR);
- if(fd < 0)
- sysfatal("open /dev/mouse: %r");
- nerr = 0;
- o = center;
- for(;;){
- if(n = read(fd, buf, sizeof buf), n != 1+4*12){
- if(n < 0 || ++nerr > 10)
- break;
- Con_DPrintf("mproc: bad count %d not 49: %r\n", n);
- continue;
- }
- nerr = 0;
- switch(*buf){
- case 'r':
- resized = 1;
- /* fall through */
- case 'm':
- if(!mouseon)
- break;
- if(fixms){
- fixms = 0;
- goto res;
- }
- p.x = atoi(buf+1+0*12);
- p.y = atoi(buf+1+1*12);
- b = atoi(buf+1+2*12);
- qlock(&mlck);
- mΔx += p.x - o.x;
- mΔy += p.y - o.y;
- mb = b;
- qunlock(&mlck);
- if(!ptinrect(p, grabr)){
- res:
- fprint(fd, "m%d %d", center.x, center.y);
- p = center;
- }
- o = p;
- break;
- }
- }
-}
-
-void
-IN_Grabm(int on)
-{
- static char nocurs[2*4+2*2*16];
- static int fd = -1;
-
- if(mouseon == on)
- return;
- if(mouseon = on && m_windowed.value){
- fd = open("/dev/cursor", ORDWR|OCEXEC);
- if(fd < 0){
- Con_DPrintf("IN_Grabm:open: %r\n");
- return;
- }
- write(fd, nocurs, sizeof nocurs);
- fixms++;
- }else if(fd >= 0){
- close(fd);
- fd = -1;
- }
-}
-
-void
-IN_Shutdown(void)
-{
- if(inchan != nil)
- chanfree(inchan);
- IN_Grabm(0);
-}
-
-void
-IN_Init(void)
-{
- if(cls.state == ca_dedicated){
- if(inchan = chancreate(sizeof(void *), 2), inchan == nil)
- sysfatal("chancreate: %r");
- if(proccreate(cproc, nil, 8192) < 0)
- sysfatal("proccreate iproc: %r");
- return;
- }
- Cvar_RegisterVariable(&m_windowed);
- Cvar_RegisterVariable(&m_filter);
- if(inchan = chancreate(sizeof(Kev), Nbuf), inchan == nil)
- sysfatal("chancreate: %r");
- if(proccreate(kproc, nil, 8192) < 0)
- sysfatal("proccreate kproc: %r");
- if(proccreate(mproc, nil, 8192) < 0)
- sysfatal("proccreate mproc: %r");
-}
--- /dev/null
+++ b/in_plan9.c
@@ -1,0 +1,348 @@
+#include "quakedef.h"
+#include <bio.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <keyboard.h>
+
+/* vid.c */
+extern int resized;
+extern Point center;
+extern Rectangle grabr;
+
+typedef struct Kev Kev;
+
+enum{
+ Nbuf = 20
+};
+struct Kev{
+ int key;
+ int down;
+};
+static Channel *inchan;
+static QLock mlck;
+
+static cvar_t m_windowed = {"m_windowed", "1", true};
+static cvar_t m_filter = {"m_filter", "0", true};
+static int mouseon, fixms;
+static int oldmwin;
+static float olddx, olddy;
+static int mΔx, mΔy, mb, oldmb;
+
+void
+conscmd(void)
+{
+ char *p;
+
+ if(cls.state != ca_dedicated)
+ return;
+ while(p = nbrecvp(inchan), p != nil){
+ Cbuf_AddText(p);
+ free(p);
+ }
+}
+
+static void
+cproc(void *)
+{
+ char *s;
+ Biobuf *bf;
+
+ if(bf = Bfdopen(0, OREAD), bf == nil)
+ sysfatal("Bfdopen: %r");
+ for(;;){
+ if(s = Brdstr(bf, '\n', 1), s == nil)
+ break;
+ if(sendp(inchan, s) < 0){
+ free(s);
+ break;
+ }
+ }
+ Bterm(bf);
+}
+
+void
+Sys_SendKeyEvents(void)
+{
+ Kev ev;
+ int r;
+
+ if(cls.state == ca_dedicated)
+ return;
+ if(oldmwin != (int)m_windowed.value){
+ oldmwin = (int)m_windowed.value;
+ IN_Grabm(oldmwin);
+ }
+
+ while(r = nbrecv(inchan, &ev), r > 0)
+ Key_Event(ev.key, ev.down);
+ if(r < 0)
+ Con_DPrintf("Sys_SendKeyEvents: %r\n");
+}
+
+void
+IN_Commands(void)
+{
+ int b, i, k, r;
+
+ if(!mouseon || cls.state == ca_dedicated)
+ return;
+ qlock(&mlck);
+ b = mb;
+ qunlock(&mlck);
+ b = b & 0x19 | (b & 2) << 1 | (b & 4) >> 1;
+ for(i=0, k=K_MOUSE1; i<5; i++, k++){
+ if(i == 3)
+ k = K_MWHEELUP;
+ r = b & 1<<i;
+ if(r ^ oldmb & 1<<i)
+ Key_Event(k, r);
+ }
+ oldmb = b & 7;
+}
+
+void
+IN_Move(usercmd_t *cmd)
+{
+ float dx, dy;
+
+ if(!mouseon)
+ return;
+ qlock(&mlck);
+ dx = mΔx;
+ dy = mΔy;
+ mΔx = 0;
+ mΔy = 0;
+ qunlock(&mlck);
+ if(m_filter.value){
+ dx = (dx + olddx) * 0.5;
+ dy = (dy + olddy) * 0.5;
+ }
+ olddx = dx;
+ olddy = dy;
+ dx *= sensitivity.value;
+ dy *= sensitivity.value;
+ if(in_strafe.state & 1 || lookstrafe.value && in_mlook.state & 1)
+ cmd->sidemove += m_side.value * dx;
+ else
+ cl.viewangles[YAW] -= m_yaw.value * dx;
+ if(in_mlook.state & 1)
+ V_StopPitchDrift();
+ if(in_mlook.state & 1 && ~in_strafe.state & 1){
+ cl.viewangles[PITCH] += m_pitch.value * dy;
+ if(cl.viewangles[PITCH] > 80)
+ cl.viewangles[PITCH] = 80;
+ if(cl.viewangles[PITCH] < -70)
+ cl.viewangles[PITCH] = -70;
+ }else{
+ if(in_strafe.state & 1 && noclip_anglehack)
+ cmd->upmove -= m_forward.value * dy;
+ else
+ cmd->forwardmove -= m_forward.value * dy;
+ }
+}
+
+static int
+runetokey(Rune r)
+{
+ int k = 0;
+
+ switch(r){
+ case Kpgup: k = K_PGUP; break;
+ case Kpgdown: k = K_PGDN; break;
+ case Khome: k = K_HOME; break;
+ case Kend: k = K_END; break;
+ case Kleft: k = K_LEFTARROW; break;
+ case Kright: k = K_RIGHTARROW; break;
+ case Kdown: k = K_DOWNARROW; break;
+ case Kup: k = K_UPARROW; break;
+ case Kesc: k = K_ESCAPE; break;
+ case '\n': k = K_ENTER; break;
+ case '\t': k = K_TAB; break;
+ case KF|1: k = K_F1; break;
+ case KF|2: k = K_F2; break;
+ case KF|3: k = K_F3; break;
+ case KF|4: k = K_F4; break;
+ case KF|5: k = K_F5; break;
+ case KF|6: k = K_F6; break;
+ case KF|7: k = K_F7; break;
+ case KF|8: k = K_F8; break;
+ case KF|9: k = K_F9; break;
+ case KF|10: k = K_F10; break;
+ case KF|11: k = K_F11; break;
+ case KF|12: k = K_F12; break;
+ case Kbs: k = K_BACKSPACE; break;
+ case Kdel: k = K_DEL; break;
+ case Kbreak: k = K_PAUSE; break;
+ case Kshift: k = K_SHIFT; break;
+ case Kctl: k = K_CTRL; break;
+ case Kalt:
+ case Kaltgr: k = K_ALT; break;
+ case Kins: k = K_INS; break;
+ case L'§': k = '~'; break;
+ default:
+ if(r < 0x80)
+ k = r;
+ }
+ return k;
+}
+
+static void
+kproc(void *)
+{
+ int n, k, fd;
+ char buf[256], kdown[128], *s, *p;
+ Rune r;
+ Kev ev, evc;
+
+ fd = open("/dev/kbd", OREAD);
+ if(fd < 0)
+ sysfatal("open /dev/kbd: %r");
+ memset(buf, 0, sizeof buf);
+ memset(kdown, 0, sizeof kdown);
+ evc.key = K_ENTER;
+ evc.down = true;
+ for(;;){
+ if(buf[0] != 0){
+ n = strlen(buf)+1;
+ memmove(buf, buf+n, sizeof(buf)-n);
+ }
+ if(buf[0] == 0){
+ if(n = read(fd, buf, sizeof(buf)-1), n <= 0)
+ break;
+ buf[n-1] = 0;
+ buf[n] = 0;
+ }
+ switch(buf[0]){
+ case 'c':
+ if(send(inchan, &evc) < 0)
+ threadexits(nil);
+ default:
+ continue;
+ case 'k':
+ ev.down = true;
+ s = buf+1;
+ p = kdown+1;
+ break;
+ case 'K':
+ ev.down = false;
+ s = kdown+1;
+ p = buf+1;
+ break;
+ }
+ while(*s != 0){
+ s += chartorune(&r, s);
+ if(utfrune(p, r) == nil){
+ k = runetokey(r);
+ if(k == 0)
+ continue;
+ ev.key = k;
+ if(send(inchan, &ev) < 0)
+ threadexits(nil);
+ if(ev.down)
+ evc.key = k;
+ }
+ }
+ strcpy(kdown, buf);
+ }
+}
+
+static void
+mproc(void *)
+{
+ int b, n, nerr, fd;
+ char buf[1+5*12];
+ Point p, o;
+
+ fd = open("/dev/mouse", ORDWR);
+ if(fd < 0)
+ sysfatal("open /dev/mouse: %r");
+ nerr = 0;
+ o = center;
+ for(;;){
+ if(n = read(fd, buf, sizeof buf), n != 1+4*12){
+ if(n < 0 || ++nerr > 10)
+ break;
+ Con_DPrintf("mproc: bad count %d not 49: %r\n", n);
+ continue;
+ }
+ nerr = 0;
+ switch(*buf){
+ case 'r':
+ resized = 1;
+ /* fall through */
+ case 'm':
+ if(!mouseon)
+ break;
+ if(fixms){
+ fixms = 0;
+ goto res;
+ }
+ p.x = atoi(buf+1+0*12);
+ p.y = atoi(buf+1+1*12);
+ b = atoi(buf+1+2*12);
+ qlock(&mlck);
+ mΔx += p.x - o.x;
+ mΔy += p.y - o.y;
+ mb = b;
+ qunlock(&mlck);
+ if(!ptinrect(p, grabr)){
+ res:
+ fprint(fd, "m%d %d", center.x, center.y);
+ p = center;
+ }
+ o = p;
+ break;
+ }
+ }
+}
+
+void
+IN_Grabm(int on)
+{
+ static char nocurs[2*4+2*2*16];
+ static int fd = -1;
+
+ if(mouseon == on)
+ return;
+ if(mouseon = on && m_windowed.value){
+ fd = open("/dev/cursor", ORDWR|OCEXEC);
+ if(fd < 0){
+ Con_DPrintf("IN_Grabm:open: %r\n");
+ return;
+ }
+ write(fd, nocurs, sizeof nocurs);
+ fixms++;
+ }else if(fd >= 0){
+ close(fd);
+ fd = -1;
+ }
+}
+
+void
+IN_Shutdown(void)
+{
+ if(inchan != nil)
+ chanfree(inchan);
+ IN_Grabm(0);
+}
+
+void
+IN_Init(void)
+{
+ if(cls.state == ca_dedicated){
+ if(inchan = chancreate(sizeof(void *), 2), inchan == nil)
+ sysfatal("chancreate: %r");
+ if(proccreate(cproc, nil, 8192) < 0)
+ sysfatal("proccreate iproc: %r");
+ return;
+ }
+ Cvar_RegisterVariable(&m_windowed);
+ Cvar_RegisterVariable(&m_filter);
+ if(inchan = chancreate(sizeof(Kev), Nbuf), inchan == nil)
+ sysfatal("chancreate: %r");
+ if(proccreate(kproc, nil, 8192) < 0)
+ sysfatal("proccreate kproc: %r");
+ if(proccreate(mproc, nil, 8192) < 0)
+ sysfatal("proccreate mproc: %r");
+}
--- /dev/null
+++ b/in_sdl.c
@@ -1,0 +1,177 @@
+#include "quakedef.h"
+#include <SDL.h>
+
+/* vid.c */
+extern int resized;
+
+static cvar_t m_windowed = {"m_windowed", "1", true};
+static cvar_t m_filter = {"m_filter", "0", true};
+static cvar_t m_raw = {"m_raw", "1", true};
+static int mouseon, oldmwin, focuslost;
+static float dx, dy, olddx, olddy;
+
+static int mbuttons[] = {
+ K_MOUSE1,
+ K_MOUSE3,
+ K_MOUSE2,
+};
+
+void
+conscmd(void)
+{
+}
+
+void
+Sys_SendKeyEvents(void)
+{
+ SDL_Event event;
+ int key, b;
+
+ if(cls.state == ca_dedicated)
+ return;
+ if(oldmwin != (int)m_windowed.value){
+ oldmwin = (int)m_windowed.value;
+ IN_Grabm(oldmwin);
+ }
+
+ while(SDL_PollEvent(&event)){
+ switch(event.type){
+ case SDL_QUIT:
+ Cbuf_AddText("menu_quit\n");
+ break;
+ case SDL_WINDOWEVENT:
+ switch(event.window.event){
+ case SDL_WINDOWEVENT_RESIZED:
+ resized = 1;
+ break;
+ case SDL_WINDOWEVENT_CLOSE:
+ Cbuf_AddText("menu_quit\n");
+ break;
+ case SDL_WINDOWEVENT_LEAVE:
+ focuslost = mouseon;
+ IN_Grabm(0);
+ break;
+ case SDL_WINDOWEVENT_ENTER:
+ IN_Grabm(focuslost);
+ break;
+ }
+ break;
+ case SDL_MOUSEMOTION:
+ if(mouseon){
+ dx += event.motion.xrel;
+ dy += event.motion.yrel;
+ }
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ if(mouseon && (b = event.button.button-1) >= 0 && b < nelem(mbuttons))
+ Key_Event(mbuttons[b], event.type == SDL_MOUSEBUTTONDOWN);
+ break;
+ case SDL_KEYDOWN:
+ case SDL_KEYUP:
+ switch(key = event.key.keysym.sym){
+ case SDLK_BACKQUOTE: key = '~'; break;
+ case SDLK_DELETE: key = K_DEL; break;
+ case SDLK_BACKSPACE: key = K_BACKSPACE; break;
+ case SDLK_F1: key = K_F1; break;
+ case SDLK_F2: key = K_F2; break;
+ case SDLK_F3: key = K_F3; break;
+ case SDLK_F4: key = K_F4; break;
+ case SDLK_F5: key = K_F5; break;
+ case SDLK_F6: key = K_F6; break;
+ case SDLK_F7: key = K_F7; break;
+ case SDLK_F8: key = K_F8; break;
+ case SDLK_F9: key = K_F9; break;
+ case SDLK_F10: key = K_F10; break;
+ case SDLK_F11: key = K_F11; break;
+ case SDLK_F12: key = K_F12; break;
+ case SDLK_PAUSE: key = K_PAUSE; break;
+ case SDLK_UP: key = K_UPARROW; break;
+ case SDLK_DOWN: key = K_DOWNARROW; break;
+ case SDLK_RIGHT: key = K_RIGHTARROW; break;
+ case SDLK_LEFT: key = K_LEFTARROW; break;
+ case SDLK_RSHIFT:
+ case SDLK_LSHIFT: key = K_SHIFT; break;
+ case SDLK_RCTRL:
+ case SDLK_LCTRL: key = K_CTRL; break;
+ case SDLK_RALT:
+ case SDLK_LALT: key = K_ALT; break;
+ default:
+ if(key >= 128)
+ key = 0;
+ break;
+ }
+ if(key > 0)
+ Key_Event(key, event.key.state);
+ break;
+ }
+ }
+}
+
+void
+IN_Commands(void)
+{
+}
+
+static void
+m_raw_cb(cvar_t *var)
+{
+ SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, var->value > 0 ? "0" : "1");
+}
+
+void
+IN_Move(usercmd_t *cmd)
+{
+ if(!mouseon)
+ return;
+
+ if(m_filter.value){
+ dx = (dx + olddx) * 0.5;
+ dy = (dy + olddy) * 0.5;
+ }
+ olddx = dx;
+ olddy = dy;
+ dx *= sensitivity.value;
+ dy *= sensitivity.value;
+ if(in_strafe.state & 1 || (lookstrafe.value && in_mlook.state & 1))
+ cmd->sidemove += m_side.value * dx;
+ else
+ cl.viewangles[YAW] -= m_yaw.value * dx;
+ if(in_mlook.state & 1)
+ V_StopPitchDrift();
+ if(in_mlook.state & 1 && ~in_strafe.state & 1){
+ cl.viewangles[PITCH] += m_pitch.value * dy;
+ if(cl.viewangles[PITCH] > 80)
+ cl.viewangles[PITCH] = 80;
+ if(cl.viewangles[PITCH] < -70)
+ cl.viewangles[PITCH] = -70;
+ }else{
+ if(in_strafe.state & 1 && noclip_anglehack)
+ cmd->upmove -= m_forward.value * dy;
+ else
+ cmd->forwardmove -= m_forward.value * dy;
+ }
+ dx = 0;
+ dy = 0;
+}
+
+void
+IN_Grabm(int on)
+{
+ SDL_SetRelativeMouseMode(mouseon = on);
+}
+
+void
+IN_Shutdown(void)
+{
+ IN_Grabm(0);
+}
+
+void
+IN_Init(void)
+{
+ m_raw.cb = m_raw_cb;
+ Cvar_RegisterVariable(&m_windowed);
+ Cvar_RegisterVariable(&m_filter);
+ Cvar_RegisterVariable(&m_raw);
+}
--- a/mkfile
+++ b/mkfile
@@ -5,21 +5,18 @@
CFLAGS=$CFLAGS -D__plan9__ -D__${objtype}__ -Iplan9
OFILES=\
- span`{test -f span_$objtype.s && echo -n _$objtype}.$O\
- span_alpha.$O\
cd.$O\
cd_plan9.$O\
+ chase.$O\
cl_demo.$O\
cl_input.$O\
cl_main.$O\
cl_parse.$O\
cl_tent.$O\
- chase.$O\
cmd.$O\
common.$O\
console.$O\
cvar.$O\
- draw.$O\
d_alpha.$O\
d_edge.$O\
d_init.$O\
@@ -31,6 +28,7 @@
d_sprite.$O\
d_surf.$O\
d_vars.$O\
+ draw.$O\
fs.$O\
host.$O\
host_cmd.$O\
@@ -38,7 +36,7 @@
i_resize.$O\
i_tga.$O\
i_wad.$O\
- in.$O\
+ in_plan9.$O\
isnanf.$O\
keys.$O\
m_dotproduct`{test -f span_$objtype.s && echo -n _$objtype}.$O\
@@ -52,21 +50,20 @@
model_bsp30.$O\
model_sprite.$O\
nanosec.$O\
- net_dgrm.$O\
+ net_dgrm_plan9.$O\
net_loop.$O\
net_main.$O\
- net_udp.$O\
+ net_udp_plan9.$O\
pr_cmds.$O\
pr_edict.$O\
pr_exec.$O\
protocol.$O\
- qk1.$O\
r_aclip.$O\
r_alias.$O\
r_bsp.$O\
r_draw.$O\
- r_efrag.$O\
r_edge.$O\
+ r_efrag.$O\
r_fog.$O\
r_light.$O\
r_main.$O\
@@ -75,16 +72,19 @@
r_sky.$O\
r_sprite.$O\
r_surf.$O\
- screen.$O\
sbar.$O\
- snd.$O\
+ screen.$O\
+ snd_mix.$O\
snd_plan9.$O\
softfloat.$O\
+ span_alpha.$O\
+ span`{test -f span_$objtype.s && echo -n _$objtype}.$O\
sv_main.$O\
sv_move.$O\
sv_phys.$O\
sv_user.$O\
- vid.$O\
+ sys_plan9.$O\
+ vid_plan9.$O\
view.$O\
wav.$O\
world.$O\
--- a/net_dgrm.c
+++ /dev/null
@@ -1,766 +1,0 @@
-#include "quakedef.h"
-#include <ip.h>
-
-//#define DEBUG
-
-// these two macros are to make the code more readable
-#define sfunc landrv[sock->landriver]
-#define dfunc landrv[net_landriverlevel]
-
-static int net_landriverlevel;
-
-/* statistic counters */
-static int packetsSent;
-static int packetsReSent;
-static int packetsReceived;
-static int receivedDuplicateCount;
-static int shortPacketCount;
-static int droppedDatagrams;
-
-static int myDriverLevel;
-
-static uchar netbuf[4+4+NET_MAXMESSAGE];
-
-extern int m_return_state;
-extern int m_state;
-extern bool m_return_onerror;
-extern char m_return_reason[32];
-
-static int
-netpack(Addr *a, int f, uint seq, uchar *buf, int n)
-{
- hnputl(netbuf, NET_HEADERSIZE + n | f);
- hnputl(netbuf+4, seq);
- if(buf != nil)
- memcpy(netbuf+8, buf, n);
- return udpwrite(netbuf, NET_HEADERSIZE + n, a);
-}
-
-int Datagram_SendMessage (qsocket_t *s, sizebuf_t *data)
-{
- unsigned int n;
- unsigned int eom;
-
-#ifdef DEBUG
- if (data->cursize == 0)
- fatal("Datagram_SendMessage: zero length message\n");
-
- if (data->cursize > NET_MAXMESSAGE)
- fatal("Datagram_SendMessage: message too big %ud\n", data->cursize);
-
- if (s->canSend == false)
- fatal("SendMessage: called with canSend == false\n");
-#endif
-
- memcpy(s->sendMessage, data->data, data->cursize);
- s->sendMessageLength = data->cursize;
- if(data->cursize <= MAX_DATAGRAM){
- n = data->cursize;
- eom = NFEOM;
- }else{
- n = MAX_DATAGRAM;
- eom = 0;
- }
- s->canSend = false;
- if(netpack(&s->addr, NFDAT|eom, s->sendSequence++, s->sendMessage, n) < 0)
- return -1;
- s->lastSendTime = net_time;
- packetsSent++;
- return 1;
-}
-
-
-int SendMessageNext (qsocket_t *s)
-{
- unsigned int n;
- unsigned int eom;
-
- if(s->sendMessageLength <= MAX_DATAGRAM){
- n = s->sendMessageLength;
- eom = NFEOM;
- }else{
- n = MAX_DATAGRAM;
- eom = 0;
- }
- s->sendNext = false;
- if(netpack(&s->addr, NFDAT|eom, s->sendSequence++, s->sendMessage, n) < 0)
- return -1;
- s->lastSendTime = net_time;
- packetsSent++;
- return 1;
-}
-
-
-int ReSendMessage (qsocket_t *s)
-{
- unsigned int n;
- unsigned int eom;
-
- if (s->sendMessageLength <= MAX_DATAGRAM)
- {
- n = s->sendMessageLength;
- eom = NFEOM;
- }
- else
- {
- n = MAX_DATAGRAM;
- eom = 0;
- }
- s->sendNext = false;
- if(netpack(&s->addr, NFDAT|eom, s->sendSequence-1, s->sendMessage, n) < 0)
- return -1;
- s->lastSendTime = net_time;
- packetsReSent++;
- return 1;
-}
-
-
-bool Datagram_CanSendMessage (qsocket_t *sock)
-{
- if (sock->sendNext)
- SendMessageNext (sock);
-
- return sock->canSend;
-}
-
-
-bool Datagram_CanSendUnreliableMessage (qsocket_t *)
-{
- return true;
-}
-
-
-int Datagram_SendUnreliableMessage (qsocket_t *s, sizebuf_t *data)
-{
-#ifdef DEBUG
- if (data->cursize == 0)
- fatal("Datagram_SendUnreliableMessage: zero length message\n");
-
- if (data->cursize > MAX_DATAGRAM)
- fatal("Datagram_SendUnreliableMessage: message too big %ud\n", data->cursize);
-#endif
-
- if(netpack(&s->addr, NFUNREL, s->unreliableSendSequence++, data->data, data->cursize) < 0)
- return -1;
- packetsSent++;
- return 1;
-}
-
-
-int Datagram_GetMessage (qsocket_t *sock)
-{
- int n;
- unsigned int flags;
- int ret = 0;
- unsigned int sequence;
- unsigned int count;
-
- if (!sock->canSend)
- if ((net_time - sock->lastSendTime) > 1.0)
- ReSendMessage (sock);
- while(1)
- {
- if((n = udpread(netbuf, NET_MAXMESSAGE, &sock->addr)) == 0)
- break;
-
- if (n == -1)
- {
- Con_Printf("Read error\n");
- return -1;
- }
-
- if (n < NET_HEADERSIZE)
- {
- shortPacketCount++;
- continue;
- }
-
- n = nhgetl(netbuf);
- flags = n & (~NFMASK);
- n &= NFMASK;
-
- if (flags & NFCTL)
- continue;
-
- sequence = nhgetl(netbuf+4);
- packetsReceived++;
-
- if (flags & NFUNREL)
- {
- if (sequence < sock->unreliableReceiveSequence)
- {
- Con_DPrintf("Got a stale datagram\n");
- ret = 0;
- break;
- }
- if (sequence != sock->unreliableReceiveSequence)
- {
- count = sequence - sock->unreliableReceiveSequence;
- droppedDatagrams += count;
- Con_DPrintf("Dropped %ud datagram(s)\n", count);
- }
- sock->unreliableReceiveSequence = sequence + 1;
-
- n -= NET_HEADERSIZE;
-
- SZ_Clear (&net_message);
- SZ_Write (&net_message, netbuf+8, n);
-
- ret = 2;
- break;
- }
-
- if (flags & NFACK)
- {
- if (sequence != (sock->sendSequence - 1))
- {
- Con_DPrintf("Stale ACK received\n");
- continue;
- }
- if (sequence == sock->ackSequence)
- {
- sock->ackSequence++;
- if (sock->ackSequence != sock->sendSequence)
- Con_DPrintf("ack sequencing error\n");
- }
- else
- {
- Con_DPrintf("Duplicate ACK received\n");
- continue;
- }
- sock->sendMessageLength -= MAX_DATAGRAM;
- if (sock->sendMessageLength > 0)
- {
- memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
- sock->sendNext = true;
- }
- else
- {
- sock->sendMessageLength = 0;
- sock->canSend = true;
- }
- continue;
- }
-
- if (flags & NFDAT)
- {
- netpack(&sock->addr, NFACK, sequence, nil, 0);
- if (sequence != sock->receiveSequence)
- {
- receivedDuplicateCount++;
- continue;
- }
- sock->receiveSequence++;
-
- n -= NET_HEADERSIZE;
-
- if (flags & NFEOM)
- {
- SZ_Clear(&net_message);
- SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
- SZ_Write(&net_message, netbuf+8, n);
- sock->receiveMessageLength = 0;
-
- ret = 1;
- break;
- }
-
- memcpy(sock->receiveMessage + sock->receiveMessageLength, netbuf+8, n);
- sock->receiveMessageLength += n;
- continue;
- }
- }
-
- if (sock->sendNext)
- SendMessageNext (sock);
-
- return ret;
-}
-
-
-void PrintStats(qsocket_t *s)
-{
- Con_Printf("canSend = %4d \n", s->canSend);
- Con_Printf("sendSeq = %4d ", s->sendSequence);
- Con_Printf("recvSeq = %4d \n", s->receiveSequence);
- Con_Printf("\n");
-}
-
-void NET_Stats_f (void)
-{
- qsocket_t *s;
-
- if (Cmd_Argc () == 1)
- {
- Con_Printf("unreliable messages sent = %d\n", unreliableMessagesSent);
- Con_Printf("unreliable messages recv = %d\n", unreliableMessagesReceived);
- Con_Printf("reliable messages sent = %d\n", messagesSent);
- Con_Printf("reliable messages received = %d\n", messagesReceived);
- Con_Printf("packetsSent = %d\n", packetsSent);
- Con_Printf("packetsReSent = %d\n", packetsReSent);
- Con_Printf("packetsReceived = %d\n", packetsReceived);
- Con_Printf("receivedDuplicateCount = %d\n", receivedDuplicateCount);
- Con_Printf("shortPacketCount = %d\n", shortPacketCount);
- Con_Printf("droppedDatagrams = %d\n", droppedDatagrams);
- }
- else if(strcmp(Cmd_Argv(1), "*") == 0)
- {
- for (s = net_activeSockets; s; s = s->next)
- PrintStats(s);
- for (s = net_freeSockets; s; s = s->next)
- PrintStats(s);
- }
- else
- {
- for (s = net_activeSockets; s; s = s->next)
- if(cistrcmp(Cmd_Argv(1), s->address) == 0)
- break;
- if (s == nil)
- for (s = net_freeSockets; s; s = s->next)
- if(cistrcmp(Cmd_Argv(1), s->address) == 0)
- break;
- if (s == nil)
- return;
- PrintStats(s);
- }
-}
-
-int
-Datagram_Init(void)
-{
- int i;
-
- myDriverLevel = net_driverlevel;
- Cmd_AddCommand("net_stats", NET_Stats_f);
-
- for(i=0; i<net_numlandrivers; i++){
- if(landrv[i].Init() < 0)
- continue;
- landrv[i].initialized = true;
- }
-
- return 0;
-}
-
-
-void Datagram_Shutdown (void)
-{
- int i;
-
- // shutdown the lan drivers
- for (i = 0; i < net_numlandrivers; i++)
- {
- if (landrv[i].initialized)
- {
- landrv[i].Shutdown ();
- landrv[i].initialized = false;
- }
- }
-}
-
-static qsocket_t *_Datagram_CheckNewConnections (void)
-{
- Addr clientaddr;
- int newsock;
- qsocket_t *sock;
- qsocket_t *s;
- int len;
- int command;
- int control;
-
- memset(&clientaddr, 0, sizeof clientaddr);
- if(getnewcon(&clientaddr) == 0)
- return nil;
- SZ_Clear(&net_message);
- len = udpread(net_message.data, net_message.maxsize, &clientaddr);
- if (len < sizeof(s32int))
- goto done;
- net_message.cursize = len;
-
- MSG_BeginReading ();
- control = BigLong(*((int *)net_message.data));
- MSG_ReadLong();
- if (control == -1)
- goto done;
- if ((control & (~NFMASK)) != NFCTL)
- goto done;
- if ((control & NFMASK) != len)
- goto done;
-
- command = MSG_ReadByte();
- if (command == CQSVINFO)
- {
- if(strcmp(MSG_ReadString(), "QUAKE") != 0)
- goto done;
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CPSVINFO);
- MSG_WriteString(&net_message, dfunc.AddrToString(&myip));
- MSG_WriteString(&net_message, hostname.string);
- MSG_WriteString(&net_message, sv.name);
- MSG_WriteByte(&net_message, net_activeconnections);
- MSG_WriteByte(&net_message, svs.maxclients);
- MSG_WriteByte(&net_message, NETVERSION);
- *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
- dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- goto done;
- }
-
- if (command == CQPLINFO)
- {
- int playerNumber;
- int activeNumber;
- int clientNumber;
- client_t *client;
-
- playerNumber = MSG_ReadByte();
- activeNumber = -1;
- for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
- {
- if (client->active)
- {
- activeNumber++;
- if (activeNumber == playerNumber)
- break;
- }
- }
- if (clientNumber == svs.maxclients)
- goto done;
-
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CPPLINFO);
- MSG_WriteByte(&net_message, playerNumber);
- MSG_WriteString(&net_message, client->name);
- MSG_WriteLong(&net_message, client->colors);
- MSG_WriteLong(&net_message, (int)client->edict->v.frags);
- MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
- MSG_WriteString(&net_message, client->netconnection->address);
- *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
- dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
-
- goto done;
- }
-
- if (command == CQRUINFO)
- {
- char *prevCvarName;
- cvar_t *var;
-
- // find the search start location
- prevCvarName = MSG_ReadString();
- if (*prevCvarName)
- {
- var = Cvar_FindVar (prevCvarName);
- if (!var)
- goto done;
- var = var->next;
- }
- else
- var = cvar_vars;
-
- // search for the next server cvar
- while (var)
- {
- if (var->server)
- break;
- var = var->next;
- }
-
- // send the response
-
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CPRUINFO);
- if (var)
- {
- MSG_WriteString(&net_message, var->name);
- MSG_WriteString(&net_message, var->string);
- }
- *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
- dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
-
- goto done;
- }
-
- if (command != CQCONNECT)
- goto done;
-
- if(strcmp(MSG_ReadString(), "QUAKE") != 0)
- goto done;
-
- if (MSG_ReadByte() != NETVERSION)
- {
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CPREJECT);
- MSG_WriteString(&net_message, "Incompatible version.\n");
- *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
- dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- goto done;
- }
-
- // see if this guy is already connected
- for (s = net_activeSockets; s; s = s->next)
- {
- if (s->driver != net_driverlevel)
- continue;
- if(strcmp(clientaddr.ip, s->addr.ip) != 0 || strcmp(clientaddr.srv, s->addr.srv) != 0)
- continue;
- // is this a duplicate connection reqeust?
- if(strcmp(clientaddr.srv, s->addr.srv) == 0
- && net_time - s->connecttime < 2.0)
- {
- // yes, so send a duplicate reply
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CPACCEPT);
- MSG_WriteLong(&net_message, dfunc.GetSocketPort(&myip));
- *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
- dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- goto done;
- }
- // it's somebody coming back in from a crash/disconnect
- // so close the old qsocket and let their retry get them back in
- NET_Close(s);
- goto done;
- }
-
- // allocate a QSocket
- sock = NET_NewQSocket ();
- if (sock == nil)
- {
- // no room; try to let him know
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CPREJECT);
- MSG_WriteString(&net_message, "Server is full.\n");
- *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
- dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- goto done;
- }
-
- // allocate a network socket
- newsock = 1;
-
- // everything is allocated, just fill in the details
- sock->socket = newsock;
- sock->landriver = net_landriverlevel;
- memcpy(&sock->addr, &clientaddr, sizeof clientaddr);
- strcpy(sock->address, UDP_AddrToString(&clientaddr));
-
- // send him back the info about the server connection he has been allocated
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CPACCEPT);
- MSG_WriteLong(&net_message, dfunc.GetSocketPort(&myip));
- *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
- dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
-
- return sock;
-done:
- close(clientaddr.fd);
- return nil;
-}
-
-qsocket_t *Datagram_CheckNewConnections (void)
-{
- qsocket_t *ret = nil;
-
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- if (landrv[net_landriverlevel].initialized)
- if ((ret = _Datagram_CheckNewConnections ()) != nil)
- break;
- return ret;
-}
-
-static qsocket_t *_Datagram_Connect (char *host)
-{
- Addr sendaddr;
- Addr readaddr;
- qsocket_t *sock;
- int ret = 0;
- int reps;
- double start_time;
- int control;
- char *reason;
-
- memset(&sendaddr, 0, sizeof sendaddr);
- memset(&readaddr, 0, sizeof readaddr);
-
- // see if we can resolve the host name
- if (dfunc.getip(host, &sendaddr) == -1){
- return nil;
- }
-
- sock = NET_NewQSocket ();
- if (sock == nil)
- goto ErrorReturn2;
- sock->socket = 1;
- sock->landriver = net_landriverlevel;
-
- // connect to the host
- if (dfunc.Connect(&sendaddr) == -1)
- goto ErrorReturn;
- memcpy(&readaddr, &sendaddr, sizeof readaddr);
-
- // send the connection request
- Con_Printf("trying...\n"); SCR_UpdateScreen (false);
- start_time = net_time;
-
- UDP_Listen(1);
- for (reps = 0; reps < 3; reps++)
- {
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CQCONNECT);
- MSG_WriteString(&net_message, "QUAKE");
- MSG_WriteByte(&net_message, NETVERSION);
- *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
- dfunc.Write(net_message.data, net_message.cursize, &sendaddr);
- SZ_Clear(&net_message);
- do
- {
- ret = dfunc.Read(net_message.data, net_message.maxsize, &readaddr);
- // if we got something, validate it
- if (ret > 0)
- {
- if (ret < sizeof(int))
- {
- ret = 0;
- continue;
- }
-
- net_message.cursize = ret;
- MSG_BeginReading ();
-
- control = BigLong(*((int *)net_message.data));
- MSG_ReadLong();
- if (control == -1)
- {
- ret = 0;
- continue;
- }
- if ((control & (~NFMASK)) != NFCTL)
- {
- ret = 0;
- continue;
- }
- if ((control & NFMASK) != ret)
- {
- ret = 0;
- continue;
- }
- }
- }
- while (ret == 0 && (SetNetTime() - start_time) < 2.5);
- if (ret)
- break;
- Con_Printf("still trying...\n"); SCR_UpdateScreen (false);
- start_time = SetNetTime();
- }
- /* bullshit workaround for non-plan9 servers replying from different
- * ports. because of this workaround, multiple instances on the same
- * host all require different ports prior to connection. if someone
- * has a better solution, i'm all ears. */
- start_time = SetNetTime();
- do{
- if(getnewcon(&sendaddr) > 0){
- close(readaddr.fd);
- memcpy(&readaddr, &sendaddr, sizeof readaddr);
- break;
- }
- sleep(1);
- }while(SetNetTime() - start_time < 2.5);
- UDP_Listen(0);
-
- if (ret == 0)
- {
- reason = "No Response";
- Con_Printf("%s\n", reason);
- strcpy(m_return_reason, reason);
- goto ErrorReturn;
- }
-
- if (ret == -1)
- {
- reason = "Network Error";
- Con_Printf("%s\n", reason);
- strcpy(m_return_reason, reason);
- goto ErrorReturn;
- }
-
- ret = MSG_ReadByte();
- if (ret == CPREJECT)
- {
- reason = MSG_ReadString();
- Con_Printf(reason);
- strncpy(m_return_reason, reason, 31);
- goto ErrorReturn;
- }
-
- if (ret == CPACCEPT)
- {
- memcpy(&sock->addr, &readaddr, sizeof readaddr);
- dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
- }
- else
- {
- reason = "Bad Response";
- Con_Printf("%s\n", reason);
- strcpy(m_return_reason, reason);
- goto ErrorReturn;
- }
-
- strcpy(sock->address, dfunc.AddrToString(&sendaddr));
-
- Con_Printf ("Connection accepted\n");
- sock->lastMessageTime = SetNetTime();
-
- m_return_onerror = false;
- return sock;
-
-ErrorReturn:
- close(readaddr.fd);
- NET_FreeQSocket(sock);
-ErrorReturn2:
- if (m_return_onerror)
- {
- key_dest = key_menu;
- m_state = m_return_state;
- m_return_onerror = false;
- }
- return nil;
-}
-
-qsocket_t *Datagram_Connect (char *host)
-{
- qsocket_t *ret = nil;
-
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- if (landrv[net_landriverlevel].initialized)
- if ((ret = _Datagram_Connect (host)) != nil)
- break;
- return ret;
-}
-
-void
-Datagram_Close(qsocket_t *s)
-{
- close(s->addr.fd);
-}
--- /dev/null
+++ b/net_dgrm_plan9.c
@@ -1,0 +1,766 @@
+#include "quakedef.h"
+#include <ip.h>
+
+//#define DEBUG
+
+// these two macros are to make the code more readable
+#define sfunc landrv[sock->landriver]
+#define dfunc landrv[net_landriverlevel]
+
+static int net_landriverlevel;
+
+/* statistic counters */
+static int packetsSent;
+static int packetsReSent;
+static int packetsReceived;
+static int receivedDuplicateCount;
+static int shortPacketCount;
+static int droppedDatagrams;
+
+static int myDriverLevel;
+
+static uchar netbuf[4+4+NET_MAXMESSAGE];
+
+extern int m_return_state;
+extern int m_state;
+extern bool m_return_onerror;
+extern char m_return_reason[32];
+
+static int
+netpack(Addr *a, int f, uint seq, uchar *buf, int n)
+{
+ hnputl(netbuf, NET_HEADERSIZE + n | f);
+ hnputl(netbuf+4, seq);
+ if(buf != nil)
+ memcpy(netbuf+8, buf, n);
+ return udpwrite(netbuf, NET_HEADERSIZE + n, a);
+}
+
+int Datagram_SendMessage (qsocket_t *s, sizebuf_t *data)
+{
+ unsigned int n;
+ unsigned int eom;
+
+#ifdef DEBUG
+ if (data->cursize == 0)
+ fatal("Datagram_SendMessage: zero length message\n");
+
+ if (data->cursize > NET_MAXMESSAGE)
+ fatal("Datagram_SendMessage: message too big %ud\n", data->cursize);
+
+ if (s->canSend == false)
+ fatal("SendMessage: called with canSend == false\n");
+#endif
+
+ memcpy(s->sendMessage, data->data, data->cursize);
+ s->sendMessageLength = data->cursize;
+ if(data->cursize <= MAX_DATAGRAM){
+ n = data->cursize;
+ eom = NFEOM;
+ }else{
+ n = MAX_DATAGRAM;
+ eom = 0;
+ }
+ s->canSend = false;
+ if(netpack(&s->addr, NFDAT|eom, s->sendSequence++, s->sendMessage, n) < 0)
+ return -1;
+ s->lastSendTime = net_time;
+ packetsSent++;
+ return 1;
+}
+
+
+int SendMessageNext (qsocket_t *s)
+{
+ unsigned int n;
+ unsigned int eom;
+
+ if(s->sendMessageLength <= MAX_DATAGRAM){
+ n = s->sendMessageLength;
+ eom = NFEOM;
+ }else{
+ n = MAX_DATAGRAM;
+ eom = 0;
+ }
+ s->sendNext = false;
+ if(netpack(&s->addr, NFDAT|eom, s->sendSequence++, s->sendMessage, n) < 0)
+ return -1;
+ s->lastSendTime = net_time;
+ packetsSent++;
+ return 1;
+}
+
+
+int ReSendMessage (qsocket_t *s)
+{
+ unsigned int n;
+ unsigned int eom;
+
+ if (s->sendMessageLength <= MAX_DATAGRAM)
+ {
+ n = s->sendMessageLength;
+ eom = NFEOM;
+ }
+ else
+ {
+ n = MAX_DATAGRAM;
+ eom = 0;
+ }
+ s->sendNext = false;
+ if(netpack(&s->addr, NFDAT|eom, s->sendSequence-1, s->sendMessage, n) < 0)
+ return -1;
+ s->lastSendTime = net_time;
+ packetsReSent++;
+ return 1;
+}
+
+
+bool Datagram_CanSendMessage (qsocket_t *sock)
+{
+ if (sock->sendNext)
+ SendMessageNext (sock);
+
+ return sock->canSend;
+}
+
+
+bool Datagram_CanSendUnreliableMessage (qsocket_t *)
+{
+ return true;
+}
+
+
+int Datagram_SendUnreliableMessage (qsocket_t *s, sizebuf_t *data)
+{
+#ifdef DEBUG
+ if (data->cursize == 0)
+ fatal("Datagram_SendUnreliableMessage: zero length message\n");
+
+ if (data->cursize > MAX_DATAGRAM)
+ fatal("Datagram_SendUnreliableMessage: message too big %ud\n", data->cursize);
+#endif
+
+ if(netpack(&s->addr, NFUNREL, s->unreliableSendSequence++, data->data, data->cursize) < 0)
+ return -1;
+ packetsSent++;
+ return 1;
+}
+
+
+int Datagram_GetMessage (qsocket_t *sock)
+{
+ int n;
+ unsigned int flags;
+ int ret = 0;
+ unsigned int sequence;
+ unsigned int count;
+
+ if (!sock->canSend)
+ if ((net_time - sock->lastSendTime) > 1.0)
+ ReSendMessage (sock);
+ while(1)
+ {
+ if((n = udpread(netbuf, NET_MAXMESSAGE, &sock->addr)) == 0)
+ break;
+
+ if (n == -1)
+ {
+ Con_Printf("Read error\n");
+ return -1;
+ }
+
+ if (n < NET_HEADERSIZE)
+ {
+ shortPacketCount++;
+ continue;
+ }
+
+ n = nhgetl(netbuf);
+ flags = n & (~NFMASK);
+ n &= NFMASK;
+
+ if (flags & NFCTL)
+ continue;
+
+ sequence = nhgetl(netbuf+4);
+ packetsReceived++;
+
+ if (flags & NFUNREL)
+ {
+ if (sequence < sock->unreliableReceiveSequence)
+ {
+ Con_DPrintf("Got a stale datagram\n");
+ ret = 0;
+ break;
+ }
+ if (sequence != sock->unreliableReceiveSequence)
+ {
+ count = sequence - sock->unreliableReceiveSequence;
+ droppedDatagrams += count;
+ Con_DPrintf("Dropped %ud datagram(s)\n", count);
+ }
+ sock->unreliableReceiveSequence = sequence + 1;
+
+ n -= NET_HEADERSIZE;
+
+ SZ_Clear (&net_message);
+ SZ_Write (&net_message, netbuf+8, n);
+
+ ret = 2;
+ break;
+ }
+
+ if (flags & NFACK)
+ {
+ if (sequence != (sock->sendSequence - 1))
+ {
+ Con_DPrintf("Stale ACK received\n");
+ continue;
+ }
+ if (sequence == sock->ackSequence)
+ {
+ sock->ackSequence++;
+ if (sock->ackSequence != sock->sendSequence)
+ Con_DPrintf("ack sequencing error\n");
+ }
+ else
+ {
+ Con_DPrintf("Duplicate ACK received\n");
+ continue;
+ }
+ sock->sendMessageLength -= MAX_DATAGRAM;
+ if (sock->sendMessageLength > 0)
+ {
+ memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
+ sock->sendNext = true;
+ }
+ else
+ {
+ sock->sendMessageLength = 0;
+ sock->canSend = true;
+ }
+ continue;
+ }
+
+ if (flags & NFDAT)
+ {
+ netpack(&sock->addr, NFACK, sequence, nil, 0);
+ if (sequence != sock->receiveSequence)
+ {
+ receivedDuplicateCount++;
+ continue;
+ }
+ sock->receiveSequence++;
+
+ n -= NET_HEADERSIZE;
+
+ if (flags & NFEOM)
+ {
+ SZ_Clear(&net_message);
+ SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
+ SZ_Write(&net_message, netbuf+8, n);
+ sock->receiveMessageLength = 0;
+
+ ret = 1;
+ break;
+ }
+
+ memcpy(sock->receiveMessage + sock->receiveMessageLength, netbuf+8, n);
+ sock->receiveMessageLength += n;
+ continue;
+ }
+ }
+
+ if (sock->sendNext)
+ SendMessageNext (sock);
+
+ return ret;
+}
+
+
+void PrintStats(qsocket_t *s)
+{
+ Con_Printf("canSend = %4d \n", s->canSend);
+ Con_Printf("sendSeq = %4d ", s->sendSequence);
+ Con_Printf("recvSeq = %4d \n", s->receiveSequence);
+ Con_Printf("\n");
+}
+
+void NET_Stats_f (void)
+{
+ qsocket_t *s;
+
+ if (Cmd_Argc () == 1)
+ {
+ Con_Printf("unreliable messages sent = %d\n", unreliableMessagesSent);
+ Con_Printf("unreliable messages recv = %d\n", unreliableMessagesReceived);
+ Con_Printf("reliable messages sent = %d\n", messagesSent);
+ Con_Printf("reliable messages received = %d\n", messagesReceived);
+ Con_Printf("packetsSent = %d\n", packetsSent);
+ Con_Printf("packetsReSent = %d\n", packetsReSent);
+ Con_Printf("packetsReceived = %d\n", packetsReceived);
+ Con_Printf("receivedDuplicateCount = %d\n", receivedDuplicateCount);
+ Con_Printf("shortPacketCount = %d\n", shortPacketCount);
+ Con_Printf("droppedDatagrams = %d\n", droppedDatagrams);
+ }
+ else if(strcmp(Cmd_Argv(1), "*") == 0)
+ {
+ for (s = net_activeSockets; s; s = s->next)
+ PrintStats(s);
+ for (s = net_freeSockets; s; s = s->next)
+ PrintStats(s);
+ }
+ else
+ {
+ for (s = net_activeSockets; s; s = s->next)
+ if(cistrcmp(Cmd_Argv(1), s->address) == 0)
+ break;
+ if (s == nil)
+ for (s = net_freeSockets; s; s = s->next)
+ if(cistrcmp(Cmd_Argv(1), s->address) == 0)
+ break;
+ if (s == nil)
+ return;
+ PrintStats(s);
+ }
+}
+
+int
+Datagram_Init(void)
+{
+ int i;
+
+ myDriverLevel = net_driverlevel;
+ Cmd_AddCommand("net_stats", NET_Stats_f);
+
+ for(i=0; i<net_numlandrivers; i++){
+ if(landrv[i].Init() < 0)
+ continue;
+ landrv[i].initialized = true;
+ }
+
+ return 0;
+}
+
+
+void Datagram_Shutdown (void)
+{
+ int i;
+
+ // shutdown the lan drivers
+ for (i = 0; i < net_numlandrivers; i++)
+ {
+ if (landrv[i].initialized)
+ {
+ landrv[i].Shutdown ();
+ landrv[i].initialized = false;
+ }
+ }
+}
+
+static qsocket_t *_Datagram_CheckNewConnections (void)
+{
+ Addr clientaddr;
+ int newsock;
+ qsocket_t *sock;
+ qsocket_t *s;
+ int len;
+ int command;
+ int control;
+
+ memset(&clientaddr, 0, sizeof clientaddr);
+ if(getnewcon(&clientaddr) == 0)
+ return nil;
+ SZ_Clear(&net_message);
+ len = udpread(net_message.data, net_message.maxsize, &clientaddr);
+ if (len < sizeof(s32int))
+ goto done;
+ net_message.cursize = len;
+
+ MSG_BeginReading ();
+ control = BigLong(*((int *)net_message.data));
+ MSG_ReadLong();
+ if (control == -1)
+ goto done;
+ if ((control & (~NFMASK)) != NFCTL)
+ goto done;
+ if ((control & NFMASK) != len)
+ goto done;
+
+ command = MSG_ReadByte();
+ if (command == CQSVINFO)
+ {
+ if(strcmp(MSG_ReadString(), "QUAKE") != 0)
+ goto done;
+ SZ_Clear(&net_message);
+ // save space for the header, filled in later
+ MSG_WriteLong(&net_message, 0);
+ MSG_WriteByte(&net_message, CPSVINFO);
+ MSG_WriteString(&net_message, dfunc.AddrToString(&myip));
+ MSG_WriteString(&net_message, hostname.string);
+ MSG_WriteString(&net_message, sv.name);
+ MSG_WriteByte(&net_message, net_activeconnections);
+ MSG_WriteByte(&net_message, svs.maxclients);
+ MSG_WriteByte(&net_message, NETVERSION);
+ *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+ dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
+ SZ_Clear(&net_message);
+ goto done;
+ }
+
+ if (command == CQPLINFO)
+ {
+ int playerNumber;
+ int activeNumber;
+ int clientNumber;
+ client_t *client;
+
+ playerNumber = MSG_ReadByte();
+ activeNumber = -1;
+ for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
+ {
+ if (client->active)
+ {
+ activeNumber++;
+ if (activeNumber == playerNumber)
+ break;
+ }
+ }
+ if (clientNumber == svs.maxclients)
+ goto done;
+
+ SZ_Clear(&net_message);
+ // save space for the header, filled in later
+ MSG_WriteLong(&net_message, 0);
+ MSG_WriteByte(&net_message, CPPLINFO);
+ MSG_WriteByte(&net_message, playerNumber);
+ MSG_WriteString(&net_message, client->name);
+ MSG_WriteLong(&net_message, client->colors);
+ MSG_WriteLong(&net_message, (int)client->edict->v.frags);
+ MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
+ MSG_WriteString(&net_message, client->netconnection->address);
+ *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+ dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
+ SZ_Clear(&net_message);
+
+ goto done;
+ }
+
+ if (command == CQRUINFO)
+ {
+ char *prevCvarName;
+ cvar_t *var;
+
+ // find the search start location
+ prevCvarName = MSG_ReadString();
+ if (*prevCvarName)
+ {
+ var = Cvar_FindVar (prevCvarName);
+ if (!var)
+ goto done;
+ var = var->next;
+ }
+ else
+ var = cvar_vars;
+
+ // search for the next server cvar
+ while (var)
+ {
+ if (var->server)
+ break;
+ var = var->next;
+ }
+
+ // send the response
+
+ SZ_Clear(&net_message);
+ // save space for the header, filled in later
+ MSG_WriteLong(&net_message, 0);
+ MSG_WriteByte(&net_message, CPRUINFO);
+ if (var)
+ {
+ MSG_WriteString(&net_message, var->name);
+ MSG_WriteString(&net_message, var->string);
+ }
+ *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+ dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
+ SZ_Clear(&net_message);
+
+ goto done;
+ }
+
+ if (command != CQCONNECT)
+ goto done;
+
+ if(strcmp(MSG_ReadString(), "QUAKE") != 0)
+ goto done;
+
+ if (MSG_ReadByte() != NETVERSION)
+ {
+ SZ_Clear(&net_message);
+ // save space for the header, filled in later
+ MSG_WriteLong(&net_message, 0);
+ MSG_WriteByte(&net_message, CPREJECT);
+ MSG_WriteString(&net_message, "Incompatible version.\n");
+ *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+ dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
+ SZ_Clear(&net_message);
+ goto done;
+ }
+
+ // see if this guy is already connected
+ for (s = net_activeSockets; s; s = s->next)
+ {
+ if (s->driver != net_driverlevel)
+ continue;
+ if(strcmp(clientaddr.ip, s->addr.ip) != 0 || strcmp(clientaddr.srv, s->addr.srv) != 0)
+ continue;
+ // is this a duplicate connection reqeust?
+ if(strcmp(clientaddr.srv, s->addr.srv) == 0
+ && net_time - s->connecttime < 2.0)
+ {
+ // yes, so send a duplicate reply
+ SZ_Clear(&net_message);
+ // save space for the header, filled in later
+ MSG_WriteLong(&net_message, 0);
+ MSG_WriteByte(&net_message, CPACCEPT);
+ MSG_WriteLong(&net_message, dfunc.GetSocketPort(&myip));
+ *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+ dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
+ SZ_Clear(&net_message);
+ goto done;
+ }
+ // it's somebody coming back in from a crash/disconnect
+ // so close the old qsocket and let their retry get them back in
+ NET_Close(s);
+ goto done;
+ }
+
+ // allocate a QSocket
+ sock = NET_NewQSocket ();
+ if (sock == nil)
+ {
+ // no room; try to let him know
+ SZ_Clear(&net_message);
+ // save space for the header, filled in later
+ MSG_WriteLong(&net_message, 0);
+ MSG_WriteByte(&net_message, CPREJECT);
+ MSG_WriteString(&net_message, "Server is full.\n");
+ *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+ dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
+ SZ_Clear(&net_message);
+ goto done;
+ }
+
+ // allocate a network socket
+ newsock = 1;
+
+ // everything is allocated, just fill in the details
+ sock->socket = newsock;
+ sock->landriver = net_landriverlevel;
+ memcpy(&sock->addr, &clientaddr, sizeof clientaddr);
+ strcpy(sock->address, UDP_AddrToString(&clientaddr));
+
+ // send him back the info about the server connection he has been allocated
+ SZ_Clear(&net_message);
+ // save space for the header, filled in later
+ MSG_WriteLong(&net_message, 0);
+ MSG_WriteByte(&net_message, CPACCEPT);
+ MSG_WriteLong(&net_message, dfunc.GetSocketPort(&myip));
+ *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+ dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
+ SZ_Clear(&net_message);
+
+ return sock;
+done:
+ close(clientaddr.fd);
+ return nil;
+}
+
+qsocket_t *Datagram_CheckNewConnections (void)
+{
+ qsocket_t *ret = nil;
+
+ for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+ if (landrv[net_landriverlevel].initialized)
+ if ((ret = _Datagram_CheckNewConnections ()) != nil)
+ break;
+ return ret;
+}
+
+static qsocket_t *_Datagram_Connect (char *host)
+{
+ Addr sendaddr;
+ Addr readaddr;
+ qsocket_t *sock;
+ int ret = 0;
+ int reps;
+ double start_time;
+ int control;
+ char *reason;
+
+ memset(&sendaddr, 0, sizeof sendaddr);
+ memset(&readaddr, 0, sizeof readaddr);
+
+ // see if we can resolve the host name
+ if (dfunc.getip(host, &sendaddr) == -1){
+ return nil;
+ }
+
+ sock = NET_NewQSocket ();
+ if (sock == nil)
+ goto ErrorReturn2;
+ sock->socket = 1;
+ sock->landriver = net_landriverlevel;
+
+ // connect to the host
+ if (dfunc.Connect(&sendaddr) == -1)
+ goto ErrorReturn;
+ memcpy(&readaddr, &sendaddr, sizeof readaddr);
+
+ // send the connection request
+ Con_Printf("trying...\n"); SCR_UpdateScreen (false);
+ start_time = net_time;
+
+ UDP_Listen(1);
+ for (reps = 0; reps < 3; reps++)
+ {
+ SZ_Clear(&net_message);
+ // save space for the header, filled in later
+ MSG_WriteLong(&net_message, 0);
+ MSG_WriteByte(&net_message, CQCONNECT);
+ MSG_WriteString(&net_message, "QUAKE");
+ MSG_WriteByte(&net_message, NETVERSION);
+ *((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+ dfunc.Write(net_message.data, net_message.cursize, &sendaddr);
+ SZ_Clear(&net_message);
+ do
+ {
+ ret = dfunc.Read(net_message.data, net_message.maxsize, &readaddr);
+ // if we got something, validate it
+ if (ret > 0)
+ {
+ if (ret < sizeof(int))
+ {
+ ret = 0;
+ continue;
+ }
+
+ net_message.cursize = ret;
+ MSG_BeginReading ();
+
+ control = BigLong(*((int *)net_message.data));
+ MSG_ReadLong();
+ if (control == -1)
+ {
+ ret = 0;
+ continue;
+ }
+ if ((control & (~NFMASK)) != NFCTL)
+ {
+ ret = 0;
+ continue;
+ }
+ if ((control & NFMASK) != ret)
+ {
+ ret = 0;
+ continue;
+ }
+ }
+ }
+ while (ret == 0 && (SetNetTime() - start_time) < 2.5);
+ if (ret)
+ break;
+ Con_Printf("still trying...\n"); SCR_UpdateScreen (false);
+ start_time = SetNetTime();
+ }
+ /* bullshit workaround for non-plan9 servers replying from different
+ * ports. because of this workaround, multiple instances on the same
+ * host all require different ports prior to connection. if someone
+ * has a better solution, i'm all ears. */
+ start_time = SetNetTime();
+ do{
+ if(getnewcon(&sendaddr) > 0){
+ close(readaddr.fd);
+ memcpy(&readaddr, &sendaddr, sizeof readaddr);
+ break;
+ }
+ sleep(1);
+ }while(SetNetTime() - start_time < 2.5);
+ UDP_Listen(0);
+
+ if (ret == 0)
+ {
+ reason = "No Response";
+ Con_Printf("%s\n", reason);
+ strcpy(m_return_reason, reason);
+ goto ErrorReturn;
+ }
+
+ if (ret == -1)
+ {
+ reason = "Network Error";
+ Con_Printf("%s\n", reason);
+ strcpy(m_return_reason, reason);
+ goto ErrorReturn;
+ }
+
+ ret = MSG_ReadByte();
+ if (ret == CPREJECT)
+ {
+ reason = MSG_ReadString();
+ Con_Printf(reason);
+ strncpy(m_return_reason, reason, 31);
+ goto ErrorReturn;
+ }
+
+ if (ret == CPACCEPT)
+ {
+ memcpy(&sock->addr, &readaddr, sizeof readaddr);
+ dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
+ }
+ else
+ {
+ reason = "Bad Response";
+ Con_Printf("%s\n", reason);
+ strcpy(m_return_reason, reason);
+ goto ErrorReturn;
+ }
+
+ strcpy(sock->address, dfunc.AddrToString(&sendaddr));
+
+ Con_Printf ("Connection accepted\n");
+ sock->lastMessageTime = SetNetTime();
+
+ m_return_onerror = false;
+ return sock;
+
+ErrorReturn:
+ close(readaddr.fd);
+ NET_FreeQSocket(sock);
+ErrorReturn2:
+ if (m_return_onerror)
+ {
+ key_dest = key_menu;
+ m_state = m_return_state;
+ m_return_onerror = false;
+ }
+ return nil;
+}
+
+qsocket_t *Datagram_Connect (char *host)
+{
+ qsocket_t *ret = nil;
+
+ for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+ if (landrv[net_landriverlevel].initialized)
+ if ((ret = _Datagram_Connect (host)) != nil)
+ break;
+ return ret;
+}
+
+void
+Datagram_Close(qsocket_t *s)
+{
+ close(s->addr.fd);
+}
--- a/net_udp.c
+++ /dev/null
@@ -1,230 +1,0 @@
-#include "quakedef.h"
-#include <ip.h>
-#include <thread.h>
-
-Addr myip;
-
-static int lpid = -1, afd;
-static Channel *lchan;
-
-int
-UDP_Init(void)
-{
- char *s;
- uchar ip[IPaddrlen];
-
- fmtinstall('I', eipfmt);
- if(strcmp(hostname.string, "UNNAMED") == 0)
- if((s = getenv("sysname")) != nil){
- setcvar("hostname", s);
- free(s);
- }
- myipaddr(ip, nil);
- snprint(myip.ip, sizeof myip.ip, "%I", ip);
- snprint(myip.srv, sizeof myip.srv, "%hud", Udpport);
- return 0;
-}
-
-void
-UDP_Shutdown(void)
-{
- UDP_Listen(false);
-}
-
-static void
-lproc(void *)
-{
- int fd, lfd;
- char adir[40], ldir[40], data[100];
-
- snprint(data, sizeof data, "%s/udp!*!%s", netmtpt, myip.srv);
- if((afd = announce(data, adir)) < 0)
- sysfatal("announce: %r");
- for(;;){
- if((lfd = listen(adir, ldir)) < 0
- || (fd = accept(lfd, ldir)) < 0
- || close(lfd) < 0
- || send(lchan, &fd) < 0)
- break;
- }
-}
-
-static void
-udpname(void)
-{
- if((lchan = chancreate(sizeof(int), 0)) == nil)
- sysfatal("chancreate: %r");
- if((lpid = proccreate(lproc, nil, 8192)) < 0)
- sysfatal("proccreate lproc: %r");
-}
-
-void
-UDP_Listen(bool on)
-{
- if(lpid < 0){
- if(on)
- udpname();
- return;
- }
- if(on)
- return;
- close(afd);
- chanclose(lchan);
- threadint(lpid);
- chanfree(lchan);
- lpid = -1;
-}
-
-void
-udpinfo(Addr *a)
-{
- NetConnInfo *nc;
-
- if((nc = getnetconninfo(nil, a->fd)) == nil){
- Con_DPrintf("getnetconninfo: %r\n");
- return;
- }
- strncpy(a->ip, nc->raddr, sizeof(a->ip)-1);
- strncpy(a->srv, nc->rserv, sizeof(a->srv)-1);
- strncpy(a->sys, nc->rsys, sizeof(a->sys)-1);
- free(nc);
-}
-
-int
-UDP_Connect(Addr *a)
-{
- if((a->fd = dial(netmkaddr(a->ip, "udp", a->srv), myip.srv, nil, nil)) < 0){
- Con_DPrintf("dial: %r\n");
- return -1;
- }
- return 0;
-}
-
-int
-getnewcon(Addr *a)
-{
- if(lpid < 0)
- return 0;
- if(nbrecv(lchan, &a->fd) == 0)
- return 0;
- udpinfo(a);
- return 1;
-}
-
-int
-udpread(byte *buf, int len, Addr *a)
-{
- int n;
-
- if(flen(a->fd) < 1)
- return 0;
- if((n = read(a->fd, buf, len)) <= 0){
- Con_DPrintf("udpread: %r\n");
- return -1;
- }
- return n;
-}
-
-int
-udpwrite(uchar *buf, int len, Addr *a)
-{
- if(write(a->fd, buf, len) != len){
- Con_DPrintf("udpwrite: %r\n");
- return -1;
- }
- return len;
-}
-
-char *
-UDP_AddrToString(Addr *a)
-{
- char *p;
- static char buf[52];
-
- strncpy(buf, a->sys, sizeof(buf)-1);
- if((p = strrchr(buf, '!')) != nil)
- *p = ':';
- return buf;
-}
-
-int
-UDP_Broadcast(uchar *buf, int len)
-{
- int fd;
- char ip[46];
-
- snprint(ip, sizeof ip, "%I", IPv4bcast);
- if((fd = dial(netmkaddr(ip, "udp", myip.srv), myip.srv, nil, nil)) < 0){
- Con_DPrintf("UDP_Broadcast: %r\n");
- return -1;
- }
- if(write(fd, buf, len) != len)
- Con_DPrintf("write: %r\n");
- close(fd);
- return 0;
-}
-
-int
-getip(char *s, Addr *a)
-{
- int fd, n;
- char buf[128], *f[4], *p;
-
- snprint(buf, sizeof buf, "%s/cs", netmtpt);
- if((fd = open(buf, ORDWR)) < 0)
- sysfatal("open: %r");
-
- if((p = strrchr(s, '!')) == nil)
- p = myip.srv;
- else
- p++;
- snprint(buf, sizeof buf, "udp!%s!%s", s, p);
- n = strlen(buf);
- if(write(fd, buf, n) != n){
- Con_DPrintf("translating %s: %r\n", s);
- return -1;
- }
- seek(fd, 0, 0);
- if((n = read(fd, buf, sizeof(buf)-1)) <= 0){
- Con_DPrintf("reading cs tables: %r");
- return -1;
- }
- buf[n] = 0;
- close(fd);
- if(getfields(buf, f, 4, 0, " !") < 2)
- goto err;
- strncpy(a->ip, f[1], sizeof(a->ip)-1);
- a->ip[sizeof(a->ip)-1] = 0;
- strncpy(a->srv, f[2], sizeof(a->srv)-1);
- a->srv[sizeof(a->srv)-1] = 0;
- snprint(a->sys, sizeof a->sys, "%s!%s", a->ip, a->srv);
- return 0;
-err:
- Con_DPrintf("bad cs entry %s", buf);
- return -1;
-}
-
-int
-UDP_AddrCompare(Addr *a1, Addr *a2)
-{
- if(strcmp(a1->ip, a2->ip) != 0)
- return -1;
- if(strcmp(a1->srv, a2->srv) != 0)
- return 1;
- return 0;
-}
-
-ushort
-UDP_GetSocketPort(Addr *a)
-{
- ushort p;
-
- p = atoi(a->srv);
- return p;
-}
-
-void
-UDP_SetSocketPort(Addr *a, ushort port)
-{
- snprint(a->srv, sizeof a->srv, "%hud", port); /* was htons'ed */
-}
--- /dev/null
+++ b/net_udp_plan9.c
@@ -1,0 +1,230 @@
+#include "quakedef.h"
+#include <ip.h>
+#include <thread.h>
+
+Addr myip;
+
+static int lpid = -1, afd;
+static Channel *lchan;
+
+int
+UDP_Init(void)
+{
+ char *s;
+ uchar ip[IPaddrlen];
+
+ fmtinstall('I', eipfmt);
+ if(strcmp(hostname.string, "UNNAMED") == 0)
+ if((s = getenv("sysname")) != nil){
+ setcvar("hostname", s);
+ free(s);
+ }
+ myipaddr(ip, nil);
+ snprint(myip.ip, sizeof myip.ip, "%I", ip);
+ snprint(myip.srv, sizeof myip.srv, "%hud", Udpport);
+ return 0;
+}
+
+void
+UDP_Shutdown(void)
+{
+ UDP_Listen(false);
+}
+
+static void
+lproc(void *)
+{
+ int fd, lfd;
+ char adir[40], ldir[40], data[100];
+
+ snprint(data, sizeof data, "%s/udp!*!%s", netmtpt, myip.srv);
+ if((afd = announce(data, adir)) < 0)
+ sysfatal("announce: %r");
+ for(;;){
+ if((lfd = listen(adir, ldir)) < 0
+ || (fd = accept(lfd, ldir)) < 0
+ || close(lfd) < 0
+ || send(lchan, &fd) < 0)
+ break;
+ }
+}
+
+static void
+udpname(void)
+{
+ if((lchan = chancreate(sizeof(int), 0)) == nil)
+ sysfatal("chancreate: %r");
+ if((lpid = proccreate(lproc, nil, 8192)) < 0)
+ sysfatal("proccreate lproc: %r");
+}
+
+void
+UDP_Listen(bool on)
+{
+ if(lpid < 0){
+ if(on)
+ udpname();
+ return;
+ }
+ if(on)
+ return;
+ close(afd);
+ chanclose(lchan);
+ threadint(lpid);
+ chanfree(lchan);
+ lpid = -1;
+}
+
+void
+udpinfo(Addr *a)
+{
+ NetConnInfo *nc;
+
+ if((nc = getnetconninfo(nil, a->fd)) == nil){
+ Con_DPrintf("getnetconninfo: %r\n");
+ return;
+ }
+ strncpy(a->ip, nc->raddr, sizeof(a->ip)-1);
+ strncpy(a->srv, nc->rserv, sizeof(a->srv)-1);
+ strncpy(a->sys, nc->rsys, sizeof(a->sys)-1);
+ free(nc);
+}
+
+int
+UDP_Connect(Addr *a)
+{
+ if((a->fd = dial(netmkaddr(a->ip, "udp", a->srv), myip.srv, nil, nil)) < 0){
+ Con_DPrintf("dial: %r\n");
+ return -1;
+ }
+ return 0;
+}
+
+int
+getnewcon(Addr *a)
+{
+ if(lpid < 0)
+ return 0;
+ if(nbrecv(lchan, &a->fd) == 0)
+ return 0;
+ udpinfo(a);
+ return 1;
+}
+
+int
+udpread(byte *buf, int len, Addr *a)
+{
+ int n;
+
+ if(flen(a->fd) < 1)
+ return 0;
+ if((n = read(a->fd, buf, len)) <= 0){
+ Con_DPrintf("udpread: %r\n");
+ return -1;
+ }
+ return n;
+}
+
+int
+udpwrite(uchar *buf, int len, Addr *a)
+{
+ if(write(a->fd, buf, len) != len){
+ Con_DPrintf("udpwrite: %r\n");
+ return -1;
+ }
+ return len;
+}
+
+char *
+UDP_AddrToString(Addr *a)
+{
+ char *p;
+ static char buf[52];
+
+ strncpy(buf, a->sys, sizeof(buf)-1);
+ if((p = strrchr(buf, '!')) != nil)
+ *p = ':';
+ return buf;
+}
+
+int
+UDP_Broadcast(uchar *buf, int len)
+{
+ int fd;
+ char ip[46];
+
+ snprint(ip, sizeof ip, "%I", IPv4bcast);
+ if((fd = dial(netmkaddr(ip, "udp", myip.srv), myip.srv, nil, nil)) < 0){
+ Con_DPrintf("UDP_Broadcast: %r\n");
+ return -1;
+ }
+ if(write(fd, buf, len) != len)
+ Con_DPrintf("write: %r\n");
+ close(fd);
+ return 0;
+}
+
+int
+getip(char *s, Addr *a)
+{
+ int fd, n;
+ char buf[128], *f[4], *p;
+
+ snprint(buf, sizeof buf, "%s/cs", netmtpt);
+ if((fd = open(buf, ORDWR)) < 0)
+ sysfatal("open: %r");
+
+ if((p = strrchr(s, '!')) == nil)
+ p = myip.srv;
+ else
+ p++;
+ snprint(buf, sizeof buf, "udp!%s!%s", s, p);
+ n = strlen(buf);
+ if(write(fd, buf, n) != n){
+ Con_DPrintf("translating %s: %r\n", s);
+ return -1;
+ }
+ seek(fd, 0, 0);
+ if((n = read(fd, buf, sizeof(buf)-1)) <= 0){
+ Con_DPrintf("reading cs tables: %r");
+ return -1;
+ }
+ buf[n] = 0;
+ close(fd);
+ if(getfields(buf, f, 4, 0, " !") < 2)
+ goto err;
+ strncpy(a->ip, f[1], sizeof(a->ip)-1);
+ a->ip[sizeof(a->ip)-1] = 0;
+ strncpy(a->srv, f[2], sizeof(a->srv)-1);
+ a->srv[sizeof(a->srv)-1] = 0;
+ snprint(a->sys, sizeof a->sys, "%s!%s", a->ip, a->srv);
+ return 0;
+err:
+ Con_DPrintf("bad cs entry %s", buf);
+ return -1;
+}
+
+int
+UDP_AddrCompare(Addr *a1, Addr *a2)
+{
+ if(strcmp(a1->ip, a2->ip) != 0)
+ return -1;
+ if(strcmp(a1->srv, a2->srv) != 0)
+ return 1;
+ return 0;
+}
+
+ushort
+UDP_GetSocketPort(Addr *a)
+{
+ ushort p;
+
+ p = atoi(a->srv);
+ return p;
+}
+
+void
+UDP_SetSocketPort(Addr *a, ushort port)
+{
+ snprint(a->srv, sizeof a->srv, "%hud", port); /* was htons'ed */
+}
--- /dev/null
+++ b/net_udp_unix.c
@@ -1,0 +1,361 @@
+#include "quakedef.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+extern cvar_t hostname;
+
+static int net_acceptsocket = -1; // socket for fielding new connections
+static int net_controlsocket;
+static int net_broadcastsocket = 0;
+static Addr broadcastaddr;
+
+static unsigned long myAddr;
+Addr myip;
+
+static int UDP_OpenSocket (int port);
+static int UDP_GetSocketAddr (int socket, Addr *addr);
+static int UDP_CloseSocket (int socket);
+
+//=============================================================================
+
+int UDP_Init (void)
+{
+ struct hostent *local;
+ char buff[MAXHOSTNAMELEN];
+
+ // determine my name & address
+ gethostname(buff, MAXHOSTNAMELEN);
+ local = gethostbyname(buff);
+ myAddr = *(int *)local->h_addr_list[0];
+
+ // if the quake hostname isn't set, set it to the machine name
+ if (strcmp(hostname.string, "UNNAMED") == 0)
+ {
+ buff[15] = 0;
+ setcvar ("hostname", buff);
+ }
+
+ if ((net_controlsocket = UDP_OpenSocket (0)) == -1)
+ Host_Error("UDP_Init: Unable to open control socket\n");
+
+ ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
+ ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(Udpport);
+
+ UDP_GetSocketAddr (net_controlsocket, &myip);
+
+ return net_controlsocket;
+}
+
+//=============================================================================
+
+void UDP_Shutdown (void)
+{
+ UDP_Listen (false);
+ UDP_CloseSocket (net_controlsocket);
+}
+
+//=============================================================================
+
+void UDP_Listen (bool state)
+{
+ // enable listening
+ if (state)
+ {
+ if (net_acceptsocket != -1)
+ return;
+ if ((net_acceptsocket = UDP_OpenSocket (Udpport)) == -1)
+ Host_Error ("UDP_Listen: Unable to open accept socket\n");
+ return;
+ }
+
+ // disable listening
+ if (net_acceptsocket == -1)
+ return;
+ UDP_CloseSocket (net_acceptsocket);
+ net_acceptsocket = -1;
+}
+
+//=============================================================================
+
+static int UDP_OpenSocket (int port)
+{
+ int newsocket;
+ struct sockaddr_in address;
+
+ if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ return -1;
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(port);
+ if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
+ goto ErrorReturn;
+
+ return newsocket;
+
+ErrorReturn:
+ close (newsocket);
+ return -1;
+}
+
+//=============================================================================
+
+static int UDP_CloseSocket (int socket)
+{
+ if (socket == net_broadcastsocket)
+ net_broadcastsocket = 0;
+ return close (socket);
+}
+
+//=============================================================================
+/*
+============
+PartialIPAddress
+
+this lets you type only as much of the net address as required, using
+the local network components to fill in the rest
+============
+*/
+static int PartialIPAddress (char *in, Addr *hostaddr)
+{
+ char buff[256];
+ char *b;
+ int addr;
+ int num;
+ int mask;
+ int run;
+ int port;
+
+ buff[0] = '.';
+ b = buff;
+ strcpy(buff+1, in);
+ if (buff[1] == '.')
+ b++;
+
+ addr = 0;
+ mask=-1;
+ while (*b == '.')
+ {
+ b++;
+ num = 0;
+ run = 0;
+ while (!( *b < '0' || *b > '9'))
+ {
+ num = num*10 + *b++ - '0';
+ if (++run > 3)
+ return -1;
+ }
+ if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
+ return -1;
+ if (num < 0 || num > 255)
+ return -1;
+ mask<<=8;
+ addr = (addr<<8) + num;
+ }
+
+ if (*b++ == ':')
+ port = strtol(b, NULL, 0);
+ else
+ port = Udpport;
+
+ ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
+ ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
+
+ return 0;
+}
+//=============================================================================
+
+int UDP_Connect (Addr *addr)
+{
+ USED(addr);
+ return 0;
+}
+
+//=============================================================================
+
+int UDP_CheckNewConnections (void)
+{
+ unsigned long available;
+
+ if (net_acceptsocket == -1)
+ return -1;
+
+ if (ioctl (net_acceptsocket, FIONREAD, &available) == -1)
+ Host_Error ("UDP: ioctlsocket (FIONREAD) failed\n");
+ if (available)
+ return net_acceptsocket;
+ return -1;
+}
+
+//=============================================================================
+
+int UDP_Read (int socket, uint8_t *buf, int len, Addr *addr)
+{
+ socklen_t addrlen = sizeof (Addr);
+ int ret;
+
+ ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
+ if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED))
+ return 0;
+ return ret;
+}
+
+//=============================================================================
+
+int UDP_MakeSocketBroadcastCapable (int socket)
+{
+ int i = 1;
+
+ // make this socket broadcast capable
+ if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
+ return -1;
+ net_broadcastsocket = socket;
+
+ return 0;
+}
+
+//=============================================================================
+
+static int UDP_Write (int socket, uint8_t *buf, int len, Addr *addr)
+{
+ int ret;
+
+ ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(Addr));
+ if (ret == -1 && errno == EWOULDBLOCK)
+ return 0;
+ return ret;
+}
+
+//=============================================================================
+
+int UDP_Broadcast (int socket, uint8_t *buf, int len)
+{
+ int ret;
+
+ if (socket != net_broadcastsocket)
+ {
+ if (net_broadcastsocket != 0)
+ Host_Error("Attempted to use multiple broadcasts sockets\n");
+ ret = UDP_MakeSocketBroadcastCapable (socket);
+ if (ret == -1)
+ {
+ Con_Printf("Unable to make socket broadcast capable\n");
+ return ret;
+ }
+ }
+
+ return UDP_Write (socket, buf, len, &broadcastaddr);
+}
+
+//=============================================================================
+
+char *UDP_AddrToString (Addr *addr)
+{
+ static char buffer[22];
+ int haddr;
+
+ haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
+ sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
+ return buffer;
+}
+
+//=============================================================================
+
+int UDP_StringToAddr (char *string, Addr *addr)
+{
+ int ha1, ha2, ha3, ha4, hp;
+ int ipaddr;
+
+ sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
+ ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
+
+ ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
+ ((struct sockaddr_in *)addr)->sin_port = htons(hp);
+ return 0;
+}
+
+//=============================================================================
+
+static int UDP_GetSocketAddr (int socket, Addr *addr)
+{
+ socklen_t addrlen = sizeof(Addr);
+ unsigned int a;
+
+ memset(addr, 0, sizeof(Addr));
+ getsockname(socket, (struct sockaddr *)addr, &addrlen);
+ a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
+ if (a == 0 || a == inet_addr("127.0.0.1"))
+ ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
+
+ return 0;
+}
+
+//=============================================================================
+
+int UDP_GetNameFromAddr (Addr *addr, char *name)
+{
+ struct hostent *hostentry;
+
+ hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
+ if (hostentry)
+ {
+ strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
+ return 0;
+ }
+
+ strcpy (name, UDP_AddrToString (addr));
+ return 0;
+}
+
+//=============================================================================
+
+int UDP_GetAddrFromName(char *name, Addr *addr)
+{
+ struct hostent *hostentry;
+
+ if (name[0] >= '0' && name[0] <= '9')
+ return PartialIPAddress (name, addr);
+
+ hostentry = gethostbyname (name);
+ if (!hostentry)
+ return -1;
+
+ ((struct sockaddr_in *)addr)->sin_port = htons(Udpport);
+ ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
+
+ return 0;
+}
+
+//=============================================================================
+
+int UDP_AddrCompare (Addr *addr1, Addr *addr2)
+{
+ if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
+ return -1;
+
+ if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
+ return 1;
+
+ return 0;
+}
+
+//=============================================================================
+
+u16int UDP_GetSocketPort (Addr *addr)
+{
+ return ntohs(((struct sockaddr_in *)addr)->sin_port);
+}
+
+void UDP_SetSocketPort (Addr *addr, u16int port)
+{
+ ((struct sockaddr_in *)addr)->sin_port = htons(port);
+}
+
+//=============================================================================
--- a/qk1.c
+++ /dev/null
@@ -1,168 +1,0 @@
-#include "quakedef.h"
-#include <thread.h>
-
-int mainstacksize = 1*1024*1024;
-char *netmtpt = "/net";
-char *game;
-int debug;
-
-int
-sys_mkdir(char *path)
-{
- int d;
-
- if(access(path, AEXIST) == 0)
- return 0;
- if((d = create(path, OREAD, DMDIR|0777)) < 0){
- Con_DPrintf("Sys_mkdir: create: %r\n");
- return -1;
- }
- close(d);
- return 0;
-}
-
-char *
-sys_timestamp(void)
-{
- static char ts[32];
- Tm *tm;
- long t;
-
- if((t = time(nil)) < 0 || (tm = localtime(t)) == nil)
- return nil;
- snprint(ts, sizeof(ts),
- "%04d%02d%02d-%02d%02d%02d",
- tm->year + 1900, tm->mon + 1, tm->mday, tm->hour, tm->min, tm->sec
- );
-
- return ts;
-}
-
-char *
-lerr(void)
-{
- static char err[ERRMAX];
- rerrstr(err, sizeof(err));
- return err;
-}
-
-_Noreturn void
-fatal(char *fmt, ...)
-{
- char s[1024];
- va_list arg;
-
- va_start(arg, fmt);
- vseprint(s, s+sizeof s, fmt, arg);
- va_end(arg);
- Host_Shutdown();
- sysfatal("%s", s);
-}
-
-void *
-emalloc(long n)
-{
- void *p;
-
- if(p = mallocz(n, 1), p == nil)
- sysfatal("emalloc %r");
- setmalloctag(p, getcallerpc(&n));
- return p;
-}
-
-vlong
-flen(int fd)
-{
- vlong l;
- Dir *d;
-
- if((d = dirfstat(fd)) == nil) /* file assumed extant and readable */
- sysfatal("flen: %r");
- l = d->length;
- free(d);
- return l;
-}
-
-double
-dtime(void)
-{
- return nanosec() / 1000000000.0;
-}
-
-void
-game_shutdown(void)
-{
- stopfb();
- Host_Shutdown();
- threadexitsall(nil);
-}
-
-static void
-croak(void *, char *note)
-{
- if(strncmp(note, "sys:", 4) == 0){
- IN_Grabm(0);
- threadkillgrp(0);
- }
- noted(NDFLT);
-}
-
-static void
-usage(void)
-{
- fprint(2, "usage: %s [-d] [-g game] [-m kB] [-x netmtpt]\n", argv0);
- exits("usage");
-}
-
-void
-threadmain(int argc, char **argv)
-{
- double t, t´, Δt;
- char *e;
- static char *paths[] = {
- "/sys/games/lib/quake",
- nil,
- nil,
- };
-
- ARGBEGIN{
- case 'D':
- debug = 1;
- break;
- case 'd':
- dedicated = 1;
- break;
- case 'g':
- game = EARGF(usage());
- break;
- case 'x':
- netmtpt = EARGF(usage());
- break;
- default: usage();
- }ARGEND
- srand(getpid());
- /* ignore fp exceptions: rendering shit assumes they are */
- setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV));
- notify(croak);
-
- e = getenv("home");
- paths[1] = smprint("%s/lib/quake", e);
- free(e);
- Host_Init(argc, argv, paths);
-
- t = dtime() - 1.0 / Fpsmax;
- for(;;){
- t´ = dtime();
- Δt = t´ - t;
- if(cls.state == ca_dedicated){
- if(Δt < sys_ticrate.value)
- continue;
- Δt = sys_ticrate.value;
- }
- if(Δt > sys_ticrate.value * 2)
- t = t´;
- else
- t += Δt;
- Host_Frame(Δt);
- }
-}
--- /dev/null
+++ b/seprint.c
@@ -1,0 +1,19 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+char *
+seprint(char *buf, char *e, char *fmt, ...)
+{
+ va_list a;
+ int n, m;
+
+ if(e <= buf)
+ return e;
+
+ va_start(a, fmt);
+ m = e-buf-1;
+ n = vsnprintf(buf, m, fmt, a);
+ va_end(a);
+
+ return buf + (n < m ? n : m);
+}
--- a/snd.c
+++ /dev/null
@@ -1,689 +1,0 @@
-#include "quakedef.h"
-
-cvar_t volume = {"volume", "0.7", 1};
-
-typedef struct Chan Chan;
-
-enum{
- Srate = 44100,
- Ssize = 2,
- Sch = 2,
- Sblk = Ssize * Sch,
- Ssamp = Srate / Fpsmin,
-
- Nchan = 256,
- Ndyn = 8,
- Sstat = Ndyn + Namb
-};
-static float Clipdist = 1000.0;
-
-struct Chan{
- Sfx *sfx;
- int chvol;
- int lvol;
- int rvol;
- vec_t attf;
- vec3_t zp;
- int entn;
- int entch;
- int p;
- int n;
-};
-
-static Chan *chans, *che;
-
-static int ainit, mixbufi;
-static uchar mixbufs[2][Ssamp*Sblk], *mixbuf;
-static vlong sndt, sampt;
-static int nsamp;
-static int sampbuf[Ssamp*2];
-static int scalt[32][256];
-
-static Sfx *ambsfx[Namb];
-
-typedef struct
-{
- int length;
- int speed;
- int width;
- int stereo;
- int loop;
- byte data[1]; // variable sized
-} sfxcache_t;
-
-static vec3_t listener_origin;
-static vec3_t listener_forward;
-static vec3_t listener_right;
-static vec3_t listener_up;
-static Sfx *known_sfx; // hunk allocated
-static int num_sfx;
-static int map;
-
-static cvar_t precache = {"precache", "1"};
-static cvar_t loadas8bit = {"loadas8bit", "0"};
-static cvar_t ambient_level = {"ambient_level", "0.3"};
-static cvar_t ambient_fade = {"ambient_fade", "100"};
-
-static byte *data_p;
-static byte *iff_end;
-static byte *last_chunk;
-static byte *iff_data;
-
-/* TODO: refuctor wav loading */
-static void
-resample(sfxcache_t *sc, byte *data, float stepscale)
-{
- int inwidth;
- int outcount;
- int srcsample;
- int i;
- int sample, samplefrac, fracstep;
-
- inwidth = sc->width;
- outcount = sc->length / stepscale;
- sc->length = outcount;
- sc->speed = Srate;
- if (loadas8bit.value)
- sc->width = 1;
- else
- sc->width = inwidth;
- sc->stereo = 0;
-
- if (stepscale == 1 && inwidth == 1 && sc->width == 1)
- {
-// fast special case
- for (i=0 ; i<outcount ; i++)
- ((signed char *)sc->data)[i]
- = (int)( (unsigned char)(data[i]) - 128);
- }
- else
- {
-// general case
- samplefrac = 0;
- fracstep = stepscale*256;
- for (i=0 ; i<outcount ; i++)
- {
- srcsample = samplefrac >> 8;
- samplefrac += fracstep;
- if (inwidth == 2)
- sample = LittleShort ( ((short *)data)[srcsample] );
- else
- sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
- if (sc->width == 2)
- ((short *)sc->data)[i] = sample;
- else
- ((signed char *)sc->data)[i] = sample >> 8;
- }
- }
-}
-
-static sfxcache_t *
-loadsfx(Sfx *sfx)
-{
- wavinfo_t info;
- int len;
- float stepscale;
- sfxcache_t *sc;
- uchar *u, buf[1024]; /* avoid dirtying the cache heap */
-
- if(sc = Cache_Check(&sfx->cu), sc != nil)
- return sc;
- u = loadstklmp(va("sound/%s", sfx->s), buf, sizeof buf, &len);
- if(u == nil){
- Con_DPrintf("loadsfx: %r\n");
- return nil;
- }
- if(wavinfo(u, len, &info) != 0){
- Con_Printf("loadsfx: %s: %s\n", sfx->s, lerr());
- return nil;
- }
- if(info.channels != 1){
- Con_DPrintf("loadsfx: non mono wave %s\n", sfx->s);
- return nil;
- }
- stepscale = (float)info.rate / Srate;
- len = info.samples / stepscale;
- len *= info.width * info.channels;
- if(sc = Cache_Alloc(&sfx->cu, len + sizeof *sc), sc == nil)
- return nil;
- sc->length = info.samples;
- sc->loop = info.loopofs;
- if(info.loopofs >= 0)
- sc->loop /= stepscale;
- sc->speed = info.rate;
- sc->width = info.width;
- sc->stereo = info.channels;
- resample(sc, u + info.dataofs, stepscale);
- return sc;
-}
-
-static void
-sndout(void)
-{
- int v, *pb, *pe;
- uchar *p;
- double vol;
-
- vol = volume.value;
- p = mixbuf;
- pb = sampbuf;
- pe = sampbuf + nsamp * 2;
- while(pb < pe){
- v = *pb++ * vol;
- if(v > 0x7fff)
- v = 0x7fff;
- else if(v < -0x8000)
- v = -0x8000;
- p[0] = v;
- p[1] = v >> 8;
- p += 2;
- }
-}
-
-static void
-sample8(Chan *c, void *d, int n)
-{
- int v, *pb, *pe, *ls, *rs;
- uchar *p;
-
- if(c->lvol > 255)
- c->lvol = 255;
- if(c->rvol > 255)
- c->rvol = 255;
- ls = scalt[c->lvol >> 3];
- rs = scalt[c->rvol >> 3];
- p = (uchar *)d + c->p;
- pb = sampbuf;
- pe = sampbuf + n * 2;
- while(pb < pe){
- v = *p++;
- *pb++ += ls[v];
- *pb++ += rs[v];
- }
-}
-
-static void
-sample16(Chan *c, void *d, int n)
-{
- int v, *pb, *pe, lv, rv;
- short *p;
-
- lv = c->lvol;
- rv = c->rvol;
- p = (short *)d + c->p;
- pb = sampbuf;
- pe = sampbuf + n * 2;
- while(pb < pe){
- v = *p++;
- *pb++ += v * lv >> 8;
- *pb++ += v * rv >> 8;
- }
-}
-
-static void
-samplesfx(void)
-{
- int n, m;
- Chan *c;
- sfxcache_t *sc;
- void (*sf)(Chan *, void *, int);
-
- memset(sampbuf, 0, sizeof sampbuf);
- for(c=chans; c<che; c++){
- if(c->sfx == nil)
- continue;
- if(c->lvol == 0 && c->rvol == 0)
- continue;
- if(sc = loadsfx(c->sfx), sc == nil)
- continue;
- sf = sc->width == 1 ? sample8 : sample16;
- n = nsamp;
- while(n > 0){
- m = n < c->n ? n : c->n;
- if(m > 0)
- sf(c, sc->data, m);
- c->p += m;
- c->n -= m;
- n -= m;
- if(c->n <= 0){
- if(sc->loop >= 0){
- c->p = sc->loop;
- c->n = sc->length - c->p;
- }else{
- c->sfx = nil;
- break;
- }
- }
- }
- }
- sndout();
-}
-
-static void
-spatialize(Chan *c)
-{
- vec_t Δr, m;
- vec3_t src;
-
- if(c->entn == cl.viewentity){
- c->lvol = c->chvol;
- c->rvol = c->chvol;
- return;
- }
- VectorSubtract(c->zp, listener_origin, src);
- Δr = 1.0 - VectorNormalize(src) * c->attf;
- m = DotProduct(listener_right, src);
- c->rvol = Δr * (1.0 + m) * c->chvol;
- if(c->rvol < 0)
- c->rvol = 0;
- c->lvol = Δr * (1.0 - m) * c->chvol;
- if(c->lvol < 0)
- c->lvol = 0;
-}
-
-static void
-ambs(void)
-{
- uchar *av;
- float vol;
- Chan *c, *e;
- mleaf_t *l;
- Sfx **sfx;
-
- if(cl.worldmodel == nil)
- return;
- c = chans;
- e = chans + Namb;
- l = Mod_PointInLeaf(listener_origin, cl.worldmodel);
- if(l == nil || !ambient_level.value){
- while(c < e)
- c++->sfx = nil;
- return;
- }
- sfx = ambsfx;
- av = l->ambient_sound_level;
- while(c < e){
- c->sfx = *sfx++;
- vol = ambient_level.value * *av++;
- if(vol < 8)
- vol = 0;
- if(c->chvol < vol){
- c->chvol += host_frametime * ambient_fade.value;
- if(c->chvol > vol)
- c->chvol = vol;
- }else if(c->chvol > vol){
- c->chvol -= host_frametime * ambient_fade.value;
- if(c->chvol < vol)
- c->chvol = vol;
- }
- c->lvol = c->chvol;
- c->rvol = c->chvol;
- c++;
- }
-}
-
-void
-stepsnd(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
-{
- long ns;
- Chan *c, *sum;
-
- if(!ainit)
- return;
-
- if(sndt == 0)
- sndt = nanosec() - Te9 / Fpsmax;
- nsamp = (nanosec() - sndt) / (Te9 / Srate);
- if(!cls.timedemo)
- nsamp = (nsamp + 15) & ~15;
- nsamp -= sndqueued()/Sblk - Srate/Fpsmax;
- if(nsamp < 1)
- return;
- if(nsamp > Ssamp)
- nsamp = Ssamp;
- ns = nsamp * Sblk;
- mixbuf = mixbufs[mixbufi];
- samplesfx();
- sampt += nsamp;
- if(ns != 0){
- sndwrite(mixbuf, ns);
- mixbufi = (mixbufi + 1) % nelem(mixbufs);
- }
- sndt = nanosec();
-
- VectorCopy(origin, listener_origin);
- VectorCopy(forward, listener_forward);
- VectorCopy(right, listener_right);
- VectorCopy(up, listener_up);
- ambs();
- sum = nil;
- for(c=chans+Namb; c<che; c++){
- if(c->sfx == nil)
- continue;
- spatialize(c);
- if(c->lvol == 0 && c->rvol == 0)
- continue;
- /* sum static sounds to avoid useless remixing */
- if(c >= chans + Sstat){
- if(sum != nil && sum->sfx == c->sfx){
- sum->lvol += c->lvol;
- sum->rvol += c->rvol;
- c->lvol = c->rvol = 0;
- continue;
- }
- for(sum=chans + Sstat; sum<c; sum++)
- if(sum->sfx == c->sfx)
- break;
- if(sum == che)
- sum = nil;
- else if(sum != c){
- sum->lvol += c->lvol;
- sum->rvol += c->rvol;
- c->lvol = c->rvol = 0;
- }
- }
- }
-}
-
-void
-stopallsfx(void)
-{
- if(!ainit)
- return;
- memset(chans, 0, sizeof(*chans)*Nchan);
- che = chans + Sstat;
- sndstop();
-}
-
-void
-stopsfx(int n, int ch)
-{
- Chan *c, *e;
-
- if(!ainit)
- return;
- c = chans;
- e = chans + Ndyn;
- while(c < e){
- if(c->entn == n && c->entch == ch){
- c->sfx = nil;
- return;
- }
- c++;
- }
-}
-
-static Chan *
-pickchan(int entn, int entch)
-{
- int Δt;
- Chan *c, *p, *e;
-
- p = nil;
- Δt = 0x7fffffff;
- for(c=chans+Namb, e=c+Ndyn; c<e; c++){
- if(entch != 0 && c->entn == entn
- && (c->entch == entch || entch == -1)){
- p = c;
- break;
- }
- if(c->entn == cl.viewentity && entn != cl.viewentity && c->sfx != nil)
- continue;
- if(c->n < Δt){
- Δt = c->n;
- p = c;
- }
- }
- if(p != nil)
- p->sfx = nil;
- return p;
-}
-
-void
-startsfx(int entn, int entch, Sfx *sfx, vec3_t zp, float vol, float att)
-{
- int skip;
- Chan *c, *c2, *e;
- sfxcache_t *sc;
-
- if(!ainit || sfx == nil)
- return;
- if(c = pickchan(entn, entch), c == nil)
- return;
- memset(c, 0, sizeof *c);
- VectorCopy(zp, c->zp);
- c->attf = att / Clipdist;
- c->chvol = vol * 255;
- c->entn = entn;
- c->entch = entch;
- spatialize(c);
- if(c->lvol == 0 && c->rvol == 0)
- return;
- if(sc = loadsfx(sfx), sc == nil)
- return;
- c->sfx = sfx;
- c->p = 0;
- c->n = sc->length;
- /* don't sum identical sfx started on the same frame */
- for(c2=chans+Namb, e=chans+Sstat; c2<e; c2++){
- if(c2 == c || c2->sfx != sfx || c2->p != 0)
- continue;
- skip = nrand(Srate / Fpsmin);
- if(skip >= c->n)
- skip = c->n - 1;
- c->p += skip;
- c->n -= skip;
- break;
- }
-}
-
-void
-localsfx(char *s)
-{
- Sfx *sfx;
-
- if(!ainit)
- return;
- sfx = precachesfx(s);
- startsfx(cl.viewentity, -1, sfx, vec3_origin, 1, 1);
-}
-
-void
-staticsfx(Sfx *sfx, vec3_t zp, float vol, float att)
-{
- Chan *c;
- sfxcache_t *sc;
-
- if(sfx == nil || che >= chans+Nchan)
- return;
- c = che++;
- if(sc = loadsfx(sfx), sc == nil)
- return;
- if(sc->loop < 0){
- Con_DPrintf("staticsfx %s: nonlooped static sound\n", sfx->s);
- return;
- }
- c->sfx = sfx;
- VectorCopy(zp, c->zp);
- c->chvol = vol * 255;
- c->attf = att / Clipdist;
- c->n = sc->length;
- spatialize(c);
-}
-
-static Sfx *
-findsfx(char *s)
-{
- Sfx *sfx, *e;
-
- if(strlen(s) >= Npath)
- Host_Error("findsfx: path too long %s", s);
- sfx = known_sfx;
- e = known_sfx + num_sfx;
- while(sfx < e){
- if(strcmp(sfx->s, s) == 0)
- return sfx;
- sfx++;
- }
- if(num_sfx == MAX_SOUNDS){
- sfx = known_sfx;
- while(sfx < e){
- if(sfx->map && sfx->map < map)
- break;
- sfx++;
- }
- if(sfx == e)
- Host_Error("findsfx: sfx list overflow: %s", s);
- if(Cache_Check(&sfx->cu))
- Cache_Free(&sfx->cu);
- }else
- num_sfx++;
- strcpy(sfx->s, s);
- return sfx;
-}
-
-void
-touchsfx(char *s)
-{
- Sfx *sfx;
-
- if(!ainit)
- return;
- sfx = findsfx(s);
- Cache_Check(&sfx->cu);
-}
-
-Sfx *
-precachesfx(char *s)
-{
- Sfx *sfx;
-
- if(!ainit)
- return nil;
- sfx = findsfx(s);
- sfx->map = map;
- if(precache.value)
- loadsfx(sfx);
- return sfx;
-}
-
-static void
-playsfx(void)
-{
- static int hash = 345;
- int i;
- char *s;
- Sfx *sfx;
-
- if(Cmd_Argc() < 2){
- Con_Printf("play wav [wav..]: play a wav lump\n");
- return;
- }
- i = 1;
- while(i < Cmd_Argc()){
- if(strrchr(Cmd_Argv(i), '.') == nil)
- s = va("%s.wav", Cmd_Argv(i));
- else
- s = Cmd_Argv(i);
- sfx = precachesfx(s);
- startsfx(hash++, 0, sfx, listener_origin, 1.0, 1.0);
- i++;
- }
-}
-
-static void
-playvolsfx(void)
-{
- static int hash = 543;
- int i;
- float vol;
- char *s;
- Sfx *sfx;
-
- if(Cmd_Argc() < 3){
- Con_Printf("play wav vol [wav vol]..: play an amplified wav lump\n");
- return;
- }
- i = 1;
- while(i < Cmd_Argc()){
- if(strrchr(Cmd_Argv(i), '.') == nil)
- s = va("%s.wav", Cmd_Argv(i));
- else
- s = Cmd_Argv(i);
- sfx = precachesfx(s);
- vol = atof(Cmd_Argv(++i));
- startsfx(hash++, 0, sfx, listener_origin, vol, 1.0);
- i++;
- }
-}
-
-static void
-sfxlist(void)
-{
- char c;
- int sz, sum;
- Sfx *sfx, *e;
- sfxcache_t *sc;
-
- sum = 0;
- for(sfx=known_sfx, e=known_sfx+num_sfx; sfx<e; sfx++){
- if(sc = Cache_Check(&sfx->cu), sc == nil)
- continue;
- sz = sc->length * sc->width * (sc->stereo + 1);
- sum += sz;
- c = sc->loop >= 0 ? 'L' : ' ';
- Con_Printf("%c(%2db) %6d : %s\n", c, sc->width * 8, sz, sfx->s);
- }
- Con_Printf("Total resident: %d\n", sum);
-}
-
-void
-sfxbegin(void)
-{
- map++;
-}
-
-void
-sfxend(void)
-{
- Sfx *sfx;
- int i;
-
- for(i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++){
- if(sfx->map >= map || sfx == ambsfx[Ambsky] || sfx == ambsfx[Ambwater])
- continue;
- if(Cache_Check(&sfx->cu) != nil)
- Cache_Free(&sfx->cu);
- }
-}
-
-int
-initsnd(void)
-{
- int i, j, *p;
-
- if(sndopen() != 0)
- return -1;
- ainit = 1;
- for(p=scalt[1], i=8; i<8*nelem(scalt); i+=8)
- for(j=0; j<256; j++)
- *p++ = (char)j * i;
- Cmd_AddCommand("play", playsfx);
- Cmd_AddCommand("playvol", playvolsfx);
- Cmd_AddCommand("stopsound", stopallsfx);
- Cmd_AddCommand("soundlist", sfxlist);
- Cvar_RegisterVariable(&volume);
- Cvar_RegisterVariable(&precache);
- Cvar_RegisterVariable(&loadas8bit);
- Cvar_RegisterVariable(&ambient_level);
- Cvar_RegisterVariable(&ambient_fade);
-
- chans = calloc(Nchan, sizeof(*chans));
- known_sfx = Hunk_Alloc(MAX_SOUNDS * sizeof *known_sfx);
- num_sfx = 0;
-
- ambsfx[Ambwater] = precachesfx("ambience/water1.wav");
- ambsfx[Ambsky] = precachesfx("ambience/wind2.wav");
- stopallsfx();
- return 0;
-}
--- /dev/null
+++ b/snd_mix.c
@@ -1,0 +1,689 @@
+#include "quakedef.h"
+
+cvar_t volume = {"volume", "0.7", 1};
+
+typedef struct Chan Chan;
+
+enum{
+ Srate = 44100,
+ Ssize = 2,
+ Sch = 2,
+ Sblk = Ssize * Sch,
+ Ssamp = Srate / Fpsmin,
+
+ Nchan = 256,
+ Ndyn = 8,
+ Sstat = Ndyn + Namb
+};
+static float Clipdist = 1000.0;
+
+struct Chan{
+ Sfx *sfx;
+ int chvol;
+ int lvol;
+ int rvol;
+ vec_t attf;
+ vec3_t zp;
+ int entn;
+ int entch;
+ int p;
+ int n;
+};
+
+static Chan *chans, *che;
+
+static int ainit, mixbufi;
+static uchar mixbufs[2][Ssamp*Sblk], *mixbuf;
+static vlong sndt, sampt;
+static int nsamp;
+static int sampbuf[Ssamp*2];
+static int scalt[32][256];
+
+static Sfx *ambsfx[Namb];
+
+typedef struct
+{
+ int length;
+ int speed;
+ int width;
+ int stereo;
+ int loop;
+ byte data[1]; // variable sized
+} sfxcache_t;
+
+static vec3_t listener_origin;
+static vec3_t listener_forward;
+static vec3_t listener_right;
+static vec3_t listener_up;
+static Sfx *known_sfx; // hunk allocated
+static int num_sfx;
+static int map;
+
+static cvar_t precache = {"precache", "1"};
+static cvar_t loadas8bit = {"loadas8bit", "0"};
+static cvar_t ambient_level = {"ambient_level", "0.3"};
+static cvar_t ambient_fade = {"ambient_fade", "100"};
+
+static byte *data_p;
+static byte *iff_end;
+static byte *last_chunk;
+static byte *iff_data;
+
+/* TODO: refuctor wav loading */
+static void
+resample(sfxcache_t *sc, byte *data, float stepscale)
+{
+ int inwidth;
+ int outcount;
+ int srcsample;
+ int i;
+ int sample, samplefrac, fracstep;
+
+ inwidth = sc->width;
+ outcount = sc->length / stepscale;
+ sc->length = outcount;
+ sc->speed = Srate;
+ if (loadas8bit.value)
+ sc->width = 1;
+ else
+ sc->width = inwidth;
+ sc->stereo = 0;
+
+ if (stepscale == 1 && inwidth == 1 && sc->width == 1)
+ {
+// fast special case
+ for (i=0 ; i<outcount ; i++)
+ ((signed char *)sc->data)[i]
+ = (int)( (unsigned char)(data[i]) - 128);
+ }
+ else
+ {
+// general case
+ samplefrac = 0;
+ fracstep = stepscale*256;
+ for (i=0 ; i<outcount ; i++)
+ {
+ srcsample = samplefrac >> 8;
+ samplefrac += fracstep;
+ if (inwidth == 2)
+ sample = LittleShort ( ((short *)data)[srcsample] );
+ else
+ sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
+ if (sc->width == 2)
+ ((short *)sc->data)[i] = sample;
+ else
+ ((signed char *)sc->data)[i] = sample >> 8;
+ }
+ }
+}
+
+static sfxcache_t *
+loadsfx(Sfx *sfx)
+{
+ wavinfo_t info;
+ int len;
+ float stepscale;
+ sfxcache_t *sc;
+ uchar *u, buf[1024]; /* avoid dirtying the cache heap */
+
+ if(sc = Cache_Check(&sfx->cu), sc != nil)
+ return sc;
+ u = loadstklmp(va("sound/%s", sfx->s), buf, sizeof buf, &len);
+ if(u == nil){
+ Con_DPrintf("loadsfx: %r\n");
+ return nil;
+ }
+ if(wavinfo(u, len, &info) != 0){
+ Con_Printf("loadsfx: %s: %s\n", sfx->s, lerr());
+ return nil;
+ }
+ if(info.channels != 1){
+ Con_DPrintf("loadsfx: non mono wave %s\n", sfx->s);
+ return nil;
+ }
+ stepscale = (float)info.rate / Srate;
+ len = info.samples / stepscale;
+ len *= info.width * info.channels;
+ if(sc = Cache_Alloc(&sfx->cu, len + sizeof *sc), sc == nil)
+ return nil;
+ sc->length = info.samples;
+ sc->loop = info.loopofs;
+ if(info.loopofs >= 0)
+ sc->loop /= stepscale;
+ sc->speed = info.rate;
+ sc->width = info.width;
+ sc->stereo = info.channels;
+ resample(sc, u + info.dataofs, stepscale);
+ return sc;
+}
+
+static void
+sndout(void)
+{
+ int v, *pb, *pe;
+ uchar *p;
+ double vol;
+
+ vol = volume.value;
+ p = mixbuf;
+ pb = sampbuf;
+ pe = sampbuf + nsamp * 2;
+ while(pb < pe){
+ v = *pb++ * vol;
+ if(v > 0x7fff)
+ v = 0x7fff;
+ else if(v < -0x8000)
+ v = -0x8000;
+ p[0] = v;
+ p[1] = v >> 8;
+ p += 2;
+ }
+}
+
+static void
+sample8(Chan *c, void *d, int n)
+{
+ int v, *pb, *pe, *ls, *rs;
+ uchar *p;
+
+ if(c->lvol > 255)
+ c->lvol = 255;
+ if(c->rvol > 255)
+ c->rvol = 255;
+ ls = scalt[c->lvol >> 3];
+ rs = scalt[c->rvol >> 3];
+ p = (uchar *)d + c->p;
+ pb = sampbuf;
+ pe = sampbuf + n * 2;
+ while(pb < pe){
+ v = *p++;
+ *pb++ += ls[v];
+ *pb++ += rs[v];
+ }
+}
+
+static void
+sample16(Chan *c, void *d, int n)
+{
+ int v, *pb, *pe, lv, rv;
+ short *p;
+
+ lv = c->lvol;
+ rv = c->rvol;
+ p = (short *)d + c->p;
+ pb = sampbuf;
+ pe = sampbuf + n * 2;
+ while(pb < pe){
+ v = *p++;
+ *pb++ += v * lv >> 8;
+ *pb++ += v * rv >> 8;
+ }
+}
+
+static void
+samplesfx(void)
+{
+ int n, m;
+ Chan *c;
+ sfxcache_t *sc;
+ void (*sf)(Chan *, void *, int);
+
+ memset(sampbuf, 0, sizeof sampbuf);
+ for(c=chans; c<che; c++){
+ if(c->sfx == nil)
+ continue;
+ if(c->lvol == 0 && c->rvol == 0)
+ continue;
+ if(sc = loadsfx(c->sfx), sc == nil)
+ continue;
+ sf = sc->width == 1 ? sample8 : sample16;
+ n = nsamp;
+ while(n > 0){
+ m = n < c->n ? n : c->n;
+ if(m > 0)
+ sf(c, sc->data, m);
+ c->p += m;
+ c->n -= m;
+ n -= m;
+ if(c->n <= 0){
+ if(sc->loop >= 0){
+ c->p = sc->loop;
+ c->n = sc->length - c->p;
+ }else{
+ c->sfx = nil;
+ break;
+ }
+ }
+ }
+ }
+ sndout();
+}
+
+static void
+spatialize(Chan *c)
+{
+ vec_t Δr, m;
+ vec3_t src;
+
+ if(c->entn == cl.viewentity){
+ c->lvol = c->chvol;
+ c->rvol = c->chvol;
+ return;
+ }
+ VectorSubtract(c->zp, listener_origin, src);
+ Δr = 1.0 - VectorNormalize(src) * c->attf;
+ m = DotProduct(listener_right, src);
+ c->rvol = Δr * (1.0 + m) * c->chvol;
+ if(c->rvol < 0)
+ c->rvol = 0;
+ c->lvol = Δr * (1.0 - m) * c->chvol;
+ if(c->lvol < 0)
+ c->lvol = 0;
+}
+
+static void
+ambs(void)
+{
+ uchar *av;
+ float vol;
+ Chan *c, *e;
+ mleaf_t *l;
+ Sfx **sfx;
+
+ if(cl.worldmodel == nil)
+ return;
+ c = chans;
+ e = chans + Namb;
+ l = Mod_PointInLeaf(listener_origin, cl.worldmodel);
+ if(l == nil || !ambient_level.value){
+ while(c < e)
+ c++->sfx = nil;
+ return;
+ }
+ sfx = ambsfx;
+ av = l->ambient_sound_level;
+ while(c < e){
+ c->sfx = *sfx++;
+ vol = ambient_level.value * *av++;
+ if(vol < 8)
+ vol = 0;
+ if(c->chvol < vol){
+ c->chvol += host_frametime * ambient_fade.value;
+ if(c->chvol > vol)
+ c->chvol = vol;
+ }else if(c->chvol > vol){
+ c->chvol -= host_frametime * ambient_fade.value;
+ if(c->chvol < vol)
+ c->chvol = vol;
+ }
+ c->lvol = c->chvol;
+ c->rvol = c->chvol;
+ c++;
+ }
+}
+
+void
+stepsnd(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
+{
+ long ns;
+ Chan *c, *sum;
+
+ if(!ainit)
+ return;
+
+ if(sndt == 0)
+ sndt = nanosec() - Te9 / Fpsmax;
+ nsamp = (nanosec() - sndt) / (Te9 / Srate);
+ if(!cls.timedemo)
+ nsamp = (nsamp + 15) & ~15;
+ nsamp -= sndqueued()/Sblk - Srate/Fpsmax;
+ if(nsamp < 1)
+ return;
+ if(nsamp > Ssamp)
+ nsamp = Ssamp;
+ ns = nsamp * Sblk;
+ mixbuf = mixbufs[mixbufi];
+ samplesfx();
+ sampt += nsamp;
+ if(ns != 0){
+ sndwrite(mixbuf, ns);
+ mixbufi = (mixbufi + 1) % nelem(mixbufs);
+ }
+ sndt = nanosec();
+
+ VectorCopy(origin, listener_origin);
+ VectorCopy(forward, listener_forward);
+ VectorCopy(right, listener_right);
+ VectorCopy(up, listener_up);
+ ambs();
+ sum = nil;
+ for(c=chans+Namb; c<che; c++){
+ if(c->sfx == nil)
+ continue;
+ spatialize(c);
+ if(c->lvol == 0 && c->rvol == 0)
+ continue;
+ /* sum static sounds to avoid useless remixing */
+ if(c >= chans + Sstat){
+ if(sum != nil && sum->sfx == c->sfx){
+ sum->lvol += c->lvol;
+ sum->rvol += c->rvol;
+ c->lvol = c->rvol = 0;
+ continue;
+ }
+ for(sum=chans + Sstat; sum<c; sum++)
+ if(sum->sfx == c->sfx)
+ break;
+ if(sum == che)
+ sum = nil;
+ else if(sum != c){
+ sum->lvol += c->lvol;
+ sum->rvol += c->rvol;
+ c->lvol = c->rvol = 0;
+ }
+ }
+ }
+}
+
+void
+stopallsfx(void)
+{
+ if(!ainit)
+ return;
+ memset(chans, 0, sizeof(*chans)*Nchan);
+ che = chans + Sstat;
+ sndstop();
+}
+
+void
+stopsfx(int n, int ch)
+{
+ Chan *c, *e;
+
+ if(!ainit)
+ return;
+ c = chans;
+ e = chans + Ndyn;
+ while(c < e){
+ if(c->entn == n && c->entch == ch){
+ c->sfx = nil;
+ return;
+ }
+ c++;
+ }
+}
+
+static Chan *
+pickchan(int entn, int entch)
+{
+ int Δt;
+ Chan *c, *p, *e;
+
+ p = nil;
+ Δt = 0x7fffffff;
+ for(c=chans+Namb, e=c+Ndyn; c<e; c++){
+ if(entch != 0 && c->entn == entn
+ && (c->entch == entch || entch == -1)){
+ p = c;
+ break;
+ }
+ if(c->entn == cl.viewentity && entn != cl.viewentity && c->sfx != nil)
+ continue;
+ if(c->n < Δt){
+ Δt = c->n;
+ p = c;
+ }
+ }
+ if(p != nil)
+ p->sfx = nil;
+ return p;
+}
+
+void
+startsfx(int entn, int entch, Sfx *sfx, vec3_t zp, float vol, float att)
+{
+ int skip;
+ Chan *c, *c2, *e;
+ sfxcache_t *sc;
+
+ if(!ainit || sfx == nil)
+ return;
+ if(c = pickchan(entn, entch), c == nil)
+ return;
+ memset(c, 0, sizeof *c);
+ VectorCopy(zp, c->zp);
+ c->attf = att / Clipdist;
+ c->chvol = vol * 255;
+ c->entn = entn;
+ c->entch = entch;
+ spatialize(c);
+ if(c->lvol == 0 && c->rvol == 0)
+ return;
+ if(sc = loadsfx(sfx), sc == nil)
+ return;
+ c->sfx = sfx;
+ c->p = 0;
+ c->n = sc->length;
+ /* don't sum identical sfx started on the same frame */
+ for(c2=chans+Namb, e=chans+Sstat; c2<e; c2++){
+ if(c2 == c || c2->sfx != sfx || c2->p != 0)
+ continue;
+ skip = nrand(Srate / Fpsmin);
+ if(skip >= c->n)
+ skip = c->n - 1;
+ c->p += skip;
+ c->n -= skip;
+ break;
+ }
+}
+
+void
+localsfx(char *s)
+{
+ Sfx *sfx;
+
+ if(!ainit)
+ return;
+ sfx = precachesfx(s);
+ startsfx(cl.viewentity, -1, sfx, vec3_origin, 1, 1);
+}
+
+void
+staticsfx(Sfx *sfx, vec3_t zp, float vol, float att)
+{
+ Chan *c;
+ sfxcache_t *sc;
+
+ if(sfx == nil || che >= chans+Nchan)
+ return;
+ c = che++;
+ if(sc = loadsfx(sfx), sc == nil)
+ return;
+ if(sc->loop < 0){
+ Con_DPrintf("staticsfx %s: nonlooped static sound\n", sfx->s);
+ return;
+ }
+ c->sfx = sfx;
+ VectorCopy(zp, c->zp);
+ c->chvol = vol * 255;
+ c->attf = att / Clipdist;
+ c->n = sc->length;
+ spatialize(c);
+}
+
+static Sfx *
+findsfx(char *s)
+{
+ Sfx *sfx, *e;
+
+ if(strlen(s) >= Npath)
+ Host_Error("findsfx: path too long %s", s);
+ sfx = known_sfx;
+ e = known_sfx + num_sfx;
+ while(sfx < e){
+ if(strcmp(sfx->s, s) == 0)
+ return sfx;
+ sfx++;
+ }
+ if(num_sfx == MAX_SOUNDS){
+ sfx = known_sfx;
+ while(sfx < e){
+ if(sfx->map && sfx->map < map)
+ break;
+ sfx++;
+ }
+ if(sfx == e)
+ Host_Error("findsfx: sfx list overflow: %s", s);
+ if(Cache_Check(&sfx->cu))
+ Cache_Free(&sfx->cu);
+ }else
+ num_sfx++;
+ strcpy(sfx->s, s);
+ return sfx;
+}
+
+void
+touchsfx(char *s)
+{
+ Sfx *sfx;
+
+ if(!ainit)
+ return;
+ sfx = findsfx(s);
+ Cache_Check(&sfx->cu);
+}
+
+Sfx *
+precachesfx(char *s)
+{
+ Sfx *sfx;
+
+ if(!ainit)
+ return nil;
+ sfx = findsfx(s);
+ sfx->map = map;
+ if(precache.value)
+ loadsfx(sfx);
+ return sfx;
+}
+
+static void
+playsfx(void)
+{
+ static int hash = 345;
+ int i;
+ char *s;
+ Sfx *sfx;
+
+ if(Cmd_Argc() < 2){
+ Con_Printf("play wav [wav..]: play a wav lump\n");
+ return;
+ }
+ i = 1;
+ while(i < Cmd_Argc()){
+ if(strrchr(Cmd_Argv(i), '.') == nil)
+ s = va("%s.wav", Cmd_Argv(i));
+ else
+ s = Cmd_Argv(i);
+ sfx = precachesfx(s);
+ startsfx(hash++, 0, sfx, listener_origin, 1.0, 1.0);
+ i++;
+ }
+}
+
+static void
+playvolsfx(void)
+{
+ static int hash = 543;
+ int i;
+ float vol;
+ char *s;
+ Sfx *sfx;
+
+ if(Cmd_Argc() < 3){
+ Con_Printf("play wav vol [wav vol]..: play an amplified wav lump\n");
+ return;
+ }
+ i = 1;
+ while(i < Cmd_Argc()){
+ if(strrchr(Cmd_Argv(i), '.') == nil)
+ s = va("%s.wav", Cmd_Argv(i));
+ else
+ s = Cmd_Argv(i);
+ sfx = precachesfx(s);
+ vol = atof(Cmd_Argv(++i));
+ startsfx(hash++, 0, sfx, listener_origin, vol, 1.0);
+ i++;
+ }
+}
+
+static void
+sfxlist(void)
+{
+ char c;
+ int sz, sum;
+ Sfx *sfx, *e;
+ sfxcache_t *sc;
+
+ sum = 0;
+ for(sfx=known_sfx, e=known_sfx+num_sfx; sfx<e; sfx++){
+ if(sc = Cache_Check(&sfx->cu), sc == nil)
+ continue;
+ sz = sc->length * sc->width * (sc->stereo + 1);
+ sum += sz;
+ c = sc->loop >= 0 ? 'L' : ' ';
+ Con_Printf("%c(%2db) %6d : %s\n", c, sc->width * 8, sz, sfx->s);
+ }
+ Con_Printf("Total resident: %d\n", sum);
+}
+
+void
+sfxbegin(void)
+{
+ map++;
+}
+
+void
+sfxend(void)
+{
+ Sfx *sfx;
+ int i;
+
+ for(i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++){
+ if(sfx->map >= map || sfx == ambsfx[Ambsky] || sfx == ambsfx[Ambwater])
+ continue;
+ if(Cache_Check(&sfx->cu) != nil)
+ Cache_Free(&sfx->cu);
+ }
+}
+
+int
+initsnd(void)
+{
+ int i, j, *p;
+
+ if(sndopen() != 0)
+ return -1;
+ ainit = 1;
+ for(p=scalt[1], i=8; i<8*nelem(scalt); i+=8)
+ for(j=0; j<256; j++)
+ *p++ = (char)j * i;
+ Cmd_AddCommand("play", playsfx);
+ Cmd_AddCommand("playvol", playvolsfx);
+ Cmd_AddCommand("stopsound", stopallsfx);
+ Cmd_AddCommand("soundlist", sfxlist);
+ Cvar_RegisterVariable(&volume);
+ Cvar_RegisterVariable(&precache);
+ Cvar_RegisterVariable(&loadas8bit);
+ Cvar_RegisterVariable(&ambient_level);
+ Cvar_RegisterVariable(&ambient_fade);
+
+ chans = calloc(Nchan, sizeof(*chans));
+ known_sfx = Hunk_Alloc(MAX_SOUNDS * sizeof *known_sfx);
+ num_sfx = 0;
+
+ ambsfx[Ambwater] = precachesfx("ambience/water1.wav");
+ ambsfx[Ambsky] = precachesfx("ambience/wind2.wav");
+ stopallsfx();
+ return 0;
+}
--- /dev/null
+++ b/snd_openal.c
@@ -1,0 +1,880 @@
+#include "quakedef.h"
+#include <AL/al.h>
+#include <AL/alc.h>
+#include <AL/alext.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+typedef struct albuf_t albuf_t;
+typedef struct alchan_t alchan_t;
+
+struct albuf_t {
+ ALuint buf;
+ bool loop;
+ bool upsample;
+};
+
+struct alchan_t {
+ int ent;
+ int ch;
+ ALuint src;
+
+ alchan_t *prev, *next;
+};
+
+enum {
+ Srcstatic = -666,
+ Srcamb,
+};
+
+cvar_t volume = {"volume", "0.7", true};
+
+static struct {
+ ALuint src, buf;
+ int pcm;
+ bool playing;
+ pid_t decoder, reader;
+}track;
+
+static cvar_t s_al_dev = {"s_al_device", "0", true};
+static int s_al_dev_prev = -1;
+
+static cvar_t s_al_hrtf = {"s_al_hrtf", "0", true};
+static cvar_t s_al_doppler_factor = {"s_al_doppler_factor", "2", true};
+static cvar_t s_al_resampler_default = {"s_al_resampler_default", "6", true}; // 23rd order Sinc
+static cvar_t s_al_resampler_up = {"s_al_resampler_up", "1", true}; // Linear
+
+static ALCcontext *ctx;
+static ALCdevice *dev;
+static Sfx *known_sfx;
+static int num_sfx;
+static int map;
+static alchan_t *chans;
+
+static cvar_t ambient_level = {"ambient_level", "0.3"};
+static cvar_t ambient_fade = {"ambient_fade", "100"};
+static Sfx *ambsfx[Namb];
+static float ambvol[Namb];
+
+static int al_default_resampler, al_num_resamplers;
+static ALchar *(*qalGetStringiSOFT)(ALenum, ALsizei);
+static ALCchar *(*qalcGetStringiSOFT)(ALCdevice *, ALenum, ALsizei);
+static ALCboolean (*qalcResetDeviceSOFT)(ALCdevice *, const ALCint *attr);
+static ALCboolean *(*qalcReopenDeviceSOFT)(ALCdevice *, const ALCchar *devname, const ALCint *attr);
+static void (*qalBufferCallbackSOFT)(ALuint buf, ALenum fmt, ALsizei freq, ALBUFFERCALLBACKTYPESOFT cb, ALvoid *aux);
+
+#define ALERR() alcheckerr(__FILE__, __LINE__)
+
+static int
+alcheckerr(const char *file, int line)
+{
+ int e, ret;
+ char *s, tmp[32];
+
+ ret = 0;
+ if(ctx != nil && (e = alGetError()) != AL_NO_ERROR){
+ switch(e){
+ case AL_INVALID_NAME: s = "invalid name"; break;
+ case AL_INVALID_ENUM: s = "invalid enum"; break;
+ case AL_INVALID_VALUE: s = "invalid value"; break;
+ case AL_INVALID_OPERATION: s = "invalid operation"; break;
+ case AL_OUT_OF_MEMORY: s = "out of memory"; break;
+ default:
+ snprint(tmp, sizeof(tmp), "unknown (0x%x)", e);
+ s = tmp;
+ break;
+ }
+ ret |= e;
+ fprintf(stderr, "AL: %s:%d: %s\n", file, line, s);
+ }
+ if(dev != nil && (e = alcGetError(dev)) != ALC_NO_ERROR){
+ switch(e){
+ case ALC_INVALID_DEVICE: s = "invalid device"; break;
+ case ALC_INVALID_ENUM: s = "invalid enum"; break;
+ case ALC_INVALID_VALUE: s = "invalid value"; break;
+ case ALC_INVALID_CONTEXT: s = "invalid context"; break;
+ case ALC_OUT_OF_MEMORY: s = "out of memory"; break;
+ default:
+ snprint(tmp, sizeof(tmp), "unknown error (0x%x)", e);
+ s = tmp;
+ break;
+ }
+ ret |= e;
+ fprintf(stderr, "ALC: %s:%d: %s\n", file, line, s);
+ }
+
+ return ret;
+}
+
+static alchan_t *
+getchan(int ent, int ch)
+{
+ alchan_t *c, *stopped;
+ ALint state;
+ ALuint src;
+
+ stopped = nil;
+ for(c = chans; c != nil; c = c->next){
+ if(c->ent == ent && c->ch == ch)
+ return c;
+ if(stopped == nil){
+ alGetSourcei(c->src, AL_SOURCE_STATE, &state);
+ if(!ALERR() && state != AL_PLAYING)
+ stopped = c;
+ }
+ }
+
+ if(stopped != nil){
+ c = stopped;
+ c->ent = ent;
+ c->ch = ch;
+ return c;
+ }
+
+ alGenSources(1, &src);
+ if(ALERR())
+ return nil;
+
+ c = calloc(1, sizeof(*c));
+ c->ent = ent;
+ c->ch = ch;
+ c->src = src;
+ c->next = chans;
+ if(chans != nil)
+ chans->prev = c;
+ chans = c;
+
+ return c;
+}
+
+static void
+delchan(alchan_t *c)
+{
+ if(c->prev != nil)
+ c->prev->next = c->next;
+ if(c->next != nil)
+ c->next->prev = c->prev;
+ if(chans == c)
+ chans = c->next;
+ alSourceStop(c->src); ALERR();
+ alSourcei(c->src, AL_BUFFER, 0); ALERR();
+ alDeleteSources(1, &c->src); ALERR();
+ free(c);
+}
+
+static Sfx *
+findsfx(char *s)
+{
+ Sfx *sfx, *e;
+ albuf_t *b;
+
+ if(strlen(s) >= Npath)
+ Host_Error("findsfx: path too long %s", s);
+ sfx = known_sfx;
+ e = known_sfx + num_sfx;
+ while(sfx < e){
+ if(strcmp(sfx->s, s) == 0){
+ sfx->map = map;
+ return sfx;
+ }
+ sfx++;
+ }
+ if(num_sfx == MAX_SOUNDS){
+ sfx = known_sfx;
+ while(sfx < e){
+ if(sfx->map && sfx->map < map)
+ break;
+ sfx++;
+ }
+ if(sfx == e)
+ Host_Error("findsfx: sfx list overflow: %s", s);
+ if((b = Cache_Check(&sfx->cu)) != nil){
+ alDeleteBuffers(1, &b->buf); ALERR();
+ Cache_Free(&sfx->cu);
+ sfx->map = map;
+ }
+ }else
+ num_sfx++;
+ strcpy(sfx->s, s);
+ return sfx;
+}
+
+static albuf_t *
+loadsfx(Sfx *sfx)
+{
+ ALint loop[2];
+ wavinfo_t info;
+ ALuint buf;
+ ALenum fmt;
+ albuf_t *b;
+ byte *in;
+ int len;
+
+ if((b = Cache_Check(&sfx->cu)) != nil)
+ return b;
+ in = loadstklmp(va("sound/%s", sfx->s), nil, 0, &len);
+ if(in == nil){
+ Con_DPrintf("loadsfx: %s\n", lerr());
+ return nil;
+ }
+ if(wavinfo(in, len, &info) != 0){
+ Con_Printf("loadsfx: %s: %s\n", sfx->s, lerr());
+ // complain but get some silence in place so it looks like it got loaded
+ memset(&info, 0, sizeof(info));
+ info.width = 8;
+ info.channels = 1;
+ info.rate = 11025;
+ info.loopofs = -1;
+ }
+ if(info.channels < 2)
+ fmt = info.width == 1 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16;
+ else
+ fmt = info.width == 1 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16;
+ alGenBuffers(1, &buf);
+ if(ALERR())
+ return nil;
+ alBufferData(buf, fmt, in+info.dataofs, info.samples*info.width, info.rate);
+ if(ALERR()){
+ alDeleteBuffers(1, &buf); ALERR();
+ return nil;
+ }
+ b = Cache_Alloc(&sfx->cu, sizeof(*b));
+ b->buf = buf;
+ if(info.loopofs >= 0){
+ loop[0] = info.loopofs;
+ loop[1] = info.samples;
+ alBufferiv(b->buf, AL_LOOP_POINTS_SOFT, loop); ALERR();
+ b->loop = true;
+ }
+ b->upsample = info.rate < 22050;
+
+ return b;
+}
+
+static void
+alplay(alchan_t *c, albuf_t *b, vec3_t zp, float vol, float att, bool rel, bool loop)
+{
+ ALint src;
+ int n;
+
+ src = c->src;
+ if(rel){
+ alSourcefv(src, AL_POSITION, vec3_origin); ALERR();
+ alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); ALERR();
+ alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); ALERR();
+ alSourcef(src, AL_REFERENCE_DISTANCE, 0.0f); ALERR();
+ }else{
+ alSourcefv(src, AL_POSITION, zp); ALERR();
+ alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); ALERR();
+ alSourcef(src, AL_ROLLOFF_FACTOR, att * 8.191); ALERR();
+ alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f); ALERR();
+ alSourcef(src, AL_MAX_DISTANCE, 8192.0f); ALERR();
+ }
+ alSourcef(src, AL_GAIN, vol); ALERR();
+ if(al_num_resamplers > 0){
+ n = b->upsample ? s_al_resampler_up.value : s_al_resampler_default.value;
+ if(n >= 0){
+ alSourcei(src, AL_SOURCE_RESAMPLER_SOFT, n);
+ ALERR();
+ }
+ }
+ alSourcei(src, AL_BUFFER, b->buf); ALERR();
+ alSourcei(src, AL_LOOPING, (b->loop || loop) ? AL_TRUE : AL_FALSE); ALERR();
+ alSourcePlay(src); ALERR();
+}
+
+
+static void
+ambs(vec3_t org)
+{
+ float vol, *av;
+ ALint state;
+ alchan_t *ch;
+ uchar *asl;
+ mleaf_t *l;
+ albuf_t *b;
+ Sfx *sfx;
+ int i;
+
+ if(cl.worldmodel == nil)
+ return;
+ l = Mod_PointInLeaf(org, cl.worldmodel);
+ asl = l->ambient_sound_level;
+ for(i = 0; i < Namb; i++){
+ if((sfx = ambsfx[i]) == nil || (b = loadsfx(sfx)) == nil)
+ continue;
+ vol = ambient_level.value * asl[i];
+ av = &ambvol[i];
+ if(vol < 8)
+ vol = 0;
+ if(*av < vol){
+ *av += host_frametime * ambient_fade.value;
+ if(*av > vol)
+ *av = vol;
+ }else if(*av > vol){
+ *av -= host_frametime * ambient_fade.value;
+ if(*av < vol)
+ *av = vol;
+ }
+ if((ch = getchan(Srcamb, i)) != nil){
+ alSourcef(ch->src, AL_GAIN, *av / 255.0f); ALERR();
+ alGetSourcei(ch->src, AL_SOURCE_STATE, &state);
+ if(!ALERR() && state != AL_PLAYING)
+ alplay(ch, b, vec3_origin, *av, 0.0f, true, true);
+ }
+ }
+}
+
+void
+stepsnd(vec3_t zp, vec3_t fw, vec3_t rt, vec3_t up)
+{
+ vec_t fwup[6] = {fw[0], fw[1], fw[2], up[0], up[1], up[2]};
+ alchan_t *c, *next;
+ static vec3_t ozp;
+ ALint state;
+ vec3_t vel;
+
+ if(dev == nil)
+ return;
+ if(zp == vec3_origin && fw == vec3_origin && rt == vec3_origin){
+ alListenerf(AL_GAIN, 0);
+ ALERR();
+ return;
+ }
+
+ alListenerfv(AL_POSITION, zp); ALERR();
+ alListenerfv(AL_ORIENTATION, fwup); ALERR();
+ VectorSubtract(zp, ozp, vel);
+ VectorCopy(zp, ozp);
+ alListenerfv(AL_VELOCITY, vel); ALERR();
+ alListenerf(AL_GAIN, volume.value); ALERR();
+
+ ambs(zp);
+
+ for(c = chans; c != nil; c = next){
+ next = c->next;
+ alGetSourcei(c->src, AL_SOURCE_STATE, &state);
+ if(!ALERR() && state != AL_PLAYING)
+ delchan(c);
+ }
+}
+
+void
+stopallsfx(void)
+{
+ alchan_t *c, *next;
+
+ if(dev == nil)
+ return;
+ alListenerf(AL_GAIN, 0); ALERR();
+ for(c = chans; c != nil; c = next){
+ next = c->next;
+ delchan(c);
+ }
+ chans = nil;
+ memset(ambvol, 0, sizeof(ambvol));
+}
+
+void
+stopsfx(int ent, int ch)
+{
+ alchan_t *c;
+
+ if(dev == nil)
+ return;
+ for(c = chans; c != nil; c = c->next){
+ if(c->ent == ent && c->ch == ch)
+ break;
+ }
+ if(c == nil)
+ return;
+ if(c->prev != nil)
+ c->prev->next = c->next;
+ if(c->next != nil)
+ c->next->prev = c->prev;
+ if(chans == c)
+ chans = c->next;
+ delchan(c);
+ if(ent == Srcamb)
+ ambvol[ch] = 0;
+}
+
+void
+startsfx(int ent, int ch, Sfx *sfx, vec3_t zp, float vol, float att)
+{
+ alchan_t *c;
+ albuf_t *b;
+
+ if(dev == nil || (b = loadsfx(sfx)) == nil || (c = getchan(ent, ch)) == nil)
+ return;
+ alSourceStop(c->src); ALERR();
+ alplay(c, b, zp, vol, att, ent == cl.viewentity, ent == Srcstatic);
+}
+
+void
+localsfx(char *name)
+{
+ if(dev == nil)
+ return;
+
+ startsfx(cl.viewentity, -1, findsfx(name), vec3_origin, 1.0f, 1.0f);
+}
+
+void
+staticsfx(Sfx *sfx, vec3_t zp, float vol, float att)
+{
+ static int numst = 0;
+
+ if(dev == nil)
+ return;
+
+ startsfx(Srcstatic, numst++, sfx, zp, vol, att/1.5f);
+}
+
+void
+touchsfx(char *s)
+{
+ Sfx *sfx;
+
+ if(dev == nil)
+ return;
+ sfx = findsfx(s);
+ Cache_Check(&sfx->cu);
+}
+
+Sfx *
+precachesfx(char *s)
+{
+ Sfx *sfx;
+
+ if(dev == nil)
+ return nil;
+ sfx = findsfx(s);
+ sfx->map = map;
+ loadsfx(sfx);
+ return sfx;
+}
+
+static ALCint *
+alcattr(bool hrtf)
+{
+ static ALCint attr[] = {
+ 0, 0, 0, 0, 0,
+ };
+
+ attr[0] = 0;
+ if(hrtf){
+ attr[0] = s_al_hrtf.value != 0 ? ALC_HRTF_SOFT : 0;
+ attr[1] = s_al_hrtf.value != 0 ? (s_al_hrtf.value > 0 ? ALC_TRUE : ALC_FALSE) : ALC_DONT_CARE_SOFT;
+ if(attr[1] == ALC_TRUE){
+ attr[2] = ALC_HRTF_ID_SOFT;
+ attr[3] = s_al_hrtf.value - 1;
+ }
+ }
+
+ return attr;
+}
+
+static int
+alinit(const char *devname)
+{
+ ALCcontext *c;
+ int e;
+
+ dev = alcOpenDevice(devname); ALERR();
+ if(dev == nil)
+ return -1;
+
+ c = alcCreateContext(dev, nil); ALERR();
+ if(c == nil){
+closedev:
+ alcCloseDevice(dev); ALERR();
+ dev = nil;
+ return -1;
+ }
+ ctx = c;
+ e = alcMakeContextCurrent(c); ALERR();
+ if(!e){
+ ctx = nil;
+ alcDestroyContext(c); ALERR();
+ goto closedev;
+ }
+ alListenerf(AL_GAIN, volume.value); ALERR();
+ alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); ALERR();
+
+ // assuming 64 Quake units is ~1.7m
+ alSpeedOfSound(343.3 * 64.0 / 1.7); ALERR();
+ alDopplerFactor(s_al_doppler_factor.value); ALERR();
+
+ if(alIsExtensionPresent("AL_SOFT_source_resampler")){
+ al_default_resampler = alGetInteger(AL_DEFAULT_RESAMPLER_SOFT);
+ if(ALERR())
+ al_default_resampler = 0;
+ al_num_resamplers = alGetInteger(AL_NUM_RESAMPLERS_SOFT);
+ if(ALERR())
+ al_num_resamplers = 0;
+ qalGetStringiSOFT = alGetProcAddress("alGetStringiSOFT");
+ }else{
+ qalGetStringiSOFT = nil;
+ }
+
+ qalBufferCallbackSOFT = nil;
+ if(alIsExtensionPresent("AL_SOFT_callback_buffer") && (alGenSources(1, &track.src), !ALERR())){
+ alSourcei(track.src, AL_SOURCE_SPATIALIZE_SOFT, AL_FALSE); ALERR();
+ qalBufferCallbackSOFT = alGetProcAddress("alBufferCallbackSOFT");
+ alGenBuffers(1, &track.buf); ALERR();
+ }
+
+ return 0;
+}
+
+static void
+alreinit(const char *def, const char *all)
+{
+ const char *s;
+ int i, n;
+
+ n = s_al_dev.value;
+ if(n == s_al_dev_prev)
+ return;
+ if(qalcReopenDeviceSOFT == nil && alcIsExtensionPresent(nil, "ALC_SOFT_reopen_device"))
+ qalcReopenDeviceSOFT = alGetProcAddress("alcReopenDeviceSOFT");
+ if(qalcReopenDeviceSOFT == nil){
+ Con_Printf("AL: can't change device settings on the fly\n");
+ return;
+ }
+ for(i = 1, s = all; s != nil && *s; i++){
+ if((n == 0 && def != nil && strcmp(s, def) == 0) || n == i){
+ if(dev == nil)
+ n = alinit(all);
+ else{
+ n = qalcReopenDeviceSOFT(dev, s, alcattr(false)) ? 0 : -1;
+ ALERR();
+ }
+ if(n != 0)
+ Con_Printf("AL: failed to switch to %s\n", s);
+ else
+ s_al_dev_prev = n;
+ return;
+ }
+ s += strlen(s)+1;
+ }
+ Con_Printf("AL: no such device: %d\n", n);
+}
+
+static void
+alvarcb(cvar_t *var)
+{
+ const char *all, *def, *s;
+ bool hrtf;
+ int i, n;
+
+ def = alcGetString(nil, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
+ if(ALERR())
+ def = nil;
+ all = alcGetString(nil, ALC_ALL_DEVICES_SPECIFIER);
+ if(ALERR())
+ all = nil;
+
+ if(var == &s_al_dev && Cmd_Argc() == 1){
+ Con_Printf("%-2d: default (%s)\n", 0, def ? def : "<invalid>");
+ for(i = 1, s = all; s != nil && *s; i++){
+ Con_Printf("%-2d: %s%s\n", i, s, strcmp(s, def) == 0 ? " (default)" : "");
+ s += strlen(s)+1;
+ }
+ return;
+ }
+
+ alreinit(def, all);
+
+ if(alcIsExtensionPresent(dev, "ALC_SOFT_HRTF")){
+ qalcGetStringiSOFT = alcGetProcAddress(dev, "alcGetStringiSOFT");
+ qalcResetDeviceSOFT = alcGetProcAddress(dev, "alcResetDeviceSOFT");
+ hrtf = true;
+ }else{
+ qalcGetStringiSOFT = nil;
+ qalcResetDeviceSOFT = nil;
+ hrtf = false;
+ }
+ if(var == &s_al_hrtf && Cmd_Argc() == 1){
+ Con_Printf("%-2d: disabled\n", -1);
+ Con_Printf("%-2d: don't care (default)\n", 0);
+ if(qalcGetStringiSOFT == nil)
+ return;
+ alcGetIntegerv(dev, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &n); ALERR();
+ for(i = 0; i < n; i++){
+ s = qalcGetStringiSOFT(dev, ALC_HRTF_SPECIFIER_SOFT, i);
+ if(!ALERR() && s != nil)
+ Con_Printf("%-2d: %s\n", i+1, s);
+ }
+ return;
+ }
+
+ if(qalcResetDeviceSOFT != nil){
+ qalcResetDeviceSOFT(dev, alcattr(hrtf));
+ ALERR();
+ }
+}
+
+static void
+aldopplercb(cvar_t *var)
+{
+ alDopplerFactor(var->value); ALERR();
+}
+
+static void
+sfxlist(void)
+{
+ int sz, sum, w, ch;
+ Sfx *sfx, *e;
+ albuf_t *b;
+
+ sum = 0;
+ for(sfx = known_sfx, e = known_sfx+num_sfx; sfx < e; sfx++){
+ if((b = Cache_Check(&sfx->cu)) == nil)
+ continue;
+ alGetBufferi(b->buf, AL_SIZE, &sz); ALERR();
+ alGetBufferi(b->buf, AL_CHANNELS, &ch); ALERR();
+ alGetBufferi(b->buf, AL_BITS, &w); ALERR();
+ sum += sz * ch * w/8;
+ Con_Printf("%c(%2db) %6d : %s\n", b->loop ? 'L' : ' ', w, sz, sfx->s);
+ }
+ Con_Printf("Total resident: %d\n", sum);
+}
+
+void
+sfxbegin(void)
+{
+ map++;
+}
+
+void
+sfxend(void)
+{
+ albuf_t *b;
+ Sfx *sfx;
+ int i;
+
+ ambsfx[Ambwater] = precachesfx("ambience/water1.wav");
+ ambsfx[Ambsky] = precachesfx("ambience/wind2.wav");
+ for(i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++){
+ if(sfx->map >= map || sfx == ambsfx[Ambsky] || sfx == ambsfx[Ambwater])
+ continue;
+ if((b = Cache_Check(&sfx->cu)) != nil){
+ alDeleteBuffers(1, &b->buf); ALERR();
+ Cache_Free(&sfx->cu);
+ }
+ }
+}
+
+void
+stepcd(void)
+{
+ alSourcef(track.src, AL_GAIN, bgmvolume.value); ALERR();
+}
+
+static ALsizei
+trackcb(ALvoid *aux, ALvoid *sampledata, ALsizei numbytes)
+{
+ ssize_t n;
+ byte *b;
+
+ USED(aux);
+ for(b = sampledata; numbytes > 0; b += n, numbytes -= n){
+ if((n = read(track.pcm, b, numbytes)) <= 0){
+ close(track.pcm);
+ track.pcm = -1;
+ break;
+ }
+ }
+
+ return b - (byte*)sampledata;
+}
+
+void
+playcd(int nt, bool loop)
+{
+ pid_t pid;
+ FILE *f;
+ fpos_t off;
+ int len, left, s[2], in[2];
+
+ stopcd();
+ if(qalBufferCallbackSOFT == nil)
+ return;
+
+ if((f = openlmp(va("music/track%02d.ogg", nt), &len)) == nil){
+ if((f = openlmp(va("music/track%02d.mp3", nt), &len)) == nil)
+ f = openlmp(va("music/track%02d.wav", nt), &len);
+ }
+ if(f == nil)
+ return;
+ if(fgetpos(f, &off) != 0){
+err:
+ close(track.pcm);
+ fclose(f);
+ if(track.decoder > 0)
+ waitpid(track.decoder, nil, 0);
+ if(track.reader > 0)
+ waitpid(track.reader, nil, 0);
+ return;
+ }
+
+ if(pipe(s) != 0)
+ goto err;
+ if(pipe(in) != 0){
+ close(s[0]);
+ close(s[1]);
+ goto err;
+ }
+
+ switch((pid = fork())){
+ case 0:
+ close(s[1]); dup2(s[0], 0);
+ close(in[0]); dup2(in[1], 1);
+ close(s[0]);
+ execl(
+ "/usr/bin/env", "/usr/bin/env",
+ "ffmpeg",
+ "-loglevel", "fatal",
+ "-i", "-",
+ "-acodec", "pcm_s16le",
+ "-f", "s16le",
+ "-ac", "2",
+ "-ar", "44100",
+ "-",
+ nil
+ );
+ perror("execl ffmpeg"); // FIXME(sigrid): add and use Con_Errorf?
+ exit(1);
+ case -1:
+ goto err;
+ }
+ track.decoder = pid;
+
+ close(s[0]);
+ close(in[1]);
+ track.pcm = in[0];
+ cdloop = loop;
+ cdtrk = nt;
+
+ switch((pid = fork())){
+ case 0:
+ close(in[0]);
+ close(0);
+ close(1);
+ left = len;
+ for(;;){
+ byte tmp[32768];
+ ssize_t n;
+ if((n = fread(tmp, 1, min(left, (int)sizeof(tmp)), f)) < 1){
+ if(ferror(f)){
+ perror("fread");
+ break;
+ }
+ }
+ if(write(s[1], tmp, n) != n)
+ break;
+ left -= n;
+ if(left < 1){
+ if(!loop)
+ break;
+ if(fsetpos(f, &off) != 0){
+ perror("fsetpos");
+ break;
+ }
+ left = len;
+ }
+ }
+ close(s[1]);
+ fclose(f);
+ exit(1);
+ case -1:
+ goto err;
+ }
+ track.reader = pid;
+
+ qalBufferCallbackSOFT(track.buf, AL_FORMAT_STEREO16, 44100, trackcb, nil);
+ if(ALERR())
+ goto err;
+ alSourcei(track.src, AL_BUFFER, track.buf); ALERR();
+ alSourcePlay(track.src); ALERR();
+ track.playing = true;
+}
+
+void
+resumecd(void)
+{
+ alSourcePlay(track.src); ALERR();
+}
+
+void
+pausecd(void)
+{
+ alSourcePause(track.src); ALERR();
+}
+
+int
+initcd(void)
+{
+ cdntrk = cdtrk = 0;
+ cdloop = false;
+ return 0;
+}
+
+void
+stopcd(void)
+{
+ if(track.playing){
+ alSourceStop(track.src); ALERR();
+ alSourcei(track.src, AL_BUFFER, 0); ALERR();
+ if(track.pcm >= 0)
+ close(track.pcm);
+ waitpid(track.decoder, nil, 0);
+ waitpid(track.reader, nil, 0);
+ }
+ track.playing = false;
+ track.pcm = -1;
+ track.decoder = track.reader = -1;
+}
+
+void
+shutcd(void)
+{
+ stopcd();
+}
+
+int
+initsnd(void)
+{
+ s_al_dev.cb = s_al_hrtf.cb = alvarcb;
+ s_al_doppler_factor.cb = aldopplercb;
+
+ Cvar_RegisterVariable(&volume);
+ Cvar_RegisterVariable(&bgmvolume);
+ Cvar_RegisterVariable(&ambient_level);
+ Cvar_RegisterVariable(&ambient_fade);
+ Cvar_RegisterVariable(&s_al_dev);
+ Cvar_RegisterVariable(&s_al_resampler_default);
+ Cvar_RegisterVariable(&s_al_resampler_up);
+ Cvar_RegisterVariable(&s_al_hrtf);
+ Cvar_RegisterVariable(&s_al_doppler_factor);
+ Cmd_AddCommand("stopsound", stopallsfx);
+ Cmd_AddCommand("soundlist", sfxlist);
+ Cmd_AddCommand("cd", cdcmd);
+
+ alinit(nil);
+ known_sfx = Hunk_Alloc(MAX_SOUNDS * sizeof *known_sfx);
+ num_sfx = 0;
+
+ return 0;
+}
+
+void
+sndclose(void)
+{
+ if(dev == nil)
+ return;
+ alcDestroyContext(ctx); ctx = nil; ALERR();
+ alcCloseDevice(dev); dev = nil; ALERR();
+}
--- /dev/null
+++ b/sys_plan9.c
@@ -1,0 +1,168 @@
+#include "quakedef.h"
+#include <thread.h>
+
+int mainstacksize = 1*1024*1024;
+char *netmtpt = "/net";
+char *game;
+int debug;
+
+int
+sys_mkdir(char *path)
+{
+ int d;
+
+ if(access(path, AEXIST) == 0)
+ return 0;
+ if((d = create(path, OREAD, DMDIR|0777)) < 0){
+ Con_DPrintf("Sys_mkdir: create: %r\n");
+ return -1;
+ }
+ close(d);
+ return 0;
+}
+
+char *
+sys_timestamp(void)
+{
+ static char ts[32];
+ Tm *tm;
+ long t;
+
+ if((t = time(nil)) < 0 || (tm = localtime(t)) == nil)
+ return nil;
+ snprint(ts, sizeof(ts),
+ "%04d%02d%02d-%02d%02d%02d",
+ tm->year + 1900, tm->mon + 1, tm->mday, tm->hour, tm->min, tm->sec
+ );
+
+ return ts;
+}
+
+char *
+lerr(void)
+{
+ static char err[ERRMAX];
+ rerrstr(err, sizeof(err));
+ return err;
+}
+
+_Noreturn void
+fatal(char *fmt, ...)
+{
+ char s[1024];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(s, s+sizeof s, fmt, arg);
+ va_end(arg);
+ Host_Shutdown();
+ sysfatal("%s", s);
+}
+
+void *
+emalloc(long n)
+{
+ void *p;
+
+ if(p = mallocz(n, 1), p == nil)
+ sysfatal("emalloc %r");
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
+
+vlong
+flen(int fd)
+{
+ vlong l;
+ Dir *d;
+
+ if((d = dirfstat(fd)) == nil) /* file assumed extant and readable */
+ sysfatal("flen: %r");
+ l = d->length;
+ free(d);
+ return l;
+}
+
+double
+dtime(void)
+{
+ return nanosec() / 1000000000.0;
+}
+
+void
+game_shutdown(void)
+{
+ stopfb();
+ Host_Shutdown();
+ threadexitsall(nil);
+}
+
+static void
+croak(void *, char *note)
+{
+ if(strncmp(note, "sys:", 4) == 0){
+ IN_Grabm(0);
+ threadkillgrp(0);
+ }
+ noted(NDFLT);
+}
+
+static void
+usage(void)
+{
+ fprint(2, "usage: %s [-d] [-g game] [-m kB] [-x netmtpt]\n", argv0);
+ exits("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ double t, t´, Δt;
+ char *e;
+ static char *paths[] = {
+ "/sys/games/lib/quake",
+ nil,
+ nil,
+ };
+
+ ARGBEGIN{
+ case 'D':
+ debug = 1;
+ break;
+ case 'd':
+ dedicated = 1;
+ break;
+ case 'g':
+ game = EARGF(usage());
+ break;
+ case 'x':
+ netmtpt = EARGF(usage());
+ break;
+ default: usage();
+ }ARGEND
+ srand(getpid());
+ /* ignore fp exceptions: rendering shit assumes they are */
+ setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV));
+ notify(croak);
+
+ e = getenv("home");
+ paths[1] = smprint("%s/lib/quake", e);
+ free(e);
+ Host_Init(argc, argv, paths);
+
+ t = dtime() - 1.0 / Fpsmax;
+ for(;;){
+ t´ = dtime();
+ Δt = t´ - t;
+ if(cls.state == ca_dedicated){
+ if(Δt < sys_ticrate.value)
+ continue;
+ Δt = sys_ticrate.value;
+ }
+ if(Δt > sys_ticrate.value * 2)
+ t = t´;
+ else
+ t += Δt;
+ Host_Frame(Δt);
+ }
+}
--- /dev/null
+++ b/sys_unix.c
@@ -1,0 +1,167 @@
+#include "quakedef.h"
+#include "parg.h"
+#include <time.h>
+#include <errno.h>
+#include <fenv.h>
+
+char *game;
+int debug;
+char lasterr[256] = {0};
+
+char *
+lerr(void)
+{
+ static char lasterrcopy[256];
+ if(*lasterr == 0 && errno != 0)
+ return strerror(errno);
+ strcpy(lasterrcopy, lasterr);
+ return lasterrcopy;
+}
+
+int
+sys_mkdir(char *path)
+{
+ return (mkdir(path, 0770) == 0 || errno == EEXIST) ? 0 : -1;
+}
+
+char *
+sys_timestamp(void)
+{
+ static char ts[32];
+ struct tm *tm;
+ time_t t;
+
+ if((t = time(nil)) == (time_t)-1 || (tm = localtime(&t)) == nil)
+ return nil;
+ snprint(ts, sizeof(ts),
+ "%04d%02d%02d-%02d%02d%02d",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec
+ );
+
+ return ts;
+}
+
+int
+nrand(int n)
+{
+ return random() % n;
+}
+
+void
+fatal(char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ vfprintf(stderr, fmt, arg);
+ va_end(arg);
+ Host_Shutdown();
+ exit(1);
+}
+
+void *
+emalloc(long n)
+{
+ void *p;
+
+ if(p = calloc(1, n), p == nil)
+ fatal("emalloc");
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
+
+uvlong
+nanosec(void)
+{
+ static time_t sec0;
+ struct timespec t;
+
+ if(clock_gettime(CLOCK_MONOTONIC, &t) != 0)
+ fatal("clock_gettime");
+ if(sec0 == 0)
+ sec0 = t.tv_sec;
+ t.tv_sec -= sec0;
+ return t.tv_sec*1000000000ULL + t.tv_nsec;
+}
+
+double
+dtime(void)
+{
+ return nanosec()/1000000000.0;
+}
+
+void
+game_shutdown(void)
+{
+ stopfb();
+ Host_Shutdown();
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ double t, t2, dt;
+ struct parg_state ps;
+ int c, nargs;
+ static char *paths[] = {
+ "/usr/games/quake",
+ nil,
+ nil,
+ };
+
+ parg_init(&ps);
+ nargs = 0;
+ while((c = parg_getopt(&ps, argc, argv, "Ddg:")) >= 0){
+ switch(c){
+ case 1:
+ argv[nargs++] = (char*)ps.optarg;
+ break;
+ case 'D':
+ debug++;
+ break;
+ case 'd':
+ dedicated = 1;
+ break;
+ case 'g':
+ game = (char*)ps.optarg;
+ break;
+ case 'h':
+ fprintf(stderr, "usage: qk1 [-g game]\n");
+ return 0;
+ break;
+ case '?':
+ fprintf(stderr, "unknown option -%c\n", ps.optopt);
+ return 1;
+ break;
+ default:
+ fprintf(stderr, "unhandled option -%c\n", c);
+ return 1;
+ break;
+ }
+ }
+
+ srand(nanosec() + time(nil));
+
+ paths[1] = strdup(va("%s/.quake", getenv("HOME")));
+ Host_Init(nargs, argv, paths);
+
+ fesetround(FE_TOWARDZERO);
+
+ t = dtime() - 1.0 / Fpsmax;
+ for(;;){
+ t2 = dtime();
+ dt = t2 - t;
+ if(cls.state == ca_dedicated){
+ if(dt < sys_ticrate.value)
+ continue;
+ dt = sys_ticrate.value;
+ }
+ if(dt > sys_ticrate.value * 2)
+ t = t2;
+ else
+ t += dt;
+ Host_Frame(dt);
+ }
+ return 0;
+}
--- a/unix/in.c
+++ /dev/null
@@ -1,177 +1,0 @@
-#include "quakedef.h"
-#include <SDL.h>
-
-/* vid.c */
-extern int resized;
-
-static cvar_t m_windowed = {"m_windowed", "1", true};
-static cvar_t m_filter = {"m_filter", "0", true};
-static cvar_t m_raw = {"m_raw", "1", true};
-static int mouseon, oldmwin, focuslost;
-static float dx, dy, olddx, olddy;
-
-static int mbuttons[] = {
- K_MOUSE1,
- K_MOUSE3,
- K_MOUSE2,
-};
-
-void
-conscmd(void)
-{
-}
-
-void
-Sys_SendKeyEvents(void)
-{
- SDL_Event event;
- int key, b;
-
- if(cls.state == ca_dedicated)
- return;
- if(oldmwin != (int)m_windowed.value){
- oldmwin = (int)m_windowed.value;
- IN_Grabm(oldmwin);
- }
-
- while(SDL_PollEvent(&event)){
- switch(event.type){
- case SDL_QUIT:
- Cbuf_AddText("menu_quit\n");
- break;
- case SDL_WINDOWEVENT:
- switch(event.window.event){
- case SDL_WINDOWEVENT_RESIZED:
- resized = 1;
- break;
- case SDL_WINDOWEVENT_CLOSE:
- Cbuf_AddText("menu_quit\n");
- break;
- case SDL_WINDOWEVENT_LEAVE:
- focuslost = mouseon;
- IN_Grabm(0);
- break;
- case SDL_WINDOWEVENT_ENTER:
- IN_Grabm(focuslost);
- break;
- }
- break;
- case SDL_MOUSEMOTION:
- if(mouseon){
- dx += event.motion.xrel;
- dy += event.motion.yrel;
- }
- break;
- case SDL_MOUSEBUTTONDOWN:
- case SDL_MOUSEBUTTONUP:
- if(mouseon && (b = event.button.button-1) >= 0 && b < nelem(mbuttons))
- Key_Event(mbuttons[b], event.type == SDL_MOUSEBUTTONDOWN);
- break;
- case SDL_KEYDOWN:
- case SDL_KEYUP:
- switch(key = event.key.keysym.sym){
- case SDLK_BACKQUOTE: key = '~'; break;
- case SDLK_DELETE: key = K_DEL; break;
- case SDLK_BACKSPACE: key = K_BACKSPACE; break;
- case SDLK_F1: key = K_F1; break;
- case SDLK_F2: key = K_F2; break;
- case SDLK_F3: key = K_F3; break;
- case SDLK_F4: key = K_F4; break;
- case SDLK_F5: key = K_F5; break;
- case SDLK_F6: key = K_F6; break;
- case SDLK_F7: key = K_F7; break;
- case SDLK_F8: key = K_F8; break;
- case SDLK_F9: key = K_F9; break;
- case SDLK_F10: key = K_F10; break;
- case SDLK_F11: key = K_F11; break;
- case SDLK_F12: key = K_F12; break;
- case SDLK_PAUSE: key = K_PAUSE; break;
- case SDLK_UP: key = K_UPARROW; break;
- case SDLK_DOWN: key = K_DOWNARROW; break;
- case SDLK_RIGHT: key = K_RIGHTARROW; break;
- case SDLK_LEFT: key = K_LEFTARROW; break;
- case SDLK_RSHIFT:
- case SDLK_LSHIFT: key = K_SHIFT; break;
- case SDLK_RCTRL:
- case SDLK_LCTRL: key = K_CTRL; break;
- case SDLK_RALT:
- case SDLK_LALT: key = K_ALT; break;
- default:
- if(key >= 128)
- key = 0;
- break;
- }
- if(key > 0)
- Key_Event(key, event.key.state);
- break;
- }
- }
-}
-
-void
-IN_Commands(void)
-{
-}
-
-static void
-m_raw_cb(cvar_t *var)
-{
- SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, var->value > 0 ? "0" : "1");
-}
-
-void
-IN_Move(usercmd_t *cmd)
-{
- if(!mouseon)
- return;
-
- if(m_filter.value){
- dx = (dx + olddx) * 0.5;
- dy = (dy + olddy) * 0.5;
- }
- olddx = dx;
- olddy = dy;
- dx *= sensitivity.value;
- dy *= sensitivity.value;
- if(in_strafe.state & 1 || (lookstrafe.value && in_mlook.state & 1))
- cmd->sidemove += m_side.value * dx;
- else
- cl.viewangles[YAW] -= m_yaw.value * dx;
- if(in_mlook.state & 1)
- V_StopPitchDrift();
- if(in_mlook.state & 1 && ~in_strafe.state & 1){
- cl.viewangles[PITCH] += m_pitch.value * dy;
- if(cl.viewangles[PITCH] > 80)
- cl.viewangles[PITCH] = 80;
- if(cl.viewangles[PITCH] < -70)
- cl.viewangles[PITCH] = -70;
- }else{
- if(in_strafe.state & 1 && noclip_anglehack)
- cmd->upmove -= m_forward.value * dy;
- else
- cmd->forwardmove -= m_forward.value * dy;
- }
- dx = 0;
- dy = 0;
-}
-
-void
-IN_Grabm(int on)
-{
- SDL_SetRelativeMouseMode(mouseon = on);
-}
-
-void
-IN_Shutdown(void)
-{
- IN_Grabm(0);
-}
-
-void
-IN_Init(void)
-{
- m_raw.cb = m_raw_cb;
- Cvar_RegisterVariable(&m_windowed);
- Cvar_RegisterVariable(&m_filter);
- Cvar_RegisterVariable(&m_raw);
-}
--- a/unix/net_udp.c
+++ /dev/null
@@ -1,361 +1,0 @@
-#include "quakedef.h"
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-extern cvar_t hostname;
-
-static int net_acceptsocket = -1; // socket for fielding new connections
-static int net_controlsocket;
-static int net_broadcastsocket = 0;
-static Addr broadcastaddr;
-
-static unsigned long myAddr;
-Addr myip;
-
-static int UDP_OpenSocket (int port);
-static int UDP_GetSocketAddr (int socket, Addr *addr);
-static int UDP_CloseSocket (int socket);
-
-//=============================================================================
-
-int UDP_Init (void)
-{
- struct hostent *local;
- char buff[MAXHOSTNAMELEN];
-
- // determine my name & address
- gethostname(buff, MAXHOSTNAMELEN);
- local = gethostbyname(buff);
- myAddr = *(int *)local->h_addr_list[0];
-
- // if the quake hostname isn't set, set it to the machine name
- if (strcmp(hostname.string, "UNNAMED") == 0)
- {
- buff[15] = 0;
- setcvar ("hostname", buff);
- }
-
- if ((net_controlsocket = UDP_OpenSocket (0)) == -1)
- Host_Error("UDP_Init: Unable to open control socket\n");
-
- ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
- ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
- ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(Udpport);
-
- UDP_GetSocketAddr (net_controlsocket, &myip);
-
- return net_controlsocket;
-}
-
-//=============================================================================
-
-void UDP_Shutdown (void)
-{
- UDP_Listen (false);
- UDP_CloseSocket (net_controlsocket);
-}
-
-//=============================================================================
-
-void UDP_Listen (bool state)
-{
- // enable listening
- if (state)
- {
- if (net_acceptsocket != -1)
- return;
- if ((net_acceptsocket = UDP_OpenSocket (Udpport)) == -1)
- Host_Error ("UDP_Listen: Unable to open accept socket\n");
- return;
- }
-
- // disable listening
- if (net_acceptsocket == -1)
- return;
- UDP_CloseSocket (net_acceptsocket);
- net_acceptsocket = -1;
-}
-
-//=============================================================================
-
-static int UDP_OpenSocket (int port)
-{
- int newsocket;
- struct sockaddr_in address;
-
- if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
- return -1;
-
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = INADDR_ANY;
- address.sin_port = htons(port);
- if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
- goto ErrorReturn;
-
- return newsocket;
-
-ErrorReturn:
- close (newsocket);
- return -1;
-}
-
-//=============================================================================
-
-static int UDP_CloseSocket (int socket)
-{
- if (socket == net_broadcastsocket)
- net_broadcastsocket = 0;
- return close (socket);
-}
-
-//=============================================================================
-/*
-============
-PartialIPAddress
-
-this lets you type only as much of the net address as required, using
-the local network components to fill in the rest
-============
-*/
-static int PartialIPAddress (char *in, Addr *hostaddr)
-{
- char buff[256];
- char *b;
- int addr;
- int num;
- int mask;
- int run;
- int port;
-
- buff[0] = '.';
- b = buff;
- strcpy(buff+1, in);
- if (buff[1] == '.')
- b++;
-
- addr = 0;
- mask=-1;
- while (*b == '.')
- {
- b++;
- num = 0;
- run = 0;
- while (!( *b < '0' || *b > '9'))
- {
- num = num*10 + *b++ - '0';
- if (++run > 3)
- return -1;
- }
- if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
- return -1;
- if (num < 0 || num > 255)
- return -1;
- mask<<=8;
- addr = (addr<<8) + num;
- }
-
- if (*b++ == ':')
- port = strtol(b, NULL, 0);
- else
- port = Udpport;
-
- ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
- ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
-
- return 0;
-}
-//=============================================================================
-
-int UDP_Connect (Addr *addr)
-{
- USED(addr);
- return 0;
-}
-
-//=============================================================================
-
-int UDP_CheckNewConnections (void)
-{
- unsigned long available;
-
- if (net_acceptsocket == -1)
- return -1;
-
- if (ioctl (net_acceptsocket, FIONREAD, &available) == -1)
- Host_Error ("UDP: ioctlsocket (FIONREAD) failed\n");
- if (available)
- return net_acceptsocket;
- return -1;
-}
-
-//=============================================================================
-
-int UDP_Read (int socket, uint8_t *buf, int len, Addr *addr)
-{
- socklen_t addrlen = sizeof (Addr);
- int ret;
-
- ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
- if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED))
- return 0;
- return ret;
-}
-
-//=============================================================================
-
-int UDP_MakeSocketBroadcastCapable (int socket)
-{
- int i = 1;
-
- // make this socket broadcast capable
- if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
- return -1;
- net_broadcastsocket = socket;
-
- return 0;
-}
-
-//=============================================================================
-
-static int UDP_Write (int socket, uint8_t *buf, int len, Addr *addr)
-{
- int ret;
-
- ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(Addr));
- if (ret == -1 && errno == EWOULDBLOCK)
- return 0;
- return ret;
-}
-
-//=============================================================================
-
-int UDP_Broadcast (int socket, uint8_t *buf, int len)
-{
- int ret;
-
- if (socket != net_broadcastsocket)
- {
- if (net_broadcastsocket != 0)
- Host_Error("Attempted to use multiple broadcasts sockets\n");
- ret = UDP_MakeSocketBroadcastCapable (socket);
- if (ret == -1)
- {
- Con_Printf("Unable to make socket broadcast capable\n");
- return ret;
- }
- }
-
- return UDP_Write (socket, buf, len, &broadcastaddr);
-}
-
-//=============================================================================
-
-char *UDP_AddrToString (Addr *addr)
-{
- static char buffer[22];
- int haddr;
-
- haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
- sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
- return buffer;
-}
-
-//=============================================================================
-
-int UDP_StringToAddr (char *string, Addr *addr)
-{
- int ha1, ha2, ha3, ha4, hp;
- int ipaddr;
-
- sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
- ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
-
- ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
- ((struct sockaddr_in *)addr)->sin_port = htons(hp);
- return 0;
-}
-
-//=============================================================================
-
-static int UDP_GetSocketAddr (int socket, Addr *addr)
-{
- socklen_t addrlen = sizeof(Addr);
- unsigned int a;
-
- memset(addr, 0, sizeof(Addr));
- getsockname(socket, (struct sockaddr *)addr, &addrlen);
- a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
- if (a == 0 || a == inet_addr("127.0.0.1"))
- ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
-
- return 0;
-}
-
-//=============================================================================
-
-int UDP_GetNameFromAddr (Addr *addr, char *name)
-{
- struct hostent *hostentry;
-
- hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
- if (hostentry)
- {
- strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
- return 0;
- }
-
- strcpy (name, UDP_AddrToString (addr));
- return 0;
-}
-
-//=============================================================================
-
-int UDP_GetAddrFromName(char *name, Addr *addr)
-{
- struct hostent *hostentry;
-
- if (name[0] >= '0' && name[0] <= '9')
- return PartialIPAddress (name, addr);
-
- hostentry = gethostbyname (name);
- if (!hostentry)
- return -1;
-
- ((struct sockaddr_in *)addr)->sin_port = htons(Udpport);
- ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
-
- return 0;
-}
-
-//=============================================================================
-
-int UDP_AddrCompare (Addr *addr1, Addr *addr2)
-{
- if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
- return -1;
-
- if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
- return 1;
-
- return 0;
-}
-
-//=============================================================================
-
-u16int UDP_GetSocketPort (Addr *addr)
-{
- return ntohs(((struct sockaddr_in *)addr)->sin_port);
-}
-
-void UDP_SetSocketPort (Addr *addr, u16int port)
-{
- ((struct sockaddr_in *)addr)->sin_port = htons(port);
-}
-
-//=============================================================================
--- a/unix/qk1.c
+++ /dev/null
@@ -1,167 +1,0 @@
-#include "quakedef.h"
-#include "parg.h"
-#include <time.h>
-#include <errno.h>
-#include <fenv.h>
-
-char *game;
-int debug;
-char lasterr[256] = {0};
-
-char *
-lerr(void)
-{
- static char lasterrcopy[256];
- if(*lasterr == 0 && errno != 0)
- return strerror(errno);
- strcpy(lasterrcopy, lasterr);
- return lasterrcopy;
-}
-
-int
-sys_mkdir(char *path)
-{
- return (mkdir(path, 0770) == 0 || errno == EEXIST) ? 0 : -1;
-}
-
-char *
-sys_timestamp(void)
-{
- static char ts[32];
- struct tm *tm;
- time_t t;
-
- if((t = time(nil)) == (time_t)-1 || (tm = localtime(&t)) == nil)
- return nil;
- snprint(ts, sizeof(ts),
- "%04d%02d%02d-%02d%02d%02d",
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec
- );
-
- return ts;
-}
-
-int
-nrand(int n)
-{
- return random() % n;
-}
-
-void
-fatal(char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- vfprintf(stderr, fmt, arg);
- va_end(arg);
- Host_Shutdown();
- exit(1);
-}
-
-void *
-emalloc(long n)
-{
- void *p;
-
- if(p = calloc(1, n), p == nil)
- fatal("emalloc");
- setmalloctag(p, getcallerpc(&n));
- return p;
-}
-
-uvlong
-nanosec(void)
-{
- static time_t sec0;
- struct timespec t;
-
- if(clock_gettime(CLOCK_MONOTONIC, &t) != 0)
- fatal("clock_gettime");
- if(sec0 == 0)
- sec0 = t.tv_sec;
- t.tv_sec -= sec0;
- return t.tv_sec*1000000000ULL + t.tv_nsec;
-}
-
-double
-dtime(void)
-{
- return nanosec()/1000000000.0;
-}
-
-void
-game_shutdown(void)
-{
- stopfb();
- Host_Shutdown();
- exit(0);
-}
-
-int
-main(int argc, char **argv)
-{
- double t, t2, dt;
- struct parg_state ps;
- int c, nargs;
- static char *paths[] = {
- "/usr/games/quake",
- nil,
- nil,
- };
-
- parg_init(&ps);
- nargs = 0;
- while((c = parg_getopt(&ps, argc, argv, "Ddg:")) >= 0){
- switch(c){
- case 1:
- argv[nargs++] = (char*)ps.optarg;
- break;
- case 'D':
- debug++;
- break;
- case 'd':
- dedicated = 1;
- break;
- case 'g':
- game = (char*)ps.optarg;
- break;
- case 'h':
- fprintf(stderr, "usage: qk1 [-g game]\n");
- return 0;
- break;
- case '?':
- fprintf(stderr, "unknown option -%c\n", ps.optopt);
- return 1;
- break;
- default:
- fprintf(stderr, "unhandled option -%c\n", c);
- return 1;
- break;
- }
- }
-
- srand(nanosec() + time(nil));
-
- paths[1] = strdup(va("%s/.quake", getenv("HOME")));
- Host_Init(nargs, argv, paths);
-
- fesetround(FE_TOWARDZERO);
-
- t = dtime() - 1.0 / Fpsmax;
- for(;;){
- t2 = dtime();
- dt = t2 - t;
- if(cls.state == ca_dedicated){
- if(dt < sys_ticrate.value)
- continue;
- dt = sys_ticrate.value;
- }
- if(dt > sys_ticrate.value * 2)
- t = t2;
- else
- t += dt;
- Host_Frame(dt);
- }
- return 0;
-}
--- a/unix/seprint.c
+++ /dev/null
@@ -1,19 +1,0 @@
-#include <stdio.h>
-#include <stdarg.h>
-
-char *
-seprint(char *buf, char *e, char *fmt, ...)
-{
- va_list a;
- int n, m;
-
- if(e <= buf)
- return e;
-
- va_start(a, fmt);
- m = e-buf-1;
- n = vsnprintf(buf, m, fmt, a);
- va_end(a);
-
- return buf + (n < m ? n : m);
-}
--- a/unix/snd_openal.c
+++ /dev/null
@@ -1,880 +1,0 @@
-#include "quakedef.h"
-#include <AL/al.h>
-#include <AL/alc.h>
-#include <AL/alext.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-typedef struct albuf_t albuf_t;
-typedef struct alchan_t alchan_t;
-
-struct albuf_t {
- ALuint buf;
- bool loop;
- bool upsample;
-};
-
-struct alchan_t {
- int ent;
- int ch;
- ALuint src;
-
- alchan_t *prev, *next;
-};
-
-enum {
- Srcstatic = -666,
- Srcamb,
-};
-
-cvar_t volume = {"volume", "0.7", true};
-
-static struct {
- ALuint src, buf;
- int pcm;
- bool playing;
- pid_t decoder, reader;
-}track;
-
-static cvar_t s_al_dev = {"s_al_device", "0", true};
-static int s_al_dev_prev = -1;
-
-static cvar_t s_al_hrtf = {"s_al_hrtf", "0", true};
-static cvar_t s_al_doppler_factor = {"s_al_doppler_factor", "2", true};
-static cvar_t s_al_resampler_default = {"s_al_resampler_default", "6", true}; // 23rd order Sinc
-static cvar_t s_al_resampler_up = {"s_al_resampler_up", "1", true}; // Linear
-
-static ALCcontext *ctx;
-static ALCdevice *dev;
-static Sfx *known_sfx;
-static int num_sfx;
-static int map;
-static alchan_t *chans;
-
-static cvar_t ambient_level = {"ambient_level", "0.3"};
-static cvar_t ambient_fade = {"ambient_fade", "100"};
-static Sfx *ambsfx[Namb];
-static float ambvol[Namb];
-
-static int al_default_resampler, al_num_resamplers;
-static ALchar *(*qalGetStringiSOFT)(ALenum, ALsizei);
-static ALCchar *(*qalcGetStringiSOFT)(ALCdevice *, ALenum, ALsizei);
-static ALCboolean (*qalcResetDeviceSOFT)(ALCdevice *, const ALCint *attr);
-static ALCboolean *(*qalcReopenDeviceSOFT)(ALCdevice *, const ALCchar *devname, const ALCint *attr);
-static void (*qalBufferCallbackSOFT)(ALuint buf, ALenum fmt, ALsizei freq, ALBUFFERCALLBACKTYPESOFT cb, ALvoid *aux);
-
-#define ALERR() alcheckerr(__FILE__, __LINE__)
-
-static int
-alcheckerr(const char *file, int line)
-{
- int e, ret;
- char *s, tmp[32];
-
- ret = 0;
- if(ctx != nil && (e = alGetError()) != AL_NO_ERROR){
- switch(e){
- case AL_INVALID_NAME: s = "invalid name"; break;
- case AL_INVALID_ENUM: s = "invalid enum"; break;
- case AL_INVALID_VALUE: s = "invalid value"; break;
- case AL_INVALID_OPERATION: s = "invalid operation"; break;
- case AL_OUT_OF_MEMORY: s = "out of memory"; break;
- default:
- snprint(tmp, sizeof(tmp), "unknown (0x%x)", e);
- s = tmp;
- break;
- }
- ret |= e;
- fprintf(stderr, "AL: %s:%d: %s\n", file, line, s);
- }
- if(dev != nil && (e = alcGetError(dev)) != ALC_NO_ERROR){
- switch(e){
- case ALC_INVALID_DEVICE: s = "invalid device"; break;
- case ALC_INVALID_ENUM: s = "invalid enum"; break;
- case ALC_INVALID_VALUE: s = "invalid value"; break;
- case ALC_INVALID_CONTEXT: s = "invalid context"; break;
- case ALC_OUT_OF_MEMORY: s = "out of memory"; break;
- default:
- snprint(tmp, sizeof(tmp), "unknown error (0x%x)", e);
- s = tmp;
- break;
- }
- ret |= e;
- fprintf(stderr, "ALC: %s:%d: %s\n", file, line, s);
- }
-
- return ret;
-}
-
-static alchan_t *
-getchan(int ent, int ch)
-{
- alchan_t *c, *stopped;
- ALint state;
- ALuint src;
-
- stopped = nil;
- for(c = chans; c != nil; c = c->next){
- if(c->ent == ent && c->ch == ch)
- return c;
- if(stopped == nil){
- alGetSourcei(c->src, AL_SOURCE_STATE, &state);
- if(!ALERR() && state != AL_PLAYING)
- stopped = c;
- }
- }
-
- if(stopped != nil){
- c = stopped;
- c->ent = ent;
- c->ch = ch;
- return c;
- }
-
- alGenSources(1, &src);
- if(ALERR())
- return nil;
-
- c = calloc(1, sizeof(*c));
- c->ent = ent;
- c->ch = ch;
- c->src = src;
- c->next = chans;
- if(chans != nil)
- chans->prev = c;
- chans = c;
-
- return c;
-}
-
-static void
-delchan(alchan_t *c)
-{
- if(c->prev != nil)
- c->prev->next = c->next;
- if(c->next != nil)
- c->next->prev = c->prev;
- if(chans == c)
- chans = c->next;
- alSourceStop(c->src); ALERR();
- alSourcei(c->src, AL_BUFFER, 0); ALERR();
- alDeleteSources(1, &c->src); ALERR();
- free(c);
-}
-
-static Sfx *
-findsfx(char *s)
-{
- Sfx *sfx, *e;
- albuf_t *b;
-
- if(strlen(s) >= Npath)
- Host_Error("findsfx: path too long %s", s);
- sfx = known_sfx;
- e = known_sfx + num_sfx;
- while(sfx < e){
- if(strcmp(sfx->s, s) == 0){
- sfx->map = map;
- return sfx;
- }
- sfx++;
- }
- if(num_sfx == MAX_SOUNDS){
- sfx = known_sfx;
- while(sfx < e){
- if(sfx->map && sfx->map < map)
- break;
- sfx++;
- }
- if(sfx == e)
- Host_Error("findsfx: sfx list overflow: %s", s);
- if((b = Cache_Check(&sfx->cu)) != nil){
- alDeleteBuffers(1, &b->buf); ALERR();
- Cache_Free(&sfx->cu);
- sfx->map = map;
- }
- }else
- num_sfx++;
- strcpy(sfx->s, s);
- return sfx;
-}
-
-static albuf_t *
-loadsfx(Sfx *sfx)
-{
- ALint loop[2];
- wavinfo_t info;
- ALuint buf;
- ALenum fmt;
- albuf_t *b;
- byte *in;
- int len;
-
- if((b = Cache_Check(&sfx->cu)) != nil)
- return b;
- in = loadstklmp(va("sound/%s", sfx->s), nil, 0, &len);
- if(in == nil){
- Con_DPrintf("loadsfx: %s\n", lerr());
- return nil;
- }
- if(wavinfo(in, len, &info) != 0){
- Con_Printf("loadsfx: %s: %s\n", sfx->s, lerr());
- // complain but get some silence in place so it looks like it got loaded
- memset(&info, 0, sizeof(info));
- info.width = 8;
- info.channels = 1;
- info.rate = 11025;
- info.loopofs = -1;
- }
- if(info.channels < 2)
- fmt = info.width == 1 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16;
- else
- fmt = info.width == 1 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16;
- alGenBuffers(1, &buf);
- if(ALERR())
- return nil;
- alBufferData(buf, fmt, in+info.dataofs, info.samples*info.width, info.rate);
- if(ALERR()){
- alDeleteBuffers(1, &buf); ALERR();
- return nil;
- }
- b = Cache_Alloc(&sfx->cu, sizeof(*b));
- b->buf = buf;
- if(info.loopofs >= 0){
- loop[0] = info.loopofs;
- loop[1] = info.samples;
- alBufferiv(b->buf, AL_LOOP_POINTS_SOFT, loop); ALERR();
- b->loop = true;
- }
- b->upsample = info.rate < 22050;
-
- return b;
-}
-
-static void
-alplay(alchan_t *c, albuf_t *b, vec3_t zp, float vol, float att, bool rel, bool loop)
-{
- ALint src;
- int n;
-
- src = c->src;
- if(rel){
- alSourcefv(src, AL_POSITION, vec3_origin); ALERR();
- alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); ALERR();
- alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); ALERR();
- alSourcef(src, AL_REFERENCE_DISTANCE, 0.0f); ALERR();
- }else{
- alSourcefv(src, AL_POSITION, zp); ALERR();
- alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); ALERR();
- alSourcef(src, AL_ROLLOFF_FACTOR, att * 8.191); ALERR();
- alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f); ALERR();
- alSourcef(src, AL_MAX_DISTANCE, 8192.0f); ALERR();
- }
- alSourcef(src, AL_GAIN, vol); ALERR();
- if(al_num_resamplers > 0){
- n = b->upsample ? s_al_resampler_up.value : s_al_resampler_default.value;
- if(n >= 0){
- alSourcei(src, AL_SOURCE_RESAMPLER_SOFT, n);
- ALERR();
- }
- }
- alSourcei(src, AL_BUFFER, b->buf); ALERR();
- alSourcei(src, AL_LOOPING, (b->loop || loop) ? AL_TRUE : AL_FALSE); ALERR();
- alSourcePlay(src); ALERR();
-}
-
-
-static void
-ambs(vec3_t org)
-{
- float vol, *av;
- ALint state;
- alchan_t *ch;
- uchar *asl;
- mleaf_t *l;
- albuf_t *b;
- Sfx *sfx;
- int i;
-
- if(cl.worldmodel == nil)
- return;
- l = Mod_PointInLeaf(org, cl.worldmodel);
- asl = l->ambient_sound_level;
- for(i = 0; i < Namb; i++){
- if((sfx = ambsfx[i]) == nil || (b = loadsfx(sfx)) == nil)
- continue;
- vol = ambient_level.value * asl[i];
- av = &ambvol[i];
- if(vol < 8)
- vol = 0;
- if(*av < vol){
- *av += host_frametime * ambient_fade.value;
- if(*av > vol)
- *av = vol;
- }else if(*av > vol){
- *av -= host_frametime * ambient_fade.value;
- if(*av < vol)
- *av = vol;
- }
- if((ch = getchan(Srcamb, i)) != nil){
- alSourcef(ch->src, AL_GAIN, *av / 255.0f); ALERR();
- alGetSourcei(ch->src, AL_SOURCE_STATE, &state);
- if(!ALERR() && state != AL_PLAYING)
- alplay(ch, b, vec3_origin, *av, 0.0f, true, true);
- }
- }
-}
-
-void
-stepsnd(vec3_t zp, vec3_t fw, vec3_t rt, vec3_t up)
-{
- vec_t fwup[6] = {fw[0], fw[1], fw[2], up[0], up[1], up[2]};
- alchan_t *c, *next;
- static vec3_t ozp;
- ALint state;
- vec3_t vel;
-
- if(dev == nil)
- return;
- if(zp == vec3_origin && fw == vec3_origin && rt == vec3_origin){
- alListenerf(AL_GAIN, 0);
- ALERR();
- return;
- }
-
- alListenerfv(AL_POSITION, zp); ALERR();
- alListenerfv(AL_ORIENTATION, fwup); ALERR();
- VectorSubtract(zp, ozp, vel);
- VectorCopy(zp, ozp);
- alListenerfv(AL_VELOCITY, vel); ALERR();
- alListenerf(AL_GAIN, volume.value); ALERR();
-
- ambs(zp);
-
- for(c = chans; c != nil; c = next){
- next = c->next;
- alGetSourcei(c->src, AL_SOURCE_STATE, &state);
- if(!ALERR() && state != AL_PLAYING)
- delchan(c);
- }
-}
-
-void
-stopallsfx(void)
-{
- alchan_t *c, *next;
-
- if(dev == nil)
- return;
- alListenerf(AL_GAIN, 0); ALERR();
- for(c = chans; c != nil; c = next){
- next = c->next;
- delchan(c);
- }
- chans = nil;
- memset(ambvol, 0, sizeof(ambvol));
-}
-
-void
-stopsfx(int ent, int ch)
-{
- alchan_t *c;
-
- if(dev == nil)
- return;
- for(c = chans; c != nil; c = c->next){
- if(c->ent == ent && c->ch == ch)
- break;
- }
- if(c == nil)
- return;
- if(c->prev != nil)
- c->prev->next = c->next;
- if(c->next != nil)
- c->next->prev = c->prev;
- if(chans == c)
- chans = c->next;
- delchan(c);
- if(ent == Srcamb)
- ambvol[ch] = 0;
-}
-
-void
-startsfx(int ent, int ch, Sfx *sfx, vec3_t zp, float vol, float att)
-{
- alchan_t *c;
- albuf_t *b;
-
- if(dev == nil || (b = loadsfx(sfx)) == nil || (c = getchan(ent, ch)) == nil)
- return;
- alSourceStop(c->src); ALERR();
- alplay(c, b, zp, vol, att, ent == cl.viewentity, ent == Srcstatic);
-}
-
-void
-localsfx(char *name)
-{
- if(dev == nil)
- return;
-
- startsfx(cl.viewentity, -1, findsfx(name), vec3_origin, 1.0f, 1.0f);
-}
-
-void
-staticsfx(Sfx *sfx, vec3_t zp, float vol, float att)
-{
- static int numst = 0;
-
- if(dev == nil)
- return;
-
- startsfx(Srcstatic, numst++, sfx, zp, vol, att/1.5f);
-}
-
-void
-touchsfx(char *s)
-{
- Sfx *sfx;
-
- if(dev == nil)
- return;
- sfx = findsfx(s);
- Cache_Check(&sfx->cu);
-}
-
-Sfx *
-precachesfx(char *s)
-{
- Sfx *sfx;
-
- if(dev == nil)
- return nil;
- sfx = findsfx(s);
- sfx->map = map;
- loadsfx(sfx);
- return sfx;
-}
-
-static ALCint *
-alcattr(bool hrtf)
-{
- static ALCint attr[] = {
- 0, 0, 0, 0, 0,
- };
-
- attr[0] = 0;
- if(hrtf){
- attr[0] = s_al_hrtf.value != 0 ? ALC_HRTF_SOFT : 0;
- attr[1] = s_al_hrtf.value != 0 ? (s_al_hrtf.value > 0 ? ALC_TRUE : ALC_FALSE) : ALC_DONT_CARE_SOFT;
- if(attr[1] == ALC_TRUE){
- attr[2] = ALC_HRTF_ID_SOFT;
- attr[3] = s_al_hrtf.value - 1;
- }
- }
-
- return attr;
-}
-
-static int
-alinit(const char *devname)
-{
- ALCcontext *c;
- int e;
-
- dev = alcOpenDevice(devname); ALERR();
- if(dev == nil)
- return -1;
-
- c = alcCreateContext(dev, nil); ALERR();
- if(c == nil){
-closedev:
- alcCloseDevice(dev); ALERR();
- dev = nil;
- return -1;
- }
- ctx = c;
- e = alcMakeContextCurrent(c); ALERR();
- if(!e){
- ctx = nil;
- alcDestroyContext(c); ALERR();
- goto closedev;
- }
- alListenerf(AL_GAIN, volume.value); ALERR();
- alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); ALERR();
-
- // assuming 64 Quake units is ~1.7m
- alSpeedOfSound(343.3 * 64.0 / 1.7); ALERR();
- alDopplerFactor(s_al_doppler_factor.value); ALERR();
-
- if(alIsExtensionPresent("AL_SOFT_source_resampler")){
- al_default_resampler = alGetInteger(AL_DEFAULT_RESAMPLER_SOFT);
- if(ALERR())
- al_default_resampler = 0;
- al_num_resamplers = alGetInteger(AL_NUM_RESAMPLERS_SOFT);
- if(ALERR())
- al_num_resamplers = 0;
- qalGetStringiSOFT = alGetProcAddress("alGetStringiSOFT");
- }else{
- qalGetStringiSOFT = nil;
- }
-
- qalBufferCallbackSOFT = nil;
- if(alIsExtensionPresent("AL_SOFT_callback_buffer") && (alGenSources(1, &track.src), !ALERR())){
- alSourcei(track.src, AL_SOURCE_SPATIALIZE_SOFT, AL_FALSE); ALERR();
- qalBufferCallbackSOFT = alGetProcAddress("alBufferCallbackSOFT");
- alGenBuffers(1, &track.buf); ALERR();
- }
-
- return 0;
-}
-
-static void
-alreinit(const char *def, const char *all)
-{
- const char *s;
- int i, n;
-
- n = s_al_dev.value;
- if(n == s_al_dev_prev)
- return;
- if(qalcReopenDeviceSOFT == nil && alcIsExtensionPresent(nil, "ALC_SOFT_reopen_device"))
- qalcReopenDeviceSOFT = alGetProcAddress("alcReopenDeviceSOFT");
- if(qalcReopenDeviceSOFT == nil){
- Con_Printf("AL: can't change device settings on the fly\n");
- return;
- }
- for(i = 1, s = all; s != nil && *s; i++){
- if((n == 0 && def != nil && strcmp(s, def) == 0) || n == i){
- if(dev == nil)
- n = alinit(all);
- else{
- n = qalcReopenDeviceSOFT(dev, s, alcattr(false)) ? 0 : -1;
- ALERR();
- }
- if(n != 0)
- Con_Printf("AL: failed to switch to %s\n", s);
- else
- s_al_dev_prev = n;
- return;
- }
- s += strlen(s)+1;
- }
- Con_Printf("AL: no such device: %d\n", n);
-}
-
-static void
-alvarcb(cvar_t *var)
-{
- const char *all, *def, *s;
- bool hrtf;
- int i, n;
-
- def = alcGetString(nil, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
- if(ALERR())
- def = nil;
- all = alcGetString(nil, ALC_ALL_DEVICES_SPECIFIER);
- if(ALERR())
- all = nil;
-
- if(var == &s_al_dev && Cmd_Argc() == 1){
- Con_Printf("%-2d: default (%s)\n", 0, def ? def : "<invalid>");
- for(i = 1, s = all; s != nil && *s; i++){
- Con_Printf("%-2d: %s%s\n", i, s, strcmp(s, def) == 0 ? " (default)" : "");
- s += strlen(s)+1;
- }
- return;
- }
-
- alreinit(def, all);
-
- if(alcIsExtensionPresent(dev, "ALC_SOFT_HRTF")){
- qalcGetStringiSOFT = alcGetProcAddress(dev, "alcGetStringiSOFT");
- qalcResetDeviceSOFT = alcGetProcAddress(dev, "alcResetDeviceSOFT");
- hrtf = true;
- }else{
- qalcGetStringiSOFT = nil;
- qalcResetDeviceSOFT = nil;
- hrtf = false;
- }
- if(var == &s_al_hrtf && Cmd_Argc() == 1){
- Con_Printf("%-2d: disabled\n", -1);
- Con_Printf("%-2d: don't care (default)\n", 0);
- if(qalcGetStringiSOFT == nil)
- return;
- alcGetIntegerv(dev, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &n); ALERR();
- for(i = 0; i < n; i++){
- s = qalcGetStringiSOFT(dev, ALC_HRTF_SPECIFIER_SOFT, i);
- if(!ALERR() && s != nil)
- Con_Printf("%-2d: %s\n", i+1, s);
- }
- return;
- }
-
- if(qalcResetDeviceSOFT != nil){
- qalcResetDeviceSOFT(dev, alcattr(hrtf));
- ALERR();
- }
-}
-
-static void
-aldopplercb(cvar_t *var)
-{
- alDopplerFactor(var->value); ALERR();
-}
-
-static void
-sfxlist(void)
-{
- int sz, sum, w, ch;
- Sfx *sfx, *e;
- albuf_t *b;
-
- sum = 0;
- for(sfx = known_sfx, e = known_sfx+num_sfx; sfx < e; sfx++){
- if((b = Cache_Check(&sfx->cu)) == nil)
- continue;
- alGetBufferi(b->buf, AL_SIZE, &sz); ALERR();
- alGetBufferi(b->buf, AL_CHANNELS, &ch); ALERR();
- alGetBufferi(b->buf, AL_BITS, &w); ALERR();
- sum += sz * ch * w/8;
- Con_Printf("%c(%2db) %6d : %s\n", b->loop ? 'L' : ' ', w, sz, sfx->s);
- }
- Con_Printf("Total resident: %d\n", sum);
-}
-
-void
-sfxbegin(void)
-{
- map++;
-}
-
-void
-sfxend(void)
-{
- albuf_t *b;
- Sfx *sfx;
- int i;
-
- ambsfx[Ambwater] = precachesfx("ambience/water1.wav");
- ambsfx[Ambsky] = precachesfx("ambience/wind2.wav");
- for(i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++){
- if(sfx->map >= map || sfx == ambsfx[Ambsky] || sfx == ambsfx[Ambwater])
- continue;
- if((b = Cache_Check(&sfx->cu)) != nil){
- alDeleteBuffers(1, &b->buf); ALERR();
- Cache_Free(&sfx->cu);
- }
- }
-}
-
-void
-stepcd(void)
-{
- alSourcef(track.src, AL_GAIN, bgmvolume.value); ALERR();
-}
-
-static ALsizei
-trackcb(ALvoid *aux, ALvoid *sampledata, ALsizei numbytes)
-{
- ssize_t n;
- byte *b;
-
- USED(aux);
- for(b = sampledata; numbytes > 0; b += n, numbytes -= n){
- if((n = read(track.pcm, b, numbytes)) <= 0){
- close(track.pcm);
- track.pcm = -1;
- break;
- }
- }
-
- return b - (byte*)sampledata;
-}
-
-void
-playcd(int nt, bool loop)
-{
- pid_t pid;
- FILE *f;
- fpos_t off;
- int len, left, s[2], in[2];
-
- stopcd();
- if(qalBufferCallbackSOFT == nil)
- return;
-
- if((f = openlmp(va("music/track%02d.ogg", nt), &len)) == nil){
- if((f = openlmp(va("music/track%02d.mp3", nt), &len)) == nil)
- f = openlmp(va("music/track%02d.wav", nt), &len);
- }
- if(f == nil)
- return;
- if(fgetpos(f, &off) != 0){
-err:
- close(track.pcm);
- fclose(f);
- if(track.decoder > 0)
- waitpid(track.decoder, nil, 0);
- if(track.reader > 0)
- waitpid(track.reader, nil, 0);
- return;
- }
-
- if(pipe(s) != 0)
- goto err;
- if(pipe(in) != 0){
- close(s[0]);
- close(s[1]);
- goto err;
- }
-
- switch((pid = fork())){
- case 0:
- close(s[1]); dup2(s[0], 0);
- close(in[0]); dup2(in[1], 1);
- close(s[0]);
- execl(
- "/usr/bin/env", "/usr/bin/env",
- "ffmpeg",
- "-loglevel", "fatal",
- "-i", "-",
- "-acodec", "pcm_s16le",
- "-f", "s16le",
- "-ac", "2",
- "-ar", "44100",
- "-",
- nil
- );
- perror("execl ffmpeg"); // FIXME(sigrid): add and use Con_Errorf?
- exit(1);
- case -1:
- goto err;
- }
- track.decoder = pid;
-
- close(s[0]);
- close(in[1]);
- track.pcm = in[0];
- cdloop = loop;
- cdtrk = nt;
-
- switch((pid = fork())){
- case 0:
- close(in[0]);
- close(0);
- close(1);
- left = len;
- for(;;){
- byte tmp[32768];
- ssize_t n;
- if((n = fread(tmp, 1, min(left, (int)sizeof(tmp)), f)) < 1){
- if(ferror(f)){
- perror("fread");
- break;
- }
- }
- if(write(s[1], tmp, n) != n)
- break;
- left -= n;
- if(left < 1){
- if(!loop)
- break;
- if(fsetpos(f, &off) != 0){
- perror("fsetpos");
- break;
- }
- left = len;
- }
- }
- close(s[1]);
- fclose(f);
- exit(1);
- case -1:
- goto err;
- }
- track.reader = pid;
-
- qalBufferCallbackSOFT(track.buf, AL_FORMAT_STEREO16, 44100, trackcb, nil);
- if(ALERR())
- goto err;
- alSourcei(track.src, AL_BUFFER, track.buf); ALERR();
- alSourcePlay(track.src); ALERR();
- track.playing = true;
-}
-
-void
-resumecd(void)
-{
- alSourcePlay(track.src); ALERR();
-}
-
-void
-pausecd(void)
-{
- alSourcePause(track.src); ALERR();
-}
-
-int
-initcd(void)
-{
- cdntrk = cdtrk = 0;
- cdloop = false;
- return 0;
-}
-
-void
-stopcd(void)
-{
- if(track.playing){
- alSourceStop(track.src); ALERR();
- alSourcei(track.src, AL_BUFFER, 0); ALERR();
- if(track.pcm >= 0)
- close(track.pcm);
- waitpid(track.decoder, nil, 0);
- waitpid(track.reader, nil, 0);
- }
- track.playing = false;
- track.pcm = -1;
- track.decoder = track.reader = -1;
-}
-
-void
-shutcd(void)
-{
- stopcd();
-}
-
-int
-initsnd(void)
-{
- s_al_dev.cb = s_al_hrtf.cb = alvarcb;
- s_al_doppler_factor.cb = aldopplercb;
-
- Cvar_RegisterVariable(&volume);
- Cvar_RegisterVariable(&bgmvolume);
- Cvar_RegisterVariable(&ambient_level);
- Cvar_RegisterVariable(&ambient_fade);
- Cvar_RegisterVariable(&s_al_dev);
- Cvar_RegisterVariable(&s_al_resampler_default);
- Cvar_RegisterVariable(&s_al_resampler_up);
- Cvar_RegisterVariable(&s_al_hrtf);
- Cvar_RegisterVariable(&s_al_doppler_factor);
- Cmd_AddCommand("stopsound", stopallsfx);
- Cmd_AddCommand("soundlist", sfxlist);
- Cmd_AddCommand("cd", cdcmd);
-
- alinit(nil);
- known_sfx = Hunk_Alloc(MAX_SOUNDS * sizeof *known_sfx);
- num_sfx = 0;
-
- return 0;
-}
-
-void
-sndclose(void)
-{
- if(dev == nil)
- return;
- alcDestroyContext(ctx); ctx = nil; ALERR();
- alcCloseDevice(dev); dev = nil; ALERR();
-}
--- a/unix/vid.c
+++ /dev/null
@@ -1,133 +1,0 @@
-#include "quakedef.h"
-#include <SDL.h>
-
-int resized;
-
-pixel_t q1pal[256];
-
-static SDL_Renderer *rend;
-static SDL_Texture *fbi;
-static SDL_Window *win;
-static pixel_t *vidbuffer;
-extern pixel_t *r_warpbuffer;
-
-static void
-resetfb(void)
-{
- void *surfcache;
- int hunkvbuf, scachesz;
-
- /* lower than 320x240 doesn't really make sense,
- * but at least this prevents a crash, beyond that
- * it's your funeral */
- SDL_GetWindowSize(win, &vid.width, &vid.height);
- if(vid.width < 320)
- vid.width = 320;
- if(vid.height < 160)
- vid.height = 160;
-
- vid.rowbytes = vid.width;
- vid.aspect = (float)vid.height / (float)vid.width * (320.0/240.0);
- vid.conrowbytes = vid.rowbytes;
- vid.conwidth = vid.width;
- vid.conheight = vid.height;
-
- free(vidbuffer);
- vidbuffer = emalloc((vid.width*vid.height+16)*sizeof(pixel_t));
- free(r_warpbuffer);
- r_warpbuffer = emalloc((vid.width*vid.height+16)*sizeof(pixel_t));
- vid.maxwarpwidth = vid.width;
- vid.maxwarpheight = vid.height;
-
- if(fbi != nil)
- SDL_DestroyTexture(fbi);
- fbi = SDL_CreateTexture(rend, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, vid.width, vid.height);
- if(fbi == NULL)
- fatal("SDL_CreateTexture: %s", SDL_GetError());
- SDL_SetTextureBlendMode(fbi, SDL_BLENDMODE_NONE);
- SDL_RenderClear(rend);
-
- vid.buffer = vidbuffer;
- vid.conbuffer = vid.buffer;
-
- if(d_pzbuffer != nil){
- D_FlushCaches();
- free(d_pzbuffer);
- d_pzbuffer = nil;
- }
-
- // alloc an extra line in case we want to wrap, and allocate the z-buffer
- hunkvbuf = vid.width * vid.height * sizeof *d_pzbuffer;
- scachesz = D_SurfaceCacheForRes(vid.width, vid.height);
- hunkvbuf += scachesz;
- d_pzbuffer = emalloc(hunkvbuf);
- surfcache = (byte *)(d_pzbuffer + vid.width * vid.height);
- D_InitCaches(surfcache, scachesz);
-}
-
-void
-stopfb(void)
-{
-}
-
-void
-flipfb(void)
-{
- int pitch;
- void *p;
-
- if(resized){ /* skip this frame if window resize */
- stopfb();
- resized = 0;
- resetfb();
- vid.recalc_refdef = true; /* force a surface cache flush */
- Con_CheckResize();
- Con_Clear_f();
- return;
- }
-
- SDL_LockTexture(fbi, NULL, &p, &pitch);
- memmove(p, vidbuffer, vid.width*vid.height*4);
- SDL_UnlockTexture(fbi);
- SDL_RenderCopy(rend, fbi, NULL, NULL);
- SDL_RenderPresent(rend);
-}
-
-void
-setpal(uchar *p0)
-{
- int x;
- uchar *p;
-
- for(p = p0, x = 0; x < 256; x++, p += 3)
- q1pal[x] = (x < 256-32 ? 0xff : 0)<<24 | p[0]<<16 | p[1]<<8 | p[2];
- q1pal[255] &= 0;
-
- scr_fullupdate = 0;
-}
-
-void
-initfb(void)
-{
- vid.numpages = 2;
- vid.colormap = malloc(256*64*sizeof(pixel_t));
- torgbx(host_colormap, vid.colormap, 256*64);
- vid.fullbright = 256 - LittleLong(*((int *)vid.colormap + 2048));
-
- if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
- fatal("SDL_Init: %s", SDL_GetError());
- win = SDL_CreateWindow("quake", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, 0);
- if(win == nil)
- fatal("SDL_CreateWindow: %s", SDL_GetError());
- if((rend = SDL_CreateRenderer(win, -1, 0)) == NULL)
- fatal("SDL_CreateRenderer: %s", SDL_GetError());
- SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
- SDL_RenderClear(rend);
- SDL_RenderPresent(rend);
- SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
-
- resetfb();
- SDL_SetWindowResizable(win, SDL_TRUE);
- SDL_SetWindowMinimumSize(win, 320, 240);
- IN_Grabm(1);
-}
--- a/vid.c
+++ /dev/null
@@ -1,153 +1,0 @@
-#include "quakedef.h"
-#include <draw.h>
-#include <thread.h>
-
-viddef_t vid; /* global video state */
-int resized;
-Point center; /* of window */
-Rectangle grabr;
-
-pixel_t q1pal[256];
-static Image *fbi;
-static Rectangle fbr;
-static pixel_t *vidbuffers[2];
-static int bufi = 0;
-static Channel *frame;
-
-void pal2xrgb(int n, s32int *pal, u8int *s, u32int *d);
-
-static void
-resetfb(void)
-{
- static int highhunk;
- void *surfcache;
- int hunkvbuf, scachesz, i;
- Point p;
-
- /* lower than 320x240 doesn't really make sense,
- * but at least this prevents a crash, beyond that
- * it's your funeral */
- vid.width = Dx(screen->r);
- if(vid.width < 320)
- vid.width = 320;
- vid.height = Dy(screen->r);
- if(vid.height < 160)
- vid.height = 160;
- if(d_pzbuffer != nil)
- D_FlushCaches();
-
- // alloc an extra line in case we want to wrap, and allocate the z-buffer
- hunkvbuf = vid.width * vid.height * sizeof *d_pzbuffer;
- scachesz = D_SurfaceCacheForRes(vid.width, vid.height);
- hunkvbuf += scachesz;
- if((d_pzbuffer = realloc(d_pzbuffer, hunkvbuf)) == nil)
- sysfatal("%r");
- surfcache = (byte*)(d_pzbuffer + vid.width * vid.height);
- D_InitCaches(surfcache, scachesz);
-
- vid.rowbytes = vid.width;
- vid.aspect = (float)vid.height / (float)vid.width * (320.0/240.0);
- vid.conrowbytes = vid.rowbytes;
- vid.conwidth = vid.width;
- vid.conheight = vid.height;
-
- center = divpt(addpt(screen->r.min, screen->r.max), 2);
- p = Pt(vid.width/2, vid.height/2);
- fbr = Rpt(subpt(center, p), addpt(center, p));
- p = Pt(vid.width/4, vid.height/4);
- grabr = Rpt(subpt(center, p), addpt(center, p));
- for(i = 0; i < nelem(vidbuffers); i++)
- vidbuffers[i] = realloc(vidbuffers[i], (vid.width*vid.height+16)*sizeof(pixel_t));
- free(r_warpbuffer);
- r_warpbuffer = emalloc((vid.width*vid.height+16)*sizeof(pixel_t));
- vid.maxwarpwidth = vid.width;
- vid.maxwarpheight = vid.height;
- freeimage(fbi);
- fbi = allocimage(display, Rect(0, 0, vid.width, vid.height), XRGB32, 0, 0);
- if(fbi == nil)
- sysfatal("resetfb: %r (%d %d)", vid.width, vid.height);
- vid.buffer = vidbuffers[bufi = 0];
- vid.conbuffer = vid.buffer;
- draw(screen, screen->r, display->black, nil, ZP);
-}
-
-static void
-loader(void *)
-{
- byte *f;
- Rectangle r;
- int n;
-
- r = Rect(0, 0, vid.width, vid.height);
- n = vid.width * vid.height;
- for(;;){
- if((f = recvp(frame)) == nil)
- break;
- if(loadimage(fbi, r, f, n*4) != n*4)
- sysfatal("%r");
- draw(screen, fbr, fbi, nil, ZP);
- if(flushimage(display, 1) < 0)
- sysfatal("%r");
- }
- threadexits(nil);
-}
-
-void
-stopfb(void)
-{
- if(frame != nil){
- sendp(frame, nil);
- chanclose(frame);
- frame = nil;
- }
-}
-
-void
-flipfb(void)
-{
- if(resized){ /* skip this frame if window resize */
- stopfb();
- if(getwindow(display, Refnone) < 0)
- sysfatal("%r");
- resized = 0;
- resetfb();
- vid.recalc_refdef = true; /* force a surface cache flush */
- Con_CheckResize();
- Con_Clear_f();
- return;
- }
- if(frame == nil){
- frame = chancreate(sizeof(pixel_t*), 0);
- proccreate(loader, nil, 4096);
- }
- if(sendp(frame, vidbuffers[bufi]) > 0){
- bufi = (bufi+1) % nelem(vidbuffers);
- vid.buffer = vidbuffers[bufi];
- vid.conbuffer = vid.buffer;
- }
-}
-
-void
-setpal(uchar *p0)
-{
- int x;
- uchar *p;
-
- for(p = p0, x = 0; x < 256; x++, p += 3)
- q1pal[x] = (x < 256-32 ? 0xff : 0)<<24 | p[0]<<16 | p[1]<<8 | p[2];
- q1pal[255] &= 0;
-
- scr_fullupdate = 0;
-}
-
-void
-initfb(void)
-{
- vid.numpages = 2;
- vid.colormap = malloc(256*64*sizeof(pixel_t));
- torgbx(host_colormap, vid.colormap, 256*64);
- vid.fullbright = 256 - LittleLong(*((int *)vid.colormap + 2048));
- if(initdraw(nil, nil, "quake") < 0)
- sysfatal("initdraw: %r\n");
- resetfb();
-}
--- /dev/null
+++ b/vid_plan9.c
@@ -1,0 +1,153 @@
+#include "quakedef.h"
+#include <draw.h>
+#include <thread.h>
+
+viddef_t vid; /* global video state */
+int resized;
+Point center; /* of window */
+Rectangle grabr;
+
+pixel_t q1pal[256];
+static Image *fbi;
+static Rectangle fbr;
+static pixel_t *vidbuffers[2];
+static int bufi = 0;
+static Channel *frame;
+
+void pal2xrgb(int n, s32int *pal, u8int *s, u32int *d);
+
+static void
+resetfb(void)
+{
+ static int highhunk;
+ void *surfcache;
+ int hunkvbuf, scachesz, i;
+ Point p;
+
+ /* lower than 320x240 doesn't really make sense,
+ * but at least this prevents a crash, beyond that
+ * it's your funeral */
+ vid.width = Dx(screen->r);
+ if(vid.width < 320)
+ vid.width = 320;
+ vid.height = Dy(screen->r);
+ if(vid.height < 160)
+ vid.height = 160;
+ if(d_pzbuffer != nil)
+ D_FlushCaches();
+
+ // alloc an extra line in case we want to wrap, and allocate the z-buffer
+ hunkvbuf = vid.width * vid.height * sizeof *d_pzbuffer;
+ scachesz = D_SurfaceCacheForRes(vid.width, vid.height);
+ hunkvbuf += scachesz;
+ if((d_pzbuffer = realloc(d_pzbuffer, hunkvbuf)) == nil)
+ sysfatal("%r");
+ surfcache = (byte*)(d_pzbuffer + vid.width * vid.height);
+ D_InitCaches(surfcache, scachesz);
+
+ vid.rowbytes = vid.width;
+ vid.aspect = (float)vid.height / (float)vid.width * (320.0/240.0);
+ vid.conrowbytes = vid.rowbytes;
+ vid.conwidth = vid.width;
+ vid.conheight = vid.height;
+
+ center = divpt(addpt(screen->r.min, screen->r.max), 2);
+ p = Pt(vid.width/2, vid.height/2);
+ fbr = Rpt(subpt(center, p), addpt(center, p));
+ p = Pt(vid.width/4, vid.height/4);
+ grabr = Rpt(subpt(center, p), addpt(center, p));
+ for(i = 0; i < nelem(vidbuffers); i++)
+ vidbuffers[i] = realloc(vidbuffers[i], (vid.width*vid.height+16)*sizeof(pixel_t));
+ free(r_warpbuffer);
+ r_warpbuffer = emalloc((vid.width*vid.height+16)*sizeof(pixel_t));
+ vid.maxwarpwidth = vid.width;
+ vid.maxwarpheight = vid.height;
+ freeimage(fbi);
+ fbi = allocimage(display, Rect(0, 0, vid.width, vid.height), XRGB32, 0, 0);
+ if(fbi == nil)
+ sysfatal("resetfb: %r (%d %d)", vid.width, vid.height);
+ vid.buffer = vidbuffers[bufi = 0];
+ vid.conbuffer = vid.buffer;
+ draw(screen, screen->r, display->black, nil, ZP);
+}
+
+static void
+loader(void *)
+{
+ byte *f;
+ Rectangle r;
+ int n;
+
+ r = Rect(0, 0, vid.width, vid.height);
+ n = vid.width * vid.height;
+ for(;;){
+ if((f = recvp(frame)) == nil)
+ break;
+ if(loadimage(fbi, r, f, n*4) != n*4)
+ sysfatal("%r");
+ draw(screen, fbr, fbi, nil, ZP);
+ if(flushimage(display, 1) < 0)
+ sysfatal("%r");
+ }
+ threadexits(nil);
+}
+
+void
+stopfb(void)
+{
+ if(frame != nil){
+ sendp(frame, nil);
+ chanclose(frame);
+ frame = nil;
+ }
+}
+
+void
+flipfb(void)
+{
+ if(resized){ /* skip this frame if window resize */
+ stopfb();
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("%r");
+ resized = 0;
+ resetfb();
+ vid.recalc_refdef = true; /* force a surface cache flush */
+ Con_CheckResize();
+ Con_Clear_f();
+ return;
+ }
+ if(frame == nil){
+ frame = chancreate(sizeof(pixel_t*), 0);
+ proccreate(loader, nil, 4096);
+ }
+ if(sendp(frame, vidbuffers[bufi]) > 0){
+ bufi = (bufi+1) % nelem(vidbuffers);
+ vid.buffer = vidbuffers[bufi];
+ vid.conbuffer = vid.buffer;
+ }
+}
+
+void
+setpal(uchar *p0)
+{
+ int x;
+ uchar *p;
+
+ for(p = p0, x = 0; x < 256; x++, p += 3)
+ q1pal[x] = (x < 256-32 ? 0xff : 0)<<24 | p[0]<<16 | p[1]<<8 | p[2];
+ q1pal[255] &= 0;
+
+ scr_fullupdate = 0;
+}
+
+void
+initfb(void)
+{
+ vid.numpages = 2;
+ vid.colormap = malloc(256*64*sizeof(pixel_t));
+ torgbx(host_colormap, vid.colormap, 256*64);
+ vid.fullbright = 256 - LittleLong(*((int *)vid.colormap + 2048));
+ if(initdraw(nil, nil, "quake") < 0)
+ sysfatal("initdraw: %r\n");
+ resetfb();
+}
--- /dev/null
+++ b/vid_sdl.c
@@ -1,0 +1,133 @@
+#include "quakedef.h"
+#include <SDL.h>
+
+int resized;
+
+pixel_t q1pal[256];
+
+static SDL_Renderer *rend;
+static SDL_Texture *fbi;
+static SDL_Window *win;
+static pixel_t *vidbuffer;
+extern pixel_t *r_warpbuffer;
+
+static void
+resetfb(void)
+{
+ void *surfcache;
+ int hunkvbuf, scachesz;
+
+ /* lower than 320x240 doesn't really make sense,
+ * but at least this prevents a crash, beyond that
+ * it's your funeral */
+ SDL_GetWindowSize(win, &vid.width, &vid.height);
+ if(vid.width < 320)
+ vid.width = 320;
+ if(vid.height < 160)
+ vid.height = 160;
+
+ vid.rowbytes = vid.width;
+ vid.aspect = (float)vid.height / (float)vid.width * (320.0/240.0);
+ vid.conrowbytes = vid.rowbytes;
+ vid.conwidth = vid.width;
+ vid.conheight = vid.height;
+
+ free(vidbuffer);
+ vidbuffer = emalloc((vid.width*vid.height+16)*sizeof(pixel_t));
+ free(r_warpbuffer);
+ r_warpbuffer = emalloc((vid.width*vid.height+16)*sizeof(pixel_t));
+ vid.maxwarpwidth = vid.width;
+ vid.maxwarpheight = vid.height;
+
+ if(fbi != nil)
+ SDL_DestroyTexture(fbi);
+ fbi = SDL_CreateTexture(rend, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, vid.width, vid.height);
+ if(fbi == NULL)
+ fatal("SDL_CreateTexture: %s", SDL_GetError());
+ SDL_SetTextureBlendMode(fbi, SDL_BLENDMODE_NONE);
+ SDL_RenderClear(rend);
+
+ vid.buffer = vidbuffer;
+ vid.conbuffer = vid.buffer;
+
+ if(d_pzbuffer != nil){
+ D_FlushCaches();
+ free(d_pzbuffer);
+ d_pzbuffer = nil;
+ }
+
+ // alloc an extra line in case we want to wrap, and allocate the z-buffer
+ hunkvbuf = vid.width * vid.height * sizeof *d_pzbuffer;
+ scachesz = D_SurfaceCacheForRes(vid.width, vid.height);
+ hunkvbuf += scachesz;
+ d_pzbuffer = emalloc(hunkvbuf);
+ surfcache = (byte *)(d_pzbuffer + vid.width * vid.height);
+ D_InitCaches(surfcache, scachesz);
+}
+
+void
+stopfb(void)
+{
+}
+
+void
+flipfb(void)
+{
+ int pitch;
+ void *p;
+
+ if(resized){ /* skip this frame if window resize */
+ stopfb();
+ resized = 0;
+ resetfb();
+ vid.recalc_refdef = true; /* force a surface cache flush */
+ Con_CheckResize();
+ Con_Clear_f();
+ return;
+ }
+
+ SDL_LockTexture(fbi, NULL, &p, &pitch);
+ memmove(p, vidbuffer, vid.width*vid.height*4);
+ SDL_UnlockTexture(fbi);
+ SDL_RenderCopy(rend, fbi, NULL, NULL);
+ SDL_RenderPresent(rend);
+}
+
+void
+setpal(uchar *p0)
+{
+ int x;
+ uchar *p;
+
+ for(p = p0, x = 0; x < 256; x++, p += 3)
+ q1pal[x] = (x < 256-32 ? 0xff : 0)<<24 | p[0]<<16 | p[1]<<8 | p[2];
+ q1pal[255] &= 0;
+
+ scr_fullupdate = 0;
+}
+
+void
+initfb(void)
+{
+ vid.numpages = 2;
+ vid.colormap = malloc(256*64*sizeof(pixel_t));
+ torgbx(host_colormap, vid.colormap, 256*64);
+ vid.fullbright = 256 - LittleLong(*((int *)vid.colormap + 2048));
+
+ if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
+ fatal("SDL_Init: %s", SDL_GetError());
+ win = SDL_CreateWindow("quake", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, 0);
+ if(win == nil)
+ fatal("SDL_CreateWindow: %s", SDL_GetError());
+ if((rend = SDL_CreateRenderer(win, -1, 0)) == NULL)
+ fatal("SDL_CreateRenderer: %s", SDL_GetError());
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderClear(rend);
+ SDL_RenderPresent(rend);
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
+
+ resetfb();
+ SDL_SetWindowResizable(win, SDL_TRUE);
+ SDL_SetWindowMinimumSize(win, 320, 240);
+ IN_Grabm(1);
+}