From a8c175d19749212ed8c2295fca49398a3dda6f85 Mon Sep 17 00:00:00 2001 From: driAn Date: Sun, 8 Jan 2006 15:02:49 +0000 Subject: [PATCH] no message git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@106 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/client.cpp | 909 ++++++++++++++------- source/src/renderextras.cpp | 1497 +++++++++++++++++++++++------------ source/src/rendergl.cpp | 1224 ++++++++++++++++++---------- source/src/sound.cpp | 699 ++++++++++------ 4 files changed, 2886 insertions(+), 1443 deletions(-) diff --git a/source/src/client.cpp b/source/src/client.cpp index e91eab97..f3860c1f 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -1,303 +1,606 @@ -// client.cpp, mostly network related client game code - -#include "cube.h" - -ENetHost *clienthost = NULL; -int connecting = 0; -int connattempts = 0; -int disconnecting = 0; -int clientnum = -1; // our client id in the game -bool c2sinit = false; // whether we need to tell the other clients our stats - -int getclientnum() { return clientnum; }; - -bool multiplayer() -{ - // check not correct on listen server? - if(clienthost) conoutf("operation not available in multiplayer"); - return clienthost!=NULL; -}; - -bool allowedittoggle() -{ - bool allow = !clienthost || gamemode==1; - if(!allow) conoutf("editing in multiplayer requires coopedit mode (1)"); - return allow; -}; - -VARF(rate, 0, 0, 25000, if(clienthost && (!rate || rate>1000)) enet_host_bandwidth_limit (clienthost, rate, rate)); - -void throttle(); - -VARF(throttle_interval, 0, 5, 30, throttle()); -VARF(throttle_accel, 0, 2, 32, throttle()); -VARF(throttle_decel, 0, 2, 32, throttle()); - -void throttle() -{ - if(!clienthost || connecting) return; - assert(ENET_PEER_PACKET_THROTTLE_SCALE==32); - enet_peer_throttle_configure(clienthost->peers, throttle_interval*1000, throttle_accel, throttle_decel); -}; - -void newname(char *name) { c2sinit = false; strn0cpy(player1->name, name, 16); }; -void newteam(char *name) { c2sinit = false; strn0cpy(player1->team, name, 5); }; - -COMMANDN(team, newteam, ARG_1STR); -COMMANDN(name, newname, ARG_1STR); - -void connects(char *servername) -{ - disconnect(1); // reset state - addserver(servername); - - conoutf("attempting to connect to %s", servername); - ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT }; - if(enet_address_set_host(&address, servername) < 0) - { - conoutf("could not resolve server %s", servername); - return; - }; - - clienthost = enet_host_create(NULL, 1, rate, rate); - - if(clienthost) - { - enet_host_connect(clienthost, &address, 1); - enet_host_flush(clienthost); - connecting = lastmillis; - connattempts = 0; - } - else - { - conoutf("could not connect to server"); - disconnect(); - }; -}; - -void disconnect(int onlyclean, int async) -{ - if(clienthost) - { - if(!connecting && !disconnecting) - { - enet_peer_disconnect(clienthost->peers); - enet_host_flush(clienthost); - disconnecting = lastmillis; - }; - if(clienthost->peers->state != ENET_PEER_STATE_DISCONNECTED) - { - if(async) return; - enet_peer_reset(clienthost->peers); - }; - enet_host_destroy(clienthost); - }; - - if(clienthost && !connecting) conoutf("disconnected"); - clienthost = NULL; - connecting = 0; - connattempts = 0; - disconnecting = 0; - clientnum = -1; - c2sinit = false; - player1->lifesequence = 0; - loopv(players) zapdynent(players[i]); - - localdisconnect(); - - if(!onlyclean) { stop(); localconnect(); }; -}; - -void trydisconnect() -{ - if(!clienthost) - { - conoutf("not connected"); - return; - }; - if(connecting) - { - conoutf("aborting connection attempt"); - disconnect(); - return; - }; - conoutf("attempting to disconnect..."); - disconnect(0, !disconnecting); -}; - -string ctext; -void toserver(char *text) { conoutf("%s:\f %s", (int)player1->name, (int)text); strn0cpy(ctext, text, 80); }; -void echo(char *text) { conoutf("%s", (int)text); }; - -COMMAND(echo, ARG_VARI); -COMMANDN(say, toserver, ARG_VARI); -COMMANDN(connect, connects, ARG_1STR); -COMMANDN(disconnect, trydisconnect, ARG_NONE); - -// collect c2s messages conveniently - -vector messages; - -void addmsg(int rel, int num, int type, ...) -{ - if(demoplayback) return; - if(num!=msgsizelookup(type)) { sprintf_sd(s)("inconsistant msg size for %d (%d != %d)", type, num, msgsizelookup(type)); fatal(s); }; - ivector &msg = messages.add(); - msg.add(num); - msg.add(rel); - msg.add(type); - va_list marker; - va_start(marker, type); - loopi(num-1) msg.add(va_arg(marker, int)); - va_end(marker); -}; - -void server_err() -{ - conoutf("server network error, disconnecting..."); - disconnect(); -}; - -int lastupdate = 0, lastping = 0; -string toservermap; -bool senditemstoserver = false; // after a map change, since server doesn't have map data - -string clientpassword; -void password(char *p) { strcpy_s(clientpassword, p); }; -COMMAND(password, ARG_1STR); - -bool netmapstart() { senditemstoserver = true; return clienthost!=NULL; }; - -void initclientnet() -{ - ctext[0] = 0; - toservermap[0] = 0; - clientpassword[0] = 0; - newname("unnamed"); - newteam("red"); -}; - -void sendpackettoserv(void *packet) -{ - if(clienthost) { enet_host_broadcast(clienthost, 0, (ENetPacket *)packet); enet_host_flush(clienthost); } - else localclienttoserver((ENetPacket *)packet); -} - -void c2sinfo(dynent *d) // send update to the server -{ - if(clientnum<0) return; // we haven't had a welcome message from the server yet - if(lastmillis-lastupdate<40) return; // don't update faster than 25fps - ENetPacket *packet = enet_packet_create (NULL, MAXTRANS, 0); - uchar *start = packet->data; - uchar *p = start+2; - bool serveriteminitdone = false; - if(toservermap[0]) // suggest server to change map - { // do this exclusively as map change may invalidate rest of update - packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_MAPCHANGE); - sendstring(toservermap, p); - toservermap[0] = 0; - putint(p, nextmode); - } - else - { - putint(p, SV_POS); - putint(p, clientnum); - putint(p, (int)(d->o.x*DMF)); // quantize coordinates to 1/16th of a cube, between 1 and 3 bytes - putint(p, (int)(d->o.y*DMF)); - putint(p, (int)(d->o.z*DMF)); - putint(p, (int)(d->yaw*DAF)); - putint(p, (int)(d->pitch*DAF)); - putint(p, (int)(d->roll*DAF)); - putint(p, (int)(d->vel.x*DVF)); // quantize to 1/100, almost always 1 byte - putint(p, (int)(d->vel.y*DVF)); - putint(p, (int)(d->vel.z*DVF)); - // pack rest in 1 byte: strafe:2, move:2, onfloor:1, state:3 - putint(p, (d->strafe&3) | ((d->move&3)<<2) | (((int)d->onfloor)<<4) | ((editmode ? CS_EDITING : d->state)<<5) ); - - if(senditemstoserver) - { - packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_ITEMLIST); - if(!m_noitems) putitems(p); - putint(p, -1); - senditemstoserver = false; - serveriteminitdone = true; - }; - if(ctext[0]) // player chat, not flood protected for now - { - packet->flags = ENET_PACKET_FLAG_RELIABLE; - putint(p, SV_TEXT); - sendstring(ctext, p); - ctext[0] = 0; - }; - if(!c2sinit) // tell other clients who I am - { - packet->flags = ENET_PACKET_FLAG_RELIABLE; - c2sinit = true; - putint(p, SV_INITC2S); - sendstring(player1->name, p); - sendstring(player1->team, p); - putint(p, player1->lifesequence); - }; - loopv(messages) // send messages collected during the previous frames - { - ivector &msg = messages[i]; - if(msg[1]) packet->flags = ENET_PACKET_FLAG_RELIABLE; - loopi(msg[0]) putint(p, msg[i+2]); - }; - messages.setsize(0); - if(lastmillis-lastping>250) - { - putint(p, SV_PING); - putint(p, lastmillis); - lastping = lastmillis; - }; - }; - *(ushort *)start = ENET_HOST_TO_NET_16(p-start); - enet_packet_resize(packet, p-start); - incomingdemodata(start, p-start, true); - if(clienthost) { enet_host_broadcast(clienthost, 0, packet); enet_host_flush(clienthost); } - else localclienttoserver(packet); - lastupdate = lastmillis; - if(serveriteminitdone) loadgamerest(); // hack -}; - -void gets2c() // get updates from the server -{ - ENetEvent event; - if(!clienthost) return; - if(connecting && lastmillis/3000 > connecting/3000) - { - conoutf("attempting to connect..."); - connecting = lastmillis; - ++connattempts; - if(connattempts > 3) - { - conoutf("could not connect to server"); - disconnect(); - return; - }; - }; - while(clienthost!=NULL && enet_host_service(clienthost, &event, 0)>0) - switch(event.type) - { - case ENET_EVENT_TYPE_CONNECT: - conoutf("connected to server"); - connecting = 0; - throttle(); - break; - - case ENET_EVENT_TYPE_RECEIVE: - if(disconnecting) conoutf("attempting to disconnect..."); - else localservertoclient(event.packet->data, event.packet->dataLength); - enet_packet_destroy(event.packet); - break; - - case ENET_EVENT_TYPE_DISCONNECT: - if(disconnecting) disconnect(); - else server_err(); - return; - } -}; - +// client.cpp, mostly network related client game code + + + +#include "cube.h" + + + +ENetHost *clienthost = NULL; + +int connecting = 0; + +int connattempts = 0; + +int disconnecting = 0; + +int clientnum = -1; // our client id in the game + +bool c2sinit = false; // whether we need to tell the other clients our stats + + + +int getclientnum() { return clientnum; }; + + + +bool multiplayer() + +{ + + // check not correct on listen server? + + if(clienthost) conoutf("operation not available in multiplayer"); + + return clienthost!=NULL; + +}; + + + +bool allowedittoggle() + +{ + + bool allow = !clienthost || gamemode==1; + + if(!allow) conoutf("editing in multiplayer requires coopedit mode (1)"); + + return allow; + +}; + + + +VARF(rate, 0, 0, 25000, if(clienthost && (!rate || rate>1000)) enet_host_bandwidth_limit (clienthost, rate, rate)); + + + +void throttle(); + + + +VARF(throttle_interval, 0, 5, 30, throttle()); + +VARF(throttle_accel, 0, 2, 32, throttle()); + +VARF(throttle_decel, 0, 2, 32, throttle()); + + + +void throttle() + +{ + + if(!clienthost || connecting) return; + + assert(ENET_PEER_PACKET_THROTTLE_SCALE==32); + + enet_peer_throttle_configure(clienthost->peers, throttle_interval*1000, throttle_accel, throttle_decel); + +}; + + + +void newname(char *name) { c2sinit = false; strn0cpy(player1->name, name, 16); }; + +void newteam(char *name) { c2sinit = false; strn0cpy(player1->team, name, 5); }; + + + +COMMANDN(team, newteam, ARG_1STR); + +COMMANDN(name, newname, ARG_1STR); + + + +void connects(char *servername) + +{ + + disconnect(1); // reset state + + addserver(servername); + + + + conoutf("attempting to connect to %s", (int) servername); + + ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT }; + + if(enet_address_set_host(&address, servername) < 0) + + { + + conoutf("could not resolve server %s", (int) servername); + + return; + + }; + + + + clienthost = enet_host_create(NULL, 1, rate, rate); + + + + if(clienthost) + + { + + enet_host_connect(clienthost, &address, 1); + + enet_host_flush(clienthost); + + connecting = lastmillis; + + connattempts = 0; + + } + + else + + { + + conoutf("could not connect to server"); + + disconnect(); + + }; + +}; + + + +void disconnect(int onlyclean, int async) + +{ + + if(clienthost) + + { + + if(!connecting && !disconnecting) + + { + + enet_peer_disconnect(clienthost->peers); + + enet_host_flush(clienthost); + + disconnecting = lastmillis; + + }; + + if(clienthost->peers->state != ENET_PEER_STATE_DISCONNECTED) + + { + + if(async) return; + + enet_peer_reset(clienthost->peers); + + }; + + enet_host_destroy(clienthost); + + }; + + + + if(clienthost && !connecting) conoutf("disconnected"); + + clienthost = NULL; + + connecting = 0; + + connattempts = 0; + + disconnecting = 0; + + clientnum = -1; + + c2sinit = false; + + player1->lifesequence = 0; + + loopv(players) zapdynent(players[i]); + + + + localdisconnect(); + + + + if(!onlyclean) { stop(); localconnect(); }; + +}; + + + +void trydisconnect() + +{ + + if(!clienthost) + + { + + conoutf("not connected"); + + return; + + }; + + if(connecting) + + { + + conoutf("aborting connection attempt"); + + disconnect(); + + return; + + }; + + conoutf("attempting to disconnect..."); + + disconnect(0, !disconnecting); + +}; + + + +string ctext; + +void toserver(char *text) { conoutf("%s:\f %s", (int)player1->name, (int)text); strn0cpy(ctext, text, 80); }; + +void echo(char *text) { conoutf("%s", (int)text); }; + + + +COMMAND(echo, ARG_VARI); + +COMMANDN(say, toserver, ARG_VARI); + +COMMANDN(connect, connects, ARG_1STR); + +COMMANDN(disconnect, trydisconnect, ARG_NONE); + + + +// collect c2s messages conveniently + + + +vector messages; + + + +void addmsg(int rel, int num, int type, ...) + +{ + + if(demoplayback) return; + + if(num!=msgsizelookup(type)) { sprintf_sd(s)("inconsistant msg size for %d (%d != %d)", type, num, msgsizelookup(type)); fatal(s); }; + + ivector &msg = messages.add(); + + msg.add(num); + + msg.add(rel); + + msg.add(type); + + va_list marker; + + va_start(marker, type); + + loopi(num-1) msg.add(va_arg(marker, int)); + + va_end(marker); + +}; + + + +void server_err() + +{ + + conoutf("server network error, disconnecting..."); + + disconnect(); + +}; + + + +int lastupdate = 0, lastping = 0; + +string toservermap; + +bool senditemstoserver = false; // after a map change, since server doesn't have map data + + + +string clientpassword; + +void password(char *p) { strcpy_s(clientpassword, p); }; + +COMMAND(password, ARG_1STR); + + + +bool netmapstart() { senditemstoserver = true; return clienthost!=NULL; }; + + + +void initclientnet() + +{ + + ctext[0] = 0; + + toservermap[0] = 0; + + clientpassword[0] = 0; + + newname("unnamed"); + + newteam("red"); + +}; + + + +void sendpackettoserv(void *packet) + +{ + + if(clienthost) { enet_host_broadcast(clienthost, 0, (ENetPacket *)packet); enet_host_flush(clienthost); } + + else localclienttoserver((ENetPacket *)packet); + +} + + + +void c2sinfo(dynent *d) // send update to the server + +{ + + if(clientnum<0) return; // we haven't had a welcome message from the server yet + + if(lastmillis-lastupdate<40) return; // don't update faster than 25fps + + ENetPacket *packet = enet_packet_create (NULL, MAXTRANS, 0); + + uchar *start = packet->data; + + uchar *p = start+2; + + bool serveriteminitdone = false; + + if(toservermap[0]) // suggest server to change map + + { // do this exclusively as map change may invalidate rest of update + + packet->flags = ENET_PACKET_FLAG_RELIABLE; + + putint(p, SV_MAPCHANGE); + + sendstring(toservermap, p); + + toservermap[0] = 0; + + putint(p, nextmode); + + } + + else + + { + + putint(p, SV_POS); + + putint(p, clientnum); + + putint(p, (int)(d->o.x*DMF)); // quantize coordinates to 1/16th of a cube, between 1 and 3 bytes + + putint(p, (int)(d->o.y*DMF)); + + putint(p, (int)(d->o.z*DMF)); + + putint(p, (int)(d->yaw*DAF)); + + putint(p, (int)(d->pitch*DAF)); + + putint(p, (int)(d->roll*DAF)); + + putint(p, (int)(d->vel.x*DVF)); // quantize to 1/100, almost always 1 byte + + putint(p, (int)(d->vel.y*DVF)); + + putint(p, (int)(d->vel.z*DVF)); + + // pack rest in 1 byte: strafe:2, move:2, onfloor:1, state:3 + + putint(p, (d->strafe&3) | ((d->move&3)<<2) | (((int)d->onfloor)<<4) | ((editmode ? CS_EDITING : d->state)<<5) ); + + + + if(senditemstoserver) + + { + + packet->flags = ENET_PACKET_FLAG_RELIABLE; + + putint(p, SV_ITEMLIST); + + if(!m_noitems) putitems(p); + + putint(p, -1); + + senditemstoserver = false; + + serveriteminitdone = true; + + }; + + if(ctext[0]) // player chat, not flood protected for now + + { + + packet->flags = ENET_PACKET_FLAG_RELIABLE; + + putint(p, SV_TEXT); + + sendstring(ctext, p); + + ctext[0] = 0; + + }; + + if(!c2sinit) // tell other clients who I am + + { + + packet->flags = ENET_PACKET_FLAG_RELIABLE; + + c2sinit = true; + + putint(p, SV_INITC2S); + + sendstring(player1->name, p); + + sendstring(player1->team, p); + + putint(p, player1->lifesequence); + + }; + + loopv(messages) // send messages collected during the previous frames + + { + + ivector &msg = messages[i]; + + if(msg[1]) packet->flags = ENET_PACKET_FLAG_RELIABLE; + + loopi(msg[0]) putint(p, msg[i+2]); + + }; + + messages.setsize(0); + + if(lastmillis-lastping>250) + + { + + putint(p, SV_PING); + + putint(p, lastmillis); + + lastping = lastmillis; + + }; + + }; + + *(ushort *)start = ENET_HOST_TO_NET_16(p-start); + + enet_packet_resize(packet, p-start); + + incomingdemodata(start, p-start, true); + + if(clienthost) { enet_host_broadcast(clienthost, 0, packet); enet_host_flush(clienthost); } + + else localclienttoserver(packet); + + lastupdate = lastmillis; + + if(serveriteminitdone) loadgamerest(); // hack + +}; + + + +void gets2c() // get updates from the server + +{ + + ENetEvent event; + + if(!clienthost) return; + + if(connecting && lastmillis/3000 > connecting/3000) + + { + + conoutf("attempting to connect..."); + + connecting = lastmillis; + + ++connattempts; + + if(connattempts > 3) + + { + + conoutf("could not connect to server"); + + disconnect(); + + return; + + }; + + }; + + while(clienthost!=NULL && enet_host_service(clienthost, &event, 0)>0) + + switch(event.type) + + { + + case ENET_EVENT_TYPE_CONNECT: + + conoutf("connected to server"); + + connecting = 0; + + throttle(); + + break; + + + + case ENET_EVENT_TYPE_RECEIVE: + + if(disconnecting) conoutf("attempting to disconnect..."); + + else localservertoclient(event.packet->data, event.packet->dataLength); + + enet_packet_destroy(event.packet); + + break; + + + + case ENET_EVENT_TYPE_DISCONNECT: + + if(disconnecting) disconnect(); + + else server_err(); + + return; + + } + +}; + + + diff --git a/source/src/renderextras.cpp b/source/src/renderextras.cpp index 2bd355bf..e589c7bc 100644 --- a/source/src/renderextras.cpp +++ b/source/src/renderextras.cpp @@ -1,499 +1,998 @@ -// renderextras.cpp: misc gl render code and the HUD - -#include "cube.h" - -void line(int x1, int y1, float z1, int x2, int y2, float z2) -{ - glBegin(GL_POLYGON); - glVertex3f((float)x1, z1, (float)y1); - glVertex3f((float)x1, z1, y1+0.01f); - glVertex3f((float)x2, z2, y2+0.01f); - glVertex3f((float)x2, z2, (float)y2); - glEnd(); - xtraverts += 4; -}; - -void linestyle(float width, int r, int g, int b) -{ - glLineWidth(width); - glColor3ub(r,g,b); -}; - -void box(block &b, float z1, float z2, float z3, float z4) -{ - glBegin(GL_POLYGON); - glVertex3f((float)b.x, z1, (float)b.y); - glVertex3f((float)b.x+b.xs, z2, (float)b.y); - glVertex3f((float)b.x+b.xs, z3, (float)b.y+b.ys); - glVertex3f((float)b.x, z4, (float)b.y+b.ys); - glEnd(); - xtraverts += 4; -}; - -void dot(int x, int y, float z) -{ - const float DOF = 0.1f; - glBegin(GL_POLYGON); - glVertex3f(x-DOF, (float)z, y-DOF); - glVertex3f(x+DOF, (float)z, y-DOF); - glVertex3f(x+DOF, (float)z, y+DOF); - glVertex3f(x-DOF, (float)z, y+DOF); - glEnd(); - xtraverts += 4; -}; - -void blendbox(int x1, int y1, int x2, int y2, bool border, int tex=-1) -{ - glDepthMask(GL_FALSE); - glDisable(GL_TEXTURE_2D); - if(tex>=0) - { - glBindTexture(GL_TEXTURE_2D, tex); - glEnable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - } - else - { - if(border) glColor3d(0.7, 0.7, 0.7); //glColor3d(0.5, 0.3, 0.4); - else glColor3d(1.0, 1.0, 1.0); - glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - }; - glBegin(GL_QUADS); - glTexCoord2f(0, 0); glVertex2i(x1, y1); - glTexCoord2f(1, 0); glVertex2i(x2, y1); - glTexCoord2f(1, 1); glVertex2i(x2, y2); - glTexCoord2f(0, 1); glVertex2i(x1, y2); - glEnd(); - glDisable(GL_BLEND); - if(tex>=0) glDisable(GL_TEXTURE_2D); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glBegin(GL_POLYGON); - glColor3d(0.6, 0.6, 0.6); //glColor3d(0.2, 0.7, 0.4); - glVertex2i(x1, y1); - glVertex2i(x2, y1); - glVertex2i(x2, y2); - glVertex2i(x1, y2); - glEnd(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - xtraverts += 8; - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glDepthMask(GL_TRUE); -}; - -const int MAXSPHERES = 50; -struct sphere { vec o; float size, max; int type; sphere *next; }; -sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL; -bool sinit = false; - -void newsphere(vec &o, float max, int type) -{ - if(!sinit) - { - loopi(MAXSPHERES) - { - spheres[i].next = sempty; - sempty = &spheres[i]; - }; - sinit = true; - }; - if(sempty) - { - sphere *p = sempty; - sempty = p->next; - p->o = o; - p->max = max; - p->size = 1; - p->type = type; - p->next = slist; - slist = p; - }; -}; - -void renderspheres(int time) -{ - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBindTexture(GL_TEXTURE_2D, 4); - - for(sphere *p, **pp = &slist; p = *pp;) - { - glPushMatrix(); - float size = p->size/p->max; - glColor4f(1.0f, 1.0f, 1.0f, 1.0f-size); - glTranslatef(p->o.x, p->o.z, p->o.y); - glRotatef(lastmillis/5.0f, 1, 1, 1); - glScalef(p->size, p->size, p->size); - glCallList(1); - glScalef(0.8f, 0.8f, 0.8f); - glCallList(1); - glPopMatrix(); - xtraverts += 12*6*2; - - if(p->size>p->max) - { - *pp = p->next; - p->next = sempty; - sempty = p; - } - else - { - p->size += time/30.0f; - pp = &p->next; - }; - }; - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); -}; - -string closeent; -char *entnames[] = -{ - "none?", "light", "playerstart", - "clips", "ammobox","grenade", - "health", "armour", "quaddamage", - "mapmodel", "trigger", - "ladder", "?", "?", "?", "?", -}; - -void renderents() // show sparkly thingies for map entities in edit mode -{ - closeent[0] = 0; - if(!editmode) return; - loopv(ents) - { - entity &e = ents[i]; - if(e.type==NOTUSED) continue; - vec v = { e.x, e.y, e.z }; - particle_splash(2, 2, 40, v); - }; - int e = closestent(); - if(e>=0) - { - entity &c = ents[e]; - sprintf_s(closeent)("closest entity = %s (%d, %d, %d, %d), selection = (%d, %d)", entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, getvar("selxs"), getvar("selys")); - }; -}; - -void loadsky(char *basename) -{ - static string lastsky = ""; - if(strcmp(lastsky, basename)==0) return; - char *side[] = { "ft", "bk", "lf", "rt", "dn", "up" }; - int texnum = 14; - loopi(6) - { - sprintf_sd(name)("packages/%s_%s.jpg", basename, side[i]); - int xs, ys; - if(!installtex(texnum+i, path(name), xs, ys, true)) conoutf("could not load sky textures"); - }; - strcpy_s(lastsky, basename); -}; - -COMMAND(loadsky, ARG_1STR); - -float cursordepth = 0.9f; -GLint viewport[4]; -GLdouble mm[16], pm[16]; -vec worldpos; - -void readmatrices() -{ - glGetIntegerv(GL_VIEWPORT, viewport); - glGetDoublev(GL_MODELVIEW_MATRIX, mm); - glGetDoublev(GL_PROJECTION_MATRIX, pm); -}; - -// stupid function to cater for stupid ATI drivers that return incorrect depth values - -float depthcorrect(float d) -{ - static int when = 0; - static float factor = 1; - //if(when++==5) factor = 0.992205f/d; // this magic value is tied to the fixed start spawn point in metl3 - return d*factor; -}; - -// find out the 3d target of the crosshair in the world easily and very acurately. -// sadly many very old cards and drivers appear to fuck up on gluUnProject() and give false -// coordinates, making shooting and such impossible. -// also hits map entities which is unwanted. -// could be replaced by a more acurate version of monster.cpp los() if needed - -void readdepth(int w, int h) -{ - glReadPixels(w/2, h/2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &cursordepth); - double worldx = 0, worldy = 0, worldz = 0; - gluUnProject(w/2, h/2, depthcorrect(cursordepth), mm, pm, viewport, &worldx, &worldz, &worldy); - worldpos.x = (float)worldx; - worldpos.y = (float)worldy; - worldpos.z = (float)worldz; - vec r = { (float)mm[0], (float)mm[4], (float)mm[8] }; - vec u = { (float)mm[1], (float)mm[5], (float)mm[9] }; - setorient(r, u); -}; - -void drawicon(float tx, float ty, int x, int y, float scale=1.0f) -{ - glBindTexture(GL_TEXTURE_2D, 5); - glBegin(GL_QUADS); - tx /= 192; - ty /= 192; - float o = 1/3.0f; - int s = 120*scale; - glTexCoord2f(tx, ty); glVertex2i(x, y); - glTexCoord2f(tx+o, ty); glVertex2i(x+s, y); - glTexCoord2f(tx+o, ty+o); glVertex2i(x+s, y+s); - glTexCoord2f(tx, ty+o); glVertex2i(x, y+s); - glEnd(); - xtraverts += 4; -}; - -void invertperspective() -{ - // This only generates a valid inverse matrix for matrices generated by gluPerspective() - GLdouble inv[16]; - memset(inv, 0, sizeof(inv)); - - inv[0*4+0] = 1.0/pm[0*4+0]; - inv[1*4+1] = 1.0/pm[1*4+1]; - inv[2*4+3] = 1.0/pm[3*4+2]; - inv[3*4+2] = -1.0; - inv[3*4+3] = pm[2*4+2]/pm[3*4+2]; - - glLoadMatrixd(inv); -}; - -VAR(crosshairsize, 0, 15, 50); - -int dblend = 0; -void damageblend(int n) { dblend += n; }; - -VAR(hidestats, 0, 0, 1); -VAR(crosshairfx, 0, 1, 1); - -void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater) -{ - - readmatrices(); - if(editmode) - { - if(cursordepth==1.0f) worldpos = player1->o; - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - cursorupdate(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - }; - - glDisable(GL_DEPTH_TEST); - invertperspective(); - glPushMatrix(); - glOrtho(0, VIRTW, VIRTH, 0, -1, 1); - glEnable(GL_BLEND); - - if(dblend || underwater) - { - glDepthMask(GL_FALSE); - glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - glBegin(GL_QUADS); - if(dblend) glColor3d(0.0f, 0.9f, 0.9f); - else glColor3d(0.9f, 0.5f, 0.0f); - glVertex2i(0, 0); - glVertex2i(VIRTW, 0); - glVertex2i(VIRTW, VIRTH); - glVertex2i(0, VIRTH); - glEnd(); - glDepthMask(GL_TRUE); - dblend -= curtime/3; - if(dblend<0) dblend = 0; - }; - - glEnable(GL_TEXTURE_2D); - - char *command = getcurcommand(); - dynent *player = playerincrosshair(); - if(command) draw_textf("> %s_", 20, 1570, 2, (int)command); - else if(closeent[0]) draw_text(closeent, 20, 1570, 2); - else if(player) - { - string plinfo; - if(isteam(player->team, player1->team)) sprintf_s(plinfo)("%s (health:%i armour:%i)", player->name, player->health, player->armour); - else sprintf_s(plinfo)("%s", player->name); - draw_text(plinfo, 20, 1570, 2); - }; - - renderscores(); - if(!rendermenu()) - { - glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA); - glBindTexture(GL_TEXTURE_2D, 1); - glBegin(GL_QUADS); - glColor3ub(255,255,255); - if(crosshairfx) - { - if(player1->gunwait) glColor3ub(128,128,128); - else if(player1->health<=25) glColor3ub(255,0,0); - else if(player1->health<=50) glColor3ub(255,128,0); - }; - float chsize = (float)crosshairsize; - glTexCoord2d(0.0, 0.0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 - chsize); - glTexCoord2d(1.0, 0.0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 - chsize); - glTexCoord2d(1.0, 1.0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 + chsize); - glTexCoord2d(0.0, 1.0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 + chsize); - glEnd(); - }; - - glPopMatrix(); - - glPushMatrix(); - glOrtho(0, VIRTW*4/3, VIRTH*4/3, 0, -1, 1); - renderconsole(); - - if(!hidestats) - { - glPopMatrix(); - glPushMatrix(); - glOrtho(0, VIRTW*3/2, VIRTH*3/2, 0, -1, 1); - draw_textf("fps %d", 3200, 2320, 2, curfps); - draw_textf("lod %d", 3200, 2390, 2, lod_factor()); - draw_textf("wqd %d", 3200, 2460, 2, nquads); - draw_textf("wvt %d", 3200, 2530, 2, curvert); - draw_textf("evt %d", 3200, 2600, 2, xtraverts); - }; - - glPopMatrix(); - - if(player1->state==CS_ALIVE) - { - glPushMatrix(); - glOrtho(0, VIRTW/2, VIRTH/2, 0, -1, 1); - draw_textf("%d", 90, 827, 2, player1->health); - if(player1->armour) draw_textf("%d", 390, 827, 2, player1->armour); - //draw_textf("%d", 690, 827, 2, player1->mag[player1->gunselect]); - if (player1->gunselect!=GUN_KNIFE) - { - //draw_textf("%d", 690, 827, 2, player1->mag[player1->gunselect]); - char gunstats [64]; - sprintf(gunstats,"%i/%i",player1->mag[player1->gunselect],player1->ammo[player1->gunselect]); - draw_text(gunstats, 690, 827, 2); - //clean up pointer? - //delete gunstats; - } - - glPopMatrix(); - glPushMatrix(); - glOrtho(0, VIRTW, VIRTH, 0, -1, 1); - glDisable(GL_BLEND); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(1.0f, 1.0f, 1.0f, (float) 0.2f+(sin(lastmillis/100)+1)/2); - - if(player1->health <= 20) - { - glEnable(GL_BLEND); - drawicon(64, 0, 20, 1650); //drawicon(128, 128, 20, 1650); - glDisable(GL_BLEND); - } - else drawicon(64, 0, 20, 1650); //drawicon(128, 128, 20, 1650); - if(player1->armour) drawicon((float)(128), 0, 620, 1650); //if(player1->armour) drawicon((float)(player1->armourtype*64), 0, 620, 1650); - int g = player1->gunselect; - int r = 64; - if(g>2) { g -= 3; r = 128; }; - - if(!player1->mag[player1->gunselect] && player1->gunselect != GUN_KNIFE && player1->gunselect != GUN_GRENADE) - { - glEnable(GL_BLEND); - drawicon((float)(g*64), (float)r, 1220, 1650); - glDisable(GL_BLEND); - } - else drawicon((float)(g*64), (float)r, 1220, 1650); - glPopMatrix(); - }; - - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glEnable(GL_DEPTH_TEST); -}; - -#define MAXSHOTLINES 100 -struct shotline -{ - vec from, to; - bool inuse; - int millis; -}; -shotline shotlines[MAXSHOTLINES]; - -void shotlinereset() { loopi(MAXSHOTLINES) shotlines[i].inuse = false; }; - -void addshotline(dynent *d, vec &from, vec &to) -{ - if(d == player1) return; - if(rnd(3) != 0) return; - loopi(MAXSHOTLINES) - { - shotline *s = &shotlines[i]; - if(s->inuse) continue; - int start = 10; - vdist(_dist, _unitv, player1->o, to); - if(_dist <= 10.0f) start = 8; - else start = 5; - - vdist(dist, unitv, from, to); - vdiv(unitv, dist); - s->inuse = true; - s->from = unitv; - vmul(s->from, dist/10*start); - vadd(s->from, from); - s->to = unitv; - vmul(s->to, dist/10*-(10-start-2)); - vadd(s->to, to); - s->millis = lastmillis; - return; - }; -}; - -VAR(shotline_duration, 0, 75, 10000); - -void rendershotlines() -{ - loopi(MAXSHOTLINES) - { - shotline *s = &shotlines[i]; - if(!s->inuse) continue; - if(lastmillis-s->millis > shotline_duration) { s->inuse = false; continue; } - glPushMatrix(); - glDisable(GL_TEXTURE_2D); - - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA); - glDisable(GL_FOG); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glBegin(GL_LINES); - glColor4f(1.0f, 1.0f, 0.7f, 0.5f); - glVertex3f(s->from.x, s->from.z, s->from.y); - glVertex3f(s->to.x, s->to.z, s->to.y); - glEnd(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glEnable(GL_FOG); - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - - glEnable(GL_TEXTURE_2D); - glPopMatrix(); - }; -}; - -void renderphysents() -{ - loopv(physents) - { - physent *d = physents[i]; - if(d && d->throwed) rendermodel("vwep/grenade_static", 0, 1, 0, 0, d->o.x, d->o.z, d->o.y, d->yaw, d->pitch, false, 2.0f, 100.0f, 0, 0); - }; -}; - +// renderextras.cpp: misc gl render code and the HUD + + + +#include "cube.h" + + + +void line(int x1, int y1, float z1, int x2, int y2, float z2) + +{ + + glBegin(GL_POLYGON); + + glVertex3f((float)x1, z1, (float)y1); + + glVertex3f((float)x1, z1, y1+0.01f); + + glVertex3f((float)x2, z2, y2+0.01f); + + glVertex3f((float)x2, z2, (float)y2); + + glEnd(); + + xtraverts += 4; + +}; + + + +void linestyle(float width, int r, int g, int b) + +{ + + glLineWidth(width); + + glColor3ub(r,g,b); + +}; + + + +void box(block &b, float z1, float z2, float z3, float z4) + +{ + + glBegin(GL_POLYGON); + + glVertex3f((float)b.x, z1, (float)b.y); + + glVertex3f((float)b.x+b.xs, z2, (float)b.y); + + glVertex3f((float)b.x+b.xs, z3, (float)b.y+b.ys); + + glVertex3f((float)b.x, z4, (float)b.y+b.ys); + + glEnd(); + + xtraverts += 4; + +}; + + + +void dot(int x, int y, float z) + +{ + + const float DOF = 0.1f; + + glBegin(GL_POLYGON); + + glVertex3f(x-DOF, (float)z, y-DOF); + + glVertex3f(x+DOF, (float)z, y-DOF); + + glVertex3f(x+DOF, (float)z, y+DOF); + + glVertex3f(x-DOF, (float)z, y+DOF); + + glEnd(); + + xtraverts += 4; + +}; + + + +void blendbox(int x1, int y1, int x2, int y2, bool border, int tex) + +{ + + glDepthMask(GL_FALSE); + + glDisable(GL_TEXTURE_2D); + + if(tex>=0) + + { + + glBindTexture(GL_TEXTURE_2D, tex); + + glEnable(GL_TEXTURE_2D); + + glDisable(GL_BLEND); + + } + + else + + { + + if(border) glColor3d(0.7, 0.7, 0.7); //glColor3d(0.5, 0.3, 0.4); + + else glColor3d(1.0, 1.0, 1.0); + + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + + }; + + glBegin(GL_QUADS); + + glTexCoord2f(0, 0); glVertex2i(x1, y1); + + glTexCoord2f(1, 0); glVertex2i(x2, y1); + + glTexCoord2f(1, 1); glVertex2i(x2, y2); + + glTexCoord2f(0, 1); glVertex2i(x1, y2); + + glEnd(); + + glDisable(GL_BLEND); + + if(tex>=0) glDisable(GL_TEXTURE_2D); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + glBegin(GL_POLYGON); + + glColor3d(0.6, 0.6, 0.6); //glColor3d(0.2, 0.7, 0.4); + + glVertex2i(x1, y1); + + glVertex2i(x2, y1); + + glVertex2i(x2, y2); + + glVertex2i(x1, y2); + + glEnd(); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + xtraverts += 8; + + glEnable(GL_BLEND); + + glEnable(GL_TEXTURE_2D); + + glDepthMask(GL_TRUE); + +}; + + + +const int MAXSPHERES = 50; + +struct sphere { vec o; float size, max; int type; sphere *next; }; + +sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL; + +bool sinit = false; + + + +void newsphere(vec &o, float max, int type) + +{ + + if(!sinit) + + { + + loopi(MAXSPHERES) + + { + + spheres[i].next = sempty; + + sempty = &spheres[i]; + + }; + + sinit = true; + + }; + + if(sempty) + + { + + sphere *p = sempty; + + sempty = p->next; + + p->o = o; + + p->max = max; + + p->size = 1; + + p->type = type; + + p->next = slist; + + slist = p; + + }; + +}; + + + +void renderspheres(int time) + +{ + + glDepthMask(GL_FALSE); + + glEnable(GL_BLEND); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glBindTexture(GL_TEXTURE_2D, 4); + + + + for(sphere *p, **pp = &slist; p = *pp;) + + { + + glPushMatrix(); + + float size = p->size/p->max; + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f-size); + + glTranslatef(p->o.x, p->o.z, p->o.y); + + glRotatef(lastmillis/5.0f, 1, 1, 1); + + glScalef(p->size, p->size, p->size); + + glCallList(1); + + glScalef(0.8f, 0.8f, 0.8f); + + glCallList(1); + + glPopMatrix(); + + xtraverts += 12*6*2; + + + + if(p->size>p->max) + + { + + *pp = p->next; + + p->next = sempty; + + sempty = p; + + } + + else + + { + + p->size += time/30.0f; + + pp = &p->next; + + }; + + }; + + + + glDisable(GL_BLEND); + + glDepthMask(GL_TRUE); + +}; + + + +string closeent; + +char *entnames[] = + +{ + + "none?", "light", "playerstart", + + "clips", "ammobox","grenade", + + "health", "armour", "quaddamage", + + "mapmodel", "trigger", + + "ladder", "?", "?", "?", "?", + +}; + + + +void renderents() // show sparkly thingies for map entities in edit mode + +{ + + closeent[0] = 0; + + if(!editmode) return; + + loopv(ents) + + { + + entity &e = ents[i]; + + if(e.type==NOTUSED) continue; + + vec v = { e.x, e.y, e.z }; + + particle_splash(2, 2, 40, v); + + }; + + int e = closestent(); + + if(e>=0) + + { + + entity &c = ents[e]; + + sprintf_s(closeent)("closest entity = %s (%d, %d, %d, %d), selection = (%d, %d)", entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, getvar("selxs"), getvar("selys")); + + }; + +}; + + + +void loadsky(char *basename) + +{ + + static string lastsky = ""; + + if(strcmp(lastsky, basename)==0) return; + + char *side[] = { "ft", "bk", "lf", "rt", "dn", "up" }; + + int texnum = 14; + + loopi(6) + + { + + sprintf_sd(name)("packages/%s_%s.jpg", basename, side[i]); + + int xs, ys; + + if(!installtex(texnum+i, path(name), xs, ys, true)) conoutf("could not load sky textures"); + + }; + + strcpy_s(lastsky, basename); + +}; + + + +COMMAND(loadsky, ARG_1STR); + + + +float cursordepth = 0.9f; + +GLint viewport[4]; + +GLdouble mm[16], pm[16]; + +vec worldpos; + + + +void readmatrices() + +{ + + glGetIntegerv(GL_VIEWPORT, viewport); + + glGetDoublev(GL_MODELVIEW_MATRIX, mm); + + glGetDoublev(GL_PROJECTION_MATRIX, pm); + +}; + + + +// stupid function to cater for stupid ATI drivers that return incorrect depth values + + + +float depthcorrect(float d) + +{ + + static int when = 0; + + static float factor = 1; + + //if(when++==5) factor = 0.992205f/d; // this magic value is tied to the fixed start spawn point in metl3 + + return d*factor; + +}; + + + +// find out the 3d target of the crosshair in the world easily and very acurately. + +// sadly many very old cards and drivers appear to fuck up on gluUnProject() and give false + +// coordinates, making shooting and such impossible. + +// also hits map entities which is unwanted. + +// could be replaced by a more acurate version of monster.cpp los() if needed + + + +void readdepth(int w, int h) + +{ + + glReadPixels(w/2, h/2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &cursordepth); + + double worldx = 0, worldy = 0, worldz = 0; + + gluUnProject(w/2, h/2, depthcorrect(cursordepth), mm, pm, viewport, &worldx, &worldz, &worldy); + + worldpos.x = (float)worldx; + + worldpos.y = (float)worldy; + + worldpos.z = (float)worldz; + + vec r = { (float)mm[0], (float)mm[4], (float)mm[8] }; + + vec u = { (float)mm[1], (float)mm[5], (float)mm[9] }; + + setorient(r, u); + +}; + + + +void drawicon(float tx, float ty, int x, int y, float scale=1.0f) + +{ + + glBindTexture(GL_TEXTURE_2D, 5); + + glBegin(GL_QUADS); + + tx /= 192; + + ty /= 192; + + float o = 1/3.0f; + + int s = 120*scale; + + glTexCoord2f(tx, ty); glVertex2i(x, y); + + glTexCoord2f(tx+o, ty); glVertex2i(x+s, y); + + glTexCoord2f(tx+o, ty+o); glVertex2i(x+s, y+s); + + glTexCoord2f(tx, ty+o); glVertex2i(x, y+s); + + glEnd(); + + xtraverts += 4; + +}; + + + +void invertperspective() + +{ + + // This only generates a valid inverse matrix for matrices generated by gluPerspective() + + GLdouble inv[16]; + + memset(inv, 0, sizeof(inv)); + + + + inv[0*4+0] = 1.0/pm[0*4+0]; + + inv[1*4+1] = 1.0/pm[1*4+1]; + + inv[2*4+3] = 1.0/pm[3*4+2]; + + inv[3*4+2] = -1.0; + + inv[3*4+3] = pm[2*4+2]/pm[3*4+2]; + + + + glLoadMatrixd(inv); + +}; + + + +VAR(crosshairsize, 0, 15, 50); + + + +int dblend = 0; + +void damageblend(int n) { dblend += n; }; + + + +VAR(hidestats, 0, 0, 1); + +VAR(crosshairfx, 0, 1, 1); + + + +void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater) + +{ + + + + readmatrices(); + + if(editmode) + + { + + if(cursordepth==1.0f) worldpos = player1->o; + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + cursorupdate(); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + }; + + + + glDisable(GL_DEPTH_TEST); + + invertperspective(); + + glPushMatrix(); + + glOrtho(0, VIRTW, VIRTH, 0, -1, 1); + + glEnable(GL_BLEND); + + + + if(dblend || underwater) + + { + + glDepthMask(GL_FALSE); + + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + + glBegin(GL_QUADS); + + if(dblend) glColor3d(0.0f, 0.9f, 0.9f); + + else glColor3d(0.9f, 0.5f, 0.0f); + + glVertex2i(0, 0); + + glVertex2i(VIRTW, 0); + + glVertex2i(VIRTW, VIRTH); + + glVertex2i(0, VIRTH); + + glEnd(); + + glDepthMask(GL_TRUE); + + dblend -= curtime/3; + + if(dblend<0) dblend = 0; + + }; + + + + glEnable(GL_TEXTURE_2D); + + + + char *command = getcurcommand(); + + dynent *player = playerincrosshair(); + + if(command) draw_textf("> %s_", 20, 1570, 2, (int)command); + + else if(closeent[0]) draw_text(closeent, 20, 1570, 2); + + else if(player) + + { + + string plinfo; + + if(isteam(player->team, player1->team)) sprintf_s(plinfo)("%s (health:%i armour:%i)", player->name, player->health, player->armour); + + else sprintf_s(plinfo)("%s", player->name); + + draw_text(plinfo, 20, 1570, 2); + + }; + + + + renderscores(); + + if(!rendermenu()) + + { + + glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA); + + glBindTexture(GL_TEXTURE_2D, 1); + + glBegin(GL_QUADS); + + glColor3ub(255,255,255); + + if(crosshairfx) + + { + + if(player1->gunwait) glColor3ub(128,128,128); + + else if(player1->health<=25) glColor3ub(255,0,0); + + else if(player1->health<=50) glColor3ub(255,128,0); + + }; + + float chsize = (float)crosshairsize; + + glTexCoord2d(0.0, 0.0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 - chsize); + + glTexCoord2d(1.0, 0.0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 - chsize); + + glTexCoord2d(1.0, 1.0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 + chsize); + + glTexCoord2d(0.0, 1.0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 + chsize); + + glEnd(); + + }; + + + + glPopMatrix(); + + + + glPushMatrix(); + + glOrtho(0, VIRTW*4/3, VIRTH*4/3, 0, -1, 1); + + renderconsole(); + + + + if(!hidestats) + + { + + glPopMatrix(); + + glPushMatrix(); + + glOrtho(0, VIRTW*3/2, VIRTH*3/2, 0, -1, 1); + + draw_textf("fps %d", 3200, 2320, 2, curfps); + + draw_textf("lod %d", 3200, 2390, 2, lod_factor()); + + draw_textf("wqd %d", 3200, 2460, 2, nquads); + + draw_textf("wvt %d", 3200, 2530, 2, curvert); + + draw_textf("evt %d", 3200, 2600, 2, xtraverts); + + }; + + + + glPopMatrix(); + + + + if(player1->state==CS_ALIVE) + + { + + glPushMatrix(); + + glOrtho(0, VIRTW/2, VIRTH/2, 0, -1, 1); + + draw_textf("%d", 90, 827, 2, player1->health); + + if(player1->armour) draw_textf("%d", 390, 827, 2, player1->armour); + + //draw_textf("%d", 690, 827, 2, player1->mag[player1->gunselect]); + + if (player1->gunselect!=GUN_KNIFE) + + { + + //draw_textf("%d", 690, 827, 2, player1->mag[player1->gunselect]); + + char gunstats [64]; + + sprintf(gunstats,"%i/%i",player1->mag[player1->gunselect],player1->ammo[player1->gunselect]); + + draw_text(gunstats, 690, 827, 2); + + //clean up pointer? + + //delete gunstats; + + } + + + + glPopMatrix(); + + glPushMatrix(); + + glOrtho(0, VIRTW, VIRTH, 0, -1, 1); + + glDisable(GL_BLEND); + + + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glColor4f(1.0f, 1.0f, 1.0f, (float) 0.2f+(sin(lastmillis/100)+1)/2); + + + + if(player1->health <= 20) + + { + + glEnable(GL_BLEND); + + drawicon(64, 0, 20, 1650); //drawicon(128, 128, 20, 1650); + + glDisable(GL_BLEND); + + } + + else drawicon(64, 0, 20, 1650); //drawicon(128, 128, 20, 1650); + + if(player1->armour) drawicon((float)(128), 0, 620, 1650); //if(player1->armour) drawicon((float)(player1->armourtype*64), 0, 620, 1650); + + int g = player1->gunselect; + + int r = 64; + + if(g>2) { g -= 3; r = 128; }; + + + + if(!player1->mag[player1->gunselect] && player1->gunselect != GUN_KNIFE && player1->gunselect != GUN_GRENADE) + + { + + glEnable(GL_BLEND); + + drawicon((float)(g*64), (float)r, 1220, 1650); + + glDisable(GL_BLEND); + + } + + else drawicon((float)(g*64), (float)r, 1220, 1650); + + glPopMatrix(); + + }; + + + + glDisable(GL_BLEND); + + glDisable(GL_TEXTURE_2D); + + glEnable(GL_DEPTH_TEST); + +}; + + + +#define MAXSHOTLINES 100 + +struct shotline + +{ + + vec from, to; + + bool inuse; + + int millis; + +}; + +shotline shotlines[MAXSHOTLINES]; + + + +void shotlinereset() { loopi(MAXSHOTLINES) shotlines[i].inuse = false; }; + + + +void addshotline(dynent *d, vec &from, vec &to) + +{ + + if(d == player1) return; + + if(rnd(3) != 0) return; + + loopi(MAXSHOTLINES) + + { + + shotline *s = &shotlines[i]; + + if(s->inuse) continue; + + int start = 10; + + vdist(_dist, _unitv, player1->o, to); + + if(_dist <= 10.0f) start = 8; + + else start = 5; + + + + vdist(dist, unitv, from, to); + + vdiv(unitv, dist); + + s->inuse = true; + + s->from = unitv; + + vmul(s->from, dist/10*start); + + vadd(s->from, from); + + s->to = unitv; + + vmul(s->to, dist/10*-(10-start-2)); + + vadd(s->to, to); + + s->millis = lastmillis; + + return; + + }; + +}; + + + +VAR(shotline_duration, 0, 75, 10000); + + + +void rendershotlines() + +{ + + loopi(MAXSHOTLINES) + + { + + shotline *s = &shotlines[i]; + + if(!s->inuse) continue; + + if(lastmillis-s->millis > shotline_duration) { s->inuse = false; continue; } + + glPushMatrix(); + + glDisable(GL_TEXTURE_2D); + + + + glDepthMask(GL_FALSE); + + glEnable(GL_BLEND); + + glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA); + + glDisable(GL_FOG); + + + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + glBegin(GL_LINES); + + glColor4f(1.0f, 1.0f, 0.7f, 0.5f); + + glVertex3f(s->from.x, s->from.z, s->from.y); + + glVertex3f(s->to.x, s->to.z, s->to.y); + + glEnd(); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + + + glEnable(GL_FOG); + + glDisable(GL_BLEND); + + glDepthMask(GL_TRUE); + + + + glEnable(GL_TEXTURE_2D); + + glPopMatrix(); + + }; + +}; + + + +void renderphysents() + +{ + + loopv(physents) + + { + + physent *d = physents[i]; + + if(d && d->throwed) rendermodel("vwep/grenade_static", 0, 1, 0, 0, d->o.x, d->o.z, d->o.y, d->yaw, d->pitch, false, 2.0f, 100.0f, 0, 0); + + }; + +}; + + + diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index f19ff21e..969b1e1a 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -1,408 +1,816 @@ -// rendergl.cpp: core opengl rendering stuff - -#include "cube.h" - -#ifdef DARWIN -#define GL_COMBINE_EXT GL_COMBINE_ARB -#define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB -#define GL_SOURCE0_RBG_EXT GL_SOURCE0_RGB_ARB -#define GL_SOURCE1_RBG_EXT GL_SOURCE1_RGB_ARB -#define GL_RGB_SCALE_EXT GL_RGB_SCALE_ARB -#endif - -extern int curvert; - -bool hasoverbright = false; - -void purgetextures(); - -GLUquadricObj *qsphere = NULL; -int glmaxtexsize = 256; - -void gl_init(int w, int h) -{ - //#define fogvalues 0.5f, 0.6f, 0.7f, 1.0f - - glViewport(0, 0, w, h); - glClearDepth(1.0); - glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_TEST); - glShadeModel(GL_SMOOTH); - - - glEnable(GL_FOG); - glFogi(GL_FOG_MODE, GL_LINEAR); - glFogf(GL_FOG_DENSITY, 0.25); - glHint(GL_FOG_HINT, GL_NICEST); - - - glEnable(GL_LINE_SMOOTH); - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - glEnable(GL_POLYGON_OFFSET_LINE); - glPolygonOffset(-3.0, -3.0); - - glCullFace(GL_FRONT); - glEnable(GL_CULL_FACE); - - char *exts = (char *)glGetString(GL_EXTENSIONS); - - if(strstr(exts, "GL_EXT_texture_env_combine")) hasoverbright = true; - else conoutf("WARNING: cannot use overbright lighting, using old lighting model!"); - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glmaxtexsize); - - purgetextures(); - - if(!(qsphere = gluNewQuadric())) fatal("glu sphere"); - gluQuadricDrawStyle(qsphere, GLU_FILL); - gluQuadricOrientation(qsphere, GLU_INSIDE); - gluQuadricTexture(qsphere, GL_TRUE); - glNewList(1, GL_COMPILE); - gluSphere(qsphere, 1, 12, 6); - glEndList(); -}; - -void cleangl() -{ - if(qsphere) gluDeleteQuadric(qsphere); -}; - -bool installtex(int tnum, char *texname, int &xs, int &ys, bool clamp, bool highqual=false) -{ - SDL_Surface *s = IMG_Load(texname); - if(!s) { conoutf("couldn't load texture %s", (int)texname); return false; }; - if(s->format->BitsPerPixel!=24) { conoutf("texture must be 24bpp: %s", (int)texname); return false; }; - // loopi(s->w*s->h*3) { uchar *p = (uchar *)s->pixels+i; *p = 255-*p; }; - glBindTexture(GL_TEXTURE_2D, tnum); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, highqual ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); //NEAREST); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - xs = s->w; - ys = s->h; - while(xs>glmaxtexsize || ys>glmaxtexsize) { xs /= 2; ys /= 2; }; - void *scaledimg = s->pixels; - if(xs!=s->w) - { - conoutf("warning: quality loss: scaling %s", (int)texname); // for voodoo cards under linux - scaledimg = alloc(xs*ys*3); - gluScaleImage(GL_RGB, s->w, s->h, GL_UNSIGNED_BYTE, s->pixels, xs, ys, GL_UNSIGNED_BYTE, scaledimg); - }; - if(gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, xs, ys, GL_RGB, GL_UNSIGNED_BYTE, scaledimg)) fatal("could not build mipmaps"); - if(xs!=s->w) free(scaledimg); - SDL_FreeSurface(s); - return true; -}; - -// management of texture slots -// each texture slot can have multople texture frames, of which currently only the first is used -// additional frames can be used for various shaders - -const int MAXTEX = 1000; -int texx[MAXTEX]; // ( loaded texture ) -> ( name, size ) -int texy[MAXTEX]; -string texname[MAXTEX]; -int curtex = 0; -const int FIRSTTEX = 100; // opengl id = loaded id + FIRSTTEX -// std 1+, sky 14+, md3's 30+,md2's 40+, menu 90+ - -const int MAXFRAMES = 2; // increase to allow more complex shader defs -int mapping[256][MAXFRAMES]; // ( cube texture, frame ) -> ( opengl id, name ) -string mapname[256][MAXFRAMES]; - -void purgetextures() -{ - loopi(256) loop(j,MAXFRAMES) mapping[i][j] = 0; -}; - -int curtexnum = 0; - -void texturereset() { curtexnum = 0; }; - -void texture(char *aframe, char *name) -{ - int num = curtexnum++, frame = atoi(aframe); - if(num<0 || num>=256 || frame<0 || frame>=MAXFRAMES) return; - mapping[num][frame] = 1; - char *n = mapname[num][frame]; - strcpy_s(n, name); - path(n); -}; - -COMMAND(texturereset, ARG_NONE); -COMMAND(texture, ARG_2STR); - -int lookuptexture(int tex, int &xs, int &ys) -{ - int frame = 0; // other frames? - int tid = mapping[tex][frame]; - - if(tid>=FIRSTTEX) - { - xs = texx[tid-FIRSTTEX]; - ys = texy[tid-FIRSTTEX]; - return tid; - }; - - xs = ys = 16; - if(!tid) return 1; // crosshair :) - - loopi(curtex) // lazily happens once per "texture" command, basically - { - if(strcmp(mapname[tex][frame], texname[i])==0) - { - mapping[tex][frame] = tid = i+FIRSTTEX; - xs = texx[i]; - ys = texy[i]; - return tid; - }; - }; - - if(curtex==MAXTEX) fatal("loaded too many textures"); - - int tnum = curtex+FIRSTTEX; - strcpy_s(texname[curtex], mapname[tex][frame]); - - sprintf_sd(name)("packages%ctextures%c%s", PATHDIV, PATHDIV, texname[curtex]); - - if(installtex(tnum, name, xs, ys)) - { - mapping[tex][frame] = tnum; - texx[curtex] = xs; - texy[curtex] = ys; - curtex++; - return tnum; - } - else - { - return mapping[tex][frame] = FIRSTTEX; // temp fix - }; -}; - -void setupworld() -{ - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - setarraypointers(); - - if(hasoverbright) - { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); - }; -}; - -int skyoglid; - -struct strip { int tex, start, num; }; -vector strips; - -void renderstripssky() -{ - glBindTexture(GL_TEXTURE_2D, skyoglid); - loopv(strips) if(strips[i].tex==skyoglid) glDrawArrays(GL_TRIANGLE_STRIP, strips[i].start, strips[i].num); -}; - -void renderstrips() -{ - int lasttex = -1; - loopv(strips) if(strips[i].tex!=skyoglid) - { - if(strips[i].tex!=lasttex) - { - glBindTexture(GL_TEXTURE_2D, strips[i].tex); - lasttex = strips[i].tex; - }; - glDrawArrays(GL_TRIANGLE_STRIP, strips[i].start, strips[i].num); - }; -}; - -void overbright(float amount) { if(hasoverbright) glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, amount ); }; - -void addstrip(int tex, int start, int n) -{ - strip &s = strips.add(); - s.tex = tex; - s.start = start; - s.num = n; -}; - -VARF(gamma, 30, 100, 300, -{ - float f = gamma/100.0f; - if(SDL_SetGamma(f,f,f)==-1) - { - conoutf("Could not set gamma (card/driver doesn't support it?)"); - conoutf("sdl: %s", (int)SDL_GetError()); - }; -}); - -void transplayer() -{ - glLoadIdentity(); - - if(player1->state==CS_DEAD) - { - float t = (lastmillis-player1->lastaction)/1000.0f; - if(t >= 1.6f) t = 1.6f; - - player1->pitch = (float) sin(t)*(-70.0f-player1->oldpitch)+player1->oldpitch; - glRotated(player1->pitch,-1.0,0.0,0.0); - glRotated(player1->yaw,0.0,1.0,0.0); - - glTranslated(-player1->o.x, player1->eyeheight-sin(t)*7.0f-player1->o.z, -player1->o.y); - } - else - { - glRotated(player1->roll,0.0,0.0,1.0); - glRotated(player1->pitch,-1.0,0.0,0.0); - glRotated(player1->yaw,0.0,1.0,0.0); - - glTranslated(-player1->o.x, (player1->state==CS_DEAD ? player1->eyeheight-0.2f : 0)-player1->o.z, -player1->o.y); - }; -}; - -VAR(fov, 10, 105, 120); - -int xtraverts; - -VAR(fog, 64, 180, 1024); -VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); - -VAR(hudgun,0,1,1); - -char *hudgunnames[] = { "knife", "semipistol", "shotgun", "subgun", "sniper", "auto", "grenade" }; - -void drawhudmodel(int start, int end, float speed, int base) -{ - sprintf_sd(mdl)("hudguns/%s", hudgunnames[player1->gunselect]); - rendermodel(mdl, start, end, 0, 1.0f, player1->o.x, player1->o.z, player1->o.y, player1->yaw+90, player1->pitch, false, 1.0f, speed, 0, base); -}; - -void drawhudgun(int w, int h, float aspect, int farplane) -{ - if(!hudgun || player1->state==CS_DEAD) return; - - glEnable(GL_CULL_FACE); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective((float)100.0f*h/w, aspect, 0.3f, farplane); // fov fixed at 100° - glMatrixMode(GL_MODELVIEW); - - rendermd3gun(); - rendermenumdl(); // lazy bastard - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective((float)fov*h/w, aspect, 0.15f, farplane); - glMatrixMode(GL_MODELVIEW); - - glDisable(GL_CULL_FACE); -}; - -void gl_drawframe(int w, int h, float changelod, float curfps) -{ - float hf = hdr.waterlevel-0.3f; - float fovy = (float)fov*h/w; - float aspect = w/(float)h; - bool underwater = player1->o.z>16)/256.0f, ((fogcolour>>8)&255)/256.0f, (fogcolour&255)/256.0f, 1.0f }; - glFogfv(GL_FOG_COLOR, fogc); - glClearColor(fogc[0], fogc[1], fogc[2], 1.0f); - - if(underwater) - { - fovy += (float)sin(lastmillis/1000.0)*2.0f; - aspect += (float)sin(lastmillis/1000.0+PI)*0.1f; - glFogi(GL_FOG_START, 0); - glFogi(GL_FOG_END, (fog+96)/8); - }; - - glClear((player1->outsidemap ? GL_COLOR_BUFFER_BIT : 0) | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - int farplane = fog*5/2; - gluPerspective(fovy, aspect, 0.15f, farplane); - glMatrixMode(GL_MODELVIEW); - - transplayer(); - - glEnable(GL_TEXTURE_2D); - - int xs, ys; - skyoglid = lookuptexture(DEFAULT_SKY, xs, ys); - - resetcubes(); - - curvert = 0; - strips.setsize(0); - - render_world(player1->o.x, player1->o.y, player1->o.z, changelod, - (int)player1->yaw, (int)player1->pitch, (float)fov, w, h); - finishstrips(); - - setupworld(); - - renderstripssky(); - - glLoadIdentity(); - glRotated(player1->pitch, -1.0, 0.0, 0.0); - glRotated(player1->yaw, 0.0, 1.0, 0.0); - glRotated(90.0, 1.0, 0.0, 0.0); - glColor3f(1.0f, 1.0f, 1.0f); - glDisable(GL_FOG); - glDepthFunc(GL_GREATER); - draw_envbox(14, fog*4/3); - glDepthFunc(GL_LESS); - glEnable(GL_FOG); - - transplayer(); - - overbright(2); - - renderstrips(); - - xtraverts = 0; - - renderclients(); - - renderentities(); - - renderspheres(curtime); - renderents(); - - renderphysents(); - - rendershotlines(); - - glDisable(GL_CULL_FACE); - - drawhudgun(w, h, aspect, farplane); - - overbright(1); - int nquads = renderwater(hf); - - overbright(2); - render_particles(curtime); - overbright(1); - - glDisable(GL_FOG); - - glDisable(GL_TEXTURE_2D); - - gl_drawhud(w, h, (int)curfps, nquads, curvert, underwater); - - glEnable(GL_CULL_FACE); - glEnable(GL_FOG); -}; - +// rendergl.cpp: core opengl rendering stuff + + + +#include "cube.h" + + + +#ifdef DARWIN + +#define GL_COMBINE_EXT GL_COMBINE_ARB + +#define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB + +#define GL_SOURCE0_RBG_EXT GL_SOURCE0_RGB_ARB + +#define GL_SOURCE1_RBG_EXT GL_SOURCE1_RGB_ARB + +#define GL_RGB_SCALE_EXT GL_RGB_SCALE_ARB + +#endif + + + +extern int curvert; + + + +bool hasoverbright = false; + + + +void purgetextures(); + + + +GLUquadricObj *qsphere = NULL; + +int glmaxtexsize = 256; + + + +void gl_init(int w, int h) + +{ + + //#define fogvalues 0.5f, 0.6f, 0.7f, 1.0f + + + + glViewport(0, 0, w, h); + + glClearDepth(1.0); + + glDepthFunc(GL_LESS); + + glEnable(GL_DEPTH_TEST); + + glShadeModel(GL_SMOOTH); + + + + + + glEnable(GL_FOG); + + glFogi(GL_FOG_MODE, GL_LINEAR); + + glFogf(GL_FOG_DENSITY, 0.25); + + glHint(GL_FOG_HINT, GL_NICEST); + + + + + + glEnable(GL_LINE_SMOOTH); + + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + + glEnable(GL_POLYGON_OFFSET_LINE); + + glPolygonOffset(-3.0, -3.0); + + + + glCullFace(GL_FRONT); + + glEnable(GL_CULL_FACE); + + + + char *exts = (char *)glGetString(GL_EXTENSIONS); + + + + if(strstr(exts, "GL_EXT_texture_env_combine")) hasoverbright = true; + + else conoutf("WARNING: cannot use overbright lighting, using old lighting model!"); + + + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glmaxtexsize); + + + + purgetextures(); + + + + if(!(qsphere = gluNewQuadric())) fatal("glu sphere"); + + gluQuadricDrawStyle(qsphere, GLU_FILL); + + gluQuadricOrientation(qsphere, GLU_INSIDE); + + gluQuadricTexture(qsphere, GL_TRUE); + + glNewList(1, GL_COMPILE); + + gluSphere(qsphere, 1, 12, 6); + + glEndList(); + +}; + + + +void cleangl() + +{ + + if(qsphere) gluDeleteQuadric(qsphere); + +}; + + + +bool installtex(int tnum, char *texname, int &xs, int &ys, bool clamp, bool highqual) + +{ + + SDL_Surface *s = IMG_Load(texname); + + if(!s) { conoutf("couldn't load texture %s", (int)texname); return false; }; + + if(s->format->BitsPerPixel!=24) { conoutf("texture must be 24bpp: %s", (int)texname); return false; }; + + // loopi(s->w*s->h*3) { uchar *p = (uchar *)s->pixels+i; *p = 255-*p; }; + + glBindTexture(GL_TEXTURE_2D, tnum); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, highqual ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); //NEAREST); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + xs = s->w; + + ys = s->h; + + while(xs>glmaxtexsize || ys>glmaxtexsize) { xs /= 2; ys /= 2; }; + + void *scaledimg = s->pixels; + + if(xs!=s->w) + + { + + conoutf("warning: quality loss: scaling %s", (int)texname); // for voodoo cards under linux + + scaledimg = alloc(xs*ys*3); + + gluScaleImage(GL_RGB, s->w, s->h, GL_UNSIGNED_BYTE, s->pixels, xs, ys, GL_UNSIGNED_BYTE, scaledimg); + + }; + + if(gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, xs, ys, GL_RGB, GL_UNSIGNED_BYTE, scaledimg)) fatal("could not build mipmaps"); + + if(xs!=s->w) free(scaledimg); + + SDL_FreeSurface(s); + + return true; + +}; + + + +// management of texture slots + +// each texture slot can have multople texture frames, of which currently only the first is used + +// additional frames can be used for various shaders + + + +const int MAXTEX = 1000; + +int texx[MAXTEX]; // ( loaded texture ) -> ( name, size ) + +int texy[MAXTEX]; + +string texname[MAXTEX]; + +int curtex = 0; + +const int FIRSTTEX = 100; // opengl id = loaded id + FIRSTTEX + +// std 1+, sky 14+, md3's 30+,md2's 40+, menu 90+ + + + +const int MAXFRAMES = 2; // increase to allow more complex shader defs + +int mapping[256][MAXFRAMES]; // ( cube texture, frame ) -> ( opengl id, name ) + +string mapname[256][MAXFRAMES]; + + + +void purgetextures() + +{ + + loopi(256) loop(j,MAXFRAMES) mapping[i][j] = 0; + +}; + + + +int curtexnum = 0; + + + +void texturereset() { curtexnum = 0; }; + + + +void texture(char *aframe, char *name) + +{ + + int num = curtexnum++, frame = atoi(aframe); + + if(num<0 || num>=256 || frame<0 || frame>=MAXFRAMES) return; + + mapping[num][frame] = 1; + + char *n = mapname[num][frame]; + + strcpy_s(n, name); + + path(n); + +}; + + + +COMMAND(texturereset, ARG_NONE); + +COMMAND(texture, ARG_2STR); + + + +int lookuptexture(int tex, int &xs, int &ys) + +{ + + int frame = 0; // other frames? + + int tid = mapping[tex][frame]; + + + + if(tid>=FIRSTTEX) + + { + + xs = texx[tid-FIRSTTEX]; + + ys = texy[tid-FIRSTTEX]; + + return tid; + + }; + + + + xs = ys = 16; + + if(!tid) return 1; // crosshair :) + + + + loopi(curtex) // lazily happens once per "texture" command, basically + + { + + if(strcmp(mapname[tex][frame], texname[i])==0) + + { + + mapping[tex][frame] = tid = i+FIRSTTEX; + + xs = texx[i]; + + ys = texy[i]; + + return tid; + + }; + + }; + + + + if(curtex==MAXTEX) fatal("loaded too many textures"); + + + + int tnum = curtex+FIRSTTEX; + + strcpy_s(texname[curtex], mapname[tex][frame]); + + + + sprintf_sd(name)("packages%ctextures%c%s", PATHDIV, PATHDIV, texname[curtex]); + + + + if(installtex(tnum, name, xs, ys)) + + { + + mapping[tex][frame] = tnum; + + texx[curtex] = xs; + + texy[curtex] = ys; + + curtex++; + + return tnum; + + } + + else + + { + + return mapping[tex][frame] = FIRSTTEX; // temp fix + + }; + +}; + + + +void setupworld() + +{ + + glEnableClientState(GL_VERTEX_ARRAY); + + glEnableClientState(GL_COLOR_ARRAY); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + setarraypointers(); + + + + if(hasoverbright) + + { + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); + + }; + +}; + + + +int skyoglid; + + + +struct strip { int tex, start, num; }; + +vector strips; + + + +void renderstripssky() + +{ + + glBindTexture(GL_TEXTURE_2D, skyoglid); + + loopv(strips) if(strips[i].tex==skyoglid) glDrawArrays(GL_TRIANGLE_STRIP, strips[i].start, strips[i].num); + +}; + + + +void renderstrips() + +{ + + int lasttex = -1; + + loopv(strips) if(strips[i].tex!=skyoglid) + + { + + if(strips[i].tex!=lasttex) + + { + + glBindTexture(GL_TEXTURE_2D, strips[i].tex); + + lasttex = strips[i].tex; + + }; + + glDrawArrays(GL_TRIANGLE_STRIP, strips[i].start, strips[i].num); + + }; + +}; + + + +void overbright(float amount) { if(hasoverbright) glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, amount ); }; + + + +void addstrip(int tex, int start, int n) + +{ + + strip &s = strips.add(); + + s.tex = tex; + + s.start = start; + + s.num = n; + +}; + + + +VARF(gamma, 30, 100, 300, + +{ + + float f = gamma/100.0f; + + if(SDL_SetGamma(f,f,f)==-1) + + { + + conoutf("Could not set gamma (card/driver doesn't support it?)"); + + conoutf("sdl: %s", (int)SDL_GetError()); + + }; + +}); + + + +void transplayer() + +{ + + glLoadIdentity(); + + + + if(player1->state==CS_DEAD) + + { + + float t = (lastmillis-player1->lastaction)/1000.0f; + + if(t >= 1.6f) t = 1.6f; + + + + player1->pitch = (float) sin(t)*(-70.0f-player1->oldpitch)+player1->oldpitch; + + glRotated(player1->pitch,-1.0,0.0,0.0); + + glRotated(player1->yaw,0.0,1.0,0.0); + + + + glTranslated(-player1->o.x, player1->eyeheight-sin(t)*7.0f-player1->o.z, -player1->o.y); + + } + + else + + { + + glRotated(player1->roll,0.0,0.0,1.0); + + glRotated(player1->pitch,-1.0,0.0,0.0); + + glRotated(player1->yaw,0.0,1.0,0.0); + + + + glTranslated(-player1->o.x, (player1->state==CS_DEAD ? player1->eyeheight-0.2f : 0)-player1->o.z, -player1->o.y); + + }; + +}; + + + +VAR(fov, 10, 105, 120); + + + +int xtraverts; + + + +VAR(fog, 64, 180, 1024); + +VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); + + + +VAR(hudgun,0,1,1); + + + +char *hudgunnames[] = { "knife", "semipistol", "shotgun", "subgun", "sniper", "auto", "grenade" }; + + + +void drawhudmodel(int start, int end, float speed, int base) + +{ + + sprintf_sd(mdl)("hudguns/%s", hudgunnames[player1->gunselect]); + + rendermodel(mdl, start, end, 0, 1.0f, player1->o.x, player1->o.z, player1->o.y, player1->yaw+90, player1->pitch, false, 1.0f, speed, 0, base); + +}; + + + +void drawhudgun(int w, int h, float aspect, int farplane) + +{ + + if(!hudgun || player1->state==CS_DEAD) return; + + + + glEnable(GL_CULL_FACE); + + + + glMatrixMode(GL_PROJECTION); + + glLoadIdentity(); + + gluPerspective((float)100.0f*h/w, aspect, 0.3f, farplane); // fov fixed at 100° + + glMatrixMode(GL_MODELVIEW); + + + + rendermd3gun(); + + rendermenumdl(); // lazy bastard + + + + glMatrixMode(GL_PROJECTION); + + glLoadIdentity(); + + gluPerspective((float)fov*h/w, aspect, 0.15f, farplane); + + glMatrixMode(GL_MODELVIEW); + + + + glDisable(GL_CULL_FACE); + +}; + + + +void gl_drawframe(int w, int h, float changelod, float curfps) + +{ + + float hf = hdr.waterlevel-0.3f; + + float fovy = (float)fov*h/w; + + float aspect = w/(float)h; + + bool underwater = player1->o.z>16)/256.0f, ((fogcolour>>8)&255)/256.0f, (fogcolour&255)/256.0f, 1.0f }; + + glFogfv(GL_FOG_COLOR, fogc); + + glClearColor(fogc[0], fogc[1], fogc[2], 1.0f); + + + + if(underwater) + + { + + fovy += (float)sin(lastmillis/1000.0)*2.0f; + + aspect += (float)sin(lastmillis/1000.0+PI)*0.1f; + + glFogi(GL_FOG_START, 0); + + glFogi(GL_FOG_END, (fog+96)/8); + + }; + + + + glClear((player1->outsidemap ? GL_COLOR_BUFFER_BIT : 0) | GL_DEPTH_BUFFER_BIT); + + + + glMatrixMode(GL_PROJECTION); + + glLoadIdentity(); + + int farplane = fog*5/2; + + gluPerspective(fovy, aspect, 0.15f, farplane); + + glMatrixMode(GL_MODELVIEW); + + + + transplayer(); + + + + glEnable(GL_TEXTURE_2D); + + + + int xs, ys; + + skyoglid = lookuptexture(DEFAULT_SKY, xs, ys); + + + + resetcubes(); + + + + curvert = 0; + + strips.setsize(0); + + + + render_world(player1->o.x, player1->o.y, player1->o.z, changelod, + + (int)player1->yaw, (int)player1->pitch, (float)fov, w, h); + + finishstrips(); + + + + setupworld(); + + + + renderstripssky(); + + + + glLoadIdentity(); + + glRotated(player1->pitch, -1.0, 0.0, 0.0); + + glRotated(player1->yaw, 0.0, 1.0, 0.0); + + glRotated(90.0, 1.0, 0.0, 0.0); + + glColor3f(1.0f, 1.0f, 1.0f); + + glDisable(GL_FOG); + + glDepthFunc(GL_GREATER); + + draw_envbox(14, fog*4/3); + + glDepthFunc(GL_LESS); + + glEnable(GL_FOG); + + + + transplayer(); + + + + overbright(2); + + + + renderstrips(); + + + + xtraverts = 0; + + + + renderclients(); + + + + renderentities(); + + + + renderspheres(curtime); + + renderents(); + + + + renderphysents(); + + + + rendershotlines(); + + + + glDisable(GL_CULL_FACE); + + + + drawhudgun(w, h, aspect, farplane); + + + + overbright(1); + + int nquads = renderwater(hf); + + + + overbright(2); + + render_particles(curtime); + + overbright(1); + + + + glDisable(GL_FOG); + + + + glDisable(GL_TEXTURE_2D); + + + + gl_drawhud(w, h, (int)curfps, nquads, curvert, underwater); + + + + glEnable(GL_CULL_FACE); + + glEnable(GL_FOG); + +}; + + + diff --git a/source/src/sound.cpp b/source/src/sound.cpp index 0d29917f..27b1ddc9 100644 --- a/source/src/sound.cpp +++ b/source/src/sound.cpp @@ -1,233 +1,466 @@ -// sound.cpp: uses fmod on windows and sdl_mixer on unix (both had problems on the other platform) - -#include "cube.h" - -//#ifndef WIN32 // NOTE: fmod not being supported for the moment as it does not allow stereo pan/vol updating during playback -#define USE_MIXER -//#endif - -bool nosound = false; - -#define MAXCHAN 32 -#define SOUNDFREQ 22050 - -struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN]; - -#ifdef USE_MIXER - #include "SDL_mixer.h" - #define MAXVOL MIX_MAX_VOLUME - Mix_Music *mod = NULL; - void *stream = NULL; -#else - #include "fmod.h" - #define MAXVOL 255 - FMUSIC_MODULE *mod = NULL; - FSOUND_STREAM *stream = NULL; -#endif - -#ifdef USE_MIXER -VARFP(musicvol, 0, 128, 255, Mix_VolumeMusic((musicvol*MAXVOL)/255)); -#else -VARP(musicvol, 0, 128, 255); -#endif -VARP(soundvol, 0, 255, 255); - -void stopsound() -{ - if(nosound) return; - if(mod) - { - #ifdef USE_MIXER - Mix_HaltMusic(); - Mix_FreeMusic(mod); - #else - FMUSIC_FreeSong(mod); - #endif - mod = NULL; - }; - if(stream) - { - #ifndef USE_MIXER - FSOUND_Stream_Close(stream); - #endif - stream = NULL; - }; -}; - -VAR(soundbufferlen, 128, 1024, 4096); - -void initsound() -{ - memset(soundlocs, 0, sizeof(soundloc)*MAXCHAN); - #ifdef USE_MIXER - if(Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0) - { - conoutf("sound init failed (SDL_mixer): %s", (size_t)Mix_GetError()); - nosound = true; - }; - Mix_AllocateChannels(MAXCHAN); - #else - if(FSOUND_GetVersion()=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); }; - } - else - { - conoutf("could not play music: %s", sn); - }; - #endif - }; -}; - -COMMAND(music, ARG_1STR); - -#ifdef USE_MIXER -vector samples; -#else -vector samples; -#endif - -cvector snames; - -int registersound(char *name) -{ - loopv(snames) if(strcmp(snames[i], name)==0) return i; - snames.add(newstring(name)); - samples.add(NULL); - return samples.length()-1; -}; - -COMMAND(registersound, ARG_1EST); - -void cleansound() -{ - if(nosound) return; - stopsound(); - #ifdef USE_MIXER - Mix_CloseAudio(); - #else - FSOUND_Close(); - #endif -}; - -VAR(stereo, 0, 1, 1); - -void updatechanvol(int chan, vec *loc) -{ - int vol = soundvol, pan = 255/2; - if(loc) - { - vdist(dist, v, *loc, player1->o); - vol -= (int)(dist*3*soundvol/255); // simple mono distance attenuation - if(stereo && (v.x != 0 || v.y != 0)) - { - float yaw = -atan2(v.x, v.y) - player1->yaw*(PI / 180.0f); // relative angle of sound along X-Y axis - pan = int(255.9f*(0.5*sin(yaw)+0.5f)); // range is from 0 (left) to 255 (right) - }; - }; - vol = (vol*MAXVOL)/255; - #ifdef USE_MIXER - Mix_Volume(chan, vol); - Mix_SetPanning(chan, 255-pan, pan); - #else - FSOUND_SetVolume(chan, vol); - FSOUND_SetPan(chan, pan); - #endif -}; - -void newsoundloc(int chan, vec *loc) -{ - assert(chan>=0 && chan5) return; // avoid bursts of sounds with heavy packetloss and in sp - if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; }; - - if(!samples[n]) - { - sprintf_sd(buf)("packages/sounds/%s.wav", snames[n]); - - #ifdef USE_MIXER - samples[n] = Mix_LoadWAV(path(buf)); - #else - samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0); - #endif - - if(!samples[n]) { conoutf("failed to load sample: %s", buf); return; }; - }; - - #ifdef USE_MIXER - int chan = Mix_PlayChannel(-1, samples[n], 0); - #else - int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true); - #endif - if(chan<0) return; - if(loc) newsoundloc(chan, loc); - updatechanvol(chan, loc); - #ifndef USE_MIXER - FSOUND_SetPaused(chan, false); - #endif -}; - -void sound(int n) { playsound(n, NULL); }; -COMMAND(sound, ARG_1INT); +// sound.cpp: uses fmod on windows and sdl_mixer on unix (both had problems on the other platform) + + + +#include "cube.h" + + + +//#ifndef WIN32 // NOTE: fmod not being supported for the moment as it does not allow stereo pan/vol updating during playback + +#define USE_MIXER + +//#endif + + + +bool nosound = false; + + + +#define MAXCHAN 32 + +#define SOUNDFREQ 22050 + + + +struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN]; + + + +#ifdef USE_MIXER + + #include "SDL_mixer.h" + + #define MAXVOL MIX_MAX_VOLUME + + Mix_Music *mod = NULL; + + void *stream = NULL; + +#else + + #include "fmod.h" + + #define MAXVOL 255 + + FMUSIC_MODULE *mod = NULL; + + FSOUND_STREAM *stream = NULL; + +#endif + + + +#ifdef USE_MIXER + +VARFP(musicvol, 0, 128, 255, Mix_VolumeMusic((musicvol*MAXVOL)/255)); + +#else + +VARP(musicvol, 0, 128, 255); + +#endif + +VARP(soundvol, 0, 255, 255); + + + +void stopsound() + +{ + + if(nosound) return; + + if(mod) + + { + + #ifdef USE_MIXER + + Mix_HaltMusic(); + + Mix_FreeMusic(mod); + + #else + + FMUSIC_FreeSong(mod); + + #endif + + mod = NULL; + + }; + + if(stream) + + { + + #ifndef USE_MIXER + + FSOUND_Stream_Close(stream); + + #endif + + stream = NULL; + + }; + +}; + + + +VAR(soundbufferlen, 128, 1024, 4096); + + + +void initsound() + +{ + + memset(soundlocs, 0, sizeof(soundloc)*MAXCHAN); + + #ifdef USE_MIXER + + if(Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0) + + { + + conoutf("sound init failed (SDL_mixer): %s", (size_t)Mix_GetError()); + + nosound = true; + + }; + + Mix_AllocateChannels(MAXCHAN); + + #else + + if(FSOUND_GetVersion()=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); }; + + } + + else + + { + + conoutf("could not play music: %s", sn); + + }; + + #endif + + }; + +}; + + + +COMMAND(music, ARG_1STR); + + + +#ifdef USE_MIXER + +vector samples; + +#else + +vector samples; + +#endif + + + +cvector snames; + + + +int registersound(char *name) + +{ + + loopv(snames) if(strcmp(snames[i], name)==0) return i; + + snames.add(newstring(name)); + + samples.add(NULL); + + return samples.length()-1; + +}; + + + +COMMAND(registersound, ARG_1EST); + + + +void cleansound() + +{ + + if(nosound) return; + + stopsound(); + + #ifdef USE_MIXER + + Mix_CloseAudio(); + + #else + + FSOUND_Close(); + + #endif + +}; + + + +VAR(stereo, 0, 1, 1); + + + +void updatechanvol(int chan, vec *loc) + +{ + + int vol = soundvol, pan = 255/2; + + if(loc) + + { + + vdist(dist, v, *loc, player1->o); + + vol -= (int)(dist*3*soundvol/255); // simple mono distance attenuation + + if(stereo && (v.x != 0 || v.y != 0)) + + { + + float yaw = -atan2(v.x, v.y) - player1->yaw*(PI / 180.0f); // relative angle of sound along X-Y axis + + pan = int(255.9f*(0.5*sin(yaw)+0.5f)); // range is from 0 (left) to 255 (right) + + }; + + }; + + vol = (vol*MAXVOL)/255; + + #ifdef USE_MIXER + + Mix_Volume(chan, vol); + + Mix_SetPanning(chan, 255-pan, pan); + + #else + + FSOUND_SetVolume(chan, vol); + + FSOUND_SetPan(chan, pan); + + #endif + +}; + + + +void newsoundloc(int chan, vec *loc) + +{ + + assert(chan>=0 && chan5) return; // avoid bursts of sounds with heavy packetloss and in sp + + if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; }; + + + + if(!samples[n]) + + { + + sprintf_sd(buf)("packages/sounds/%s.wav", snames[n]); + + + + #ifdef USE_MIXER + + samples[n] = Mix_LoadWAV(path(buf)); + + #else + + samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0); + + #endif + + + + if(!samples[n]) { conoutf("failed to load sample: %s", (int) buf); return; }; + + }; + + + + #ifdef USE_MIXER + + int chan = Mix_PlayChannel(-1, samples[n], 0); + + #else + + int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true); + + #endif + + if(chan<0) return; + + if(loc) newsoundloc(chan, loc); + + updatechanvol(chan, loc); + + #ifndef USE_MIXER + + FSOUND_SetPaused(chan, false); + + #endif + +}; + + + +void sound(int n) { playsound(n, NULL); }; + +COMMAND(sound, ARG_1INT); +