diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..5162f30 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,25 @@ + +----------- + Misc info +----------- + +- I ran Clang-Format on all the original Quake2 source files to fix multiple + formatting issues and replace tabs with spaces, so that it displays nicely + and uniformly on all browsers and editors. The Clang-Format style file used + can be found at the root of the project. I tried to tune it to maintain the + overall style used by id, so the code should look pretty much the same as + before, but with the advantage of uniform indenting and spacing through. + +- Changes made by me in the Quake2 source code are usually annotated by a nearby + comment stating the change made and sometimes the date when it was first + made. These comments will start with my name (e.g.: LAMPERT), followed + by a brief description. + +- Other minor changes such as removing or adding blank lines, adding curly + braces to flow-control statements, adding `static` to local functions or data, + are not always marked with comments to avoid excessive verbosity. + +- The vast majority of the code related to the PS2 port is located inside the + src/ps2/ directory. Changes made in the Quake2 source to account for the + PlayStation2 are clearly marked as such. + diff --git a/Makefile b/Makefile index 1faa662..52a4b52 100644 --- a/Makefile +++ b/Makefile @@ -25,9 +25,9 @@ SRC_FILES = \ ps2/ref_ps2.c \ ps2/tex_image.c \ ps2/math_funcs.c \ + ps2/net_ps2.c \ ps2/main_ps2.c \ null/in_null.c \ - null/net_null.c \ null/cd_null.c \ null/snddma_null.c \ common/cmd.c \ diff --git a/README.md b/README.md index f8d847c..54c90f6 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ is already implemented and working on both the emulator and the PS2, as you can in the above screenshot of the in-game console running on the PS2. The long term goal is to have a fully functional and playable (single-player) -Quake II on the PlayStation 2, relying only on the freely available tools and libraries. +Quake II on the PlayStation 2, using only on the freely available tools and libraries. ## License diff --git a/src/client/cl_main.c b/src/client/cl_main.c index 3bd003f..bd9de4b 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -881,6 +881,7 @@ void CL_Skins_f(void) { if (!cl.configstrings[CS_PLAYERSKINS + i][0]) continue; + Com_Printf("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS + i]); SCR_UpdateScreen(); Sys_SendKeyEvents(); // pump message loop @@ -1787,7 +1788,8 @@ void CL_Frame(int msec) // predict all unacknowledged movements CL_PredictMovement(); - // LAMPERT: We don't use a separate DLL on QPS2, so this is useless. + // LAMPERT: + // We don't use a separate DLL on QPS2, so this is useless. // // allow rendering DLL change //VID_CheckChanges(); @@ -1891,7 +1893,7 @@ void CL_Init(void) =============== CL_Shutdown -FIXME: this is a callback from Sys_Quit and Com_Error. It would be better +FIXME: this is a callback from Sys_Quit and Com_Error. It would be better to run quit through here before the final handoff to the sys code. =============== */ diff --git a/src/client/cl_scrn.c b/src/client/cl_scrn.c index fb69bb9..7d59c87 100644 --- a/src/client/cl_scrn.c +++ b/src/client/cl_scrn.c @@ -561,6 +561,7 @@ void SCR_BeginLoadingPlaque(void) S_StopAllSounds(); cl.sound_prepped = false; // don't play ambients CDAudio_Stop(); + if (cls.disable_screen) return; if (developer->value) @@ -569,10 +570,12 @@ void SCR_BeginLoadingPlaque(void) return; // if at console, don't bring up the plaque if (cls.key_dest == key_console) return; + if (cl.cinematictime > 0) - scr_draw_loading = 2; // clear to balack first + scr_draw_loading = 2; // clear to black first else scr_draw_loading = 1; + SCR_UpdateScreen(); cls.disable_screen = Sys_Milliseconds(); cls.disable_servercount = cl.servercount; @@ -633,7 +636,8 @@ void SCR_TimeRefresh_f(void) start = Sys_Milliseconds(); if (Cmd_Argc() == 2) - { // run without page flipping + { + // run without page flipping re.BeginFrame(0); for (i = 0; i < 128; i++) { @@ -647,7 +651,6 @@ void SCR_TimeRefresh_f(void) for (i = 0; i < 128; i++) { cl.refdef.viewangles[1] = i / 128.0 * 360.0; - re.BeginFrame(0); re.RenderFrame(&cl.refdef); re.EndFrame(); @@ -1319,7 +1322,7 @@ void SCR_UpdateScreen(void) if (scr_draw_loading == 2) { - // loading plaque over black screen + // loading plaque over black screen int w, h; re.CinematicSetPalette(NULL); scr_draw_loading = false; diff --git a/src/client/cl_view.c b/src/client/cl_view.c index e886bd5..ba5448a 100644 --- a/src/client/cl_view.c +++ b/src/client/cl_view.c @@ -332,6 +332,7 @@ void CL_PrepRefresh(void) { if (!cl.configstrings[CS_PLAYERSKINS + i][0]) continue; + Com_Printf("client %i\r", i); SCR_UpdateScreen(); Sys_SendKeyEvents(); // pump message loop @@ -347,6 +348,7 @@ void CL_PrepRefresh(void) rotate = atof(cl.configstrings[CS_SKYROTATE]); sscanf(cl.configstrings[CS_SKYAXIS], "%f %f %f", &axis[0], &axis[1], &axis[2]); + re.SetSky(cl.configstrings[CS_SKY], rotate, axis); Com_Printf(" \r"); @@ -447,7 +449,6 @@ void SCR_DrawCrosshair(void) /* ================== V_RenderView - ================== */ void V_RenderView(float stereo_separation) diff --git a/src/client/client.h b/src/client/client.h index c5b9ab6..c480dab 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -178,8 +178,8 @@ extern client_state_t cl; /* ================================================================== -the client_static_t structure is persistant through an arbitrary number -of server connections +The client_static_t structure is persistent through +an arbitrary number of server connections. ================================================================== */ @@ -213,6 +213,9 @@ typedef enum typedef struct { connstate_t state; + + // This flag determines what's rendered to the screen, + // e.g.: console, main menu, game view... keydest_t key_dest; int framecount; diff --git a/src/client/console.c b/src/client/console.c index b168b7f..67afb17 100644 --- a/src/client/console.c +++ b/src/client/console.c @@ -95,7 +95,9 @@ void Con_ToggleConsole_f(void) cls.key_dest = key_console; if (Cvar_VariableValue("maxclients") == 1 && Com_ServerState()) + { Cvar_Set("paused", "1"); + } } } @@ -117,7 +119,9 @@ void Con_ToggleChat_f(void) } } else + { cls.key_dest = key_console; + } Con_ClearNotify(); } diff --git a/src/client/keys.c b/src/client/keys.c index f20900e..cdb45ee 100644 --- a/src/client/keys.c +++ b/src/client/keys.c @@ -252,15 +252,16 @@ void Key_Console(int key) { char * cbd; - if ((cbd = Sys_GetClipboardData()) != 0) + if ((cbd = Sys_GetClipboardData()) != NULL) { int i; - strtok(cbd, "\n\r\b"); i = strlen(cbd); if (i + key_linepos >= MAXCMDLINE) + { i = MAXCMDLINE - key_linepos; + } if (i > 0) { @@ -268,7 +269,8 @@ void Key_Console(int key) strcat(key_lines[edit_line], cbd); key_linepos += i; } - free(cbd); + + Z_Free(cbd); } return; diff --git a/src/client/menu.c b/src/client/menu.c index 15fca66..c1ad585 100644 --- a/src/client/menu.c +++ b/src/client/menu.c @@ -21,18 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #ifdef _WIN32 -#include -#endif +#include // For filelength() +#endif // _WIN32 #include "client.h" -#include "../client/qmenu.h" - -#define NUM_CURSOR_FRAMES 15 -static int m_main_cursor; - -static char * menu_in_sound = "misc/menu1.wav"; -static char * menu_move_sound = "misc/menu2.wav"; -static char * menu_out_sound = "misc/menu3.wav"; +#include "client/qmenu.h" void M_Menu_Main_f(void); void M_Menu_Game_f(void); @@ -52,16 +45,21 @@ void M_Menu_Keys_f(void); void M_Menu_Quit_f(void); void M_Menu_Credits(void); -qboolean m_entersound; // play after drawing a frame, so caching - // won't disrupt the sound - -void (*m_drawfunc)(void); -const char * (*m_keyfunc)(int key); - //============================================================================= -/* Support Routines */ +/* Locals */ -#define MAX_MENU_DEPTH 8 +enum +{ + MAX_MENU_DEPTH = 20, + NUM_CURSOR_FRAMES = 15 +}; + +static const char * menu_in_sound = "misc/menu1.wav"; +static const char * menu_move_sound = "misc/menu2.wav"; +static const char * menu_out_sound = "misc/menu3.wav"; + +static void (*m_drawfunc)(void); +static const char * (*m_keyfunc)(int key); typedef struct { @@ -69,8 +67,15 @@ typedef struct const char * (*key)(int k); } menulayer_t; -menulayer_t m_layers[MAX_MENU_DEPTH]; -int m_menudepth; +static menulayer_t m_layers[MAX_MENU_DEPTH]; +static int m_menudepth; +static int m_main_cursor; + +// play after drawing a frame, so caching won't disrupt the sound. +static qboolean m_entersound; + +//============================================================================= +/* Support Routines */ static void M_Banner(char * name) { @@ -104,7 +109,7 @@ void M_PushMenu(void (*draw)(void), const char * (*key)(int k)) { if (m_menudepth >= MAX_MENU_DEPTH) { - Com_Error(ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH"); + Com_Error(ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH exceeded!"); } m_layers[m_menudepth].draw = m_drawfunc; m_layers[m_menudepth].key = m_keyfunc; @@ -134,6 +139,7 @@ void M_PopMenu(void) S_StartLocalSound(menu_out_sound); if (m_menudepth < 1) Com_Error(ERR_FATAL, "M_PopMenu: depth < 1"); + m_menudepth--; m_drawfunc = m_layers[m_menudepth].draw; @@ -380,7 +386,11 @@ MAIN MENU ======================================================================= */ -#define MAIN_ITEMS 5 + +enum +{ + MAIN_ITEMS = 5 +}; void M_Main_Draw(void) { @@ -495,6 +505,7 @@ MULTIPLAYER MENU ======================================================================= */ + static menuframework_s s_multiplayer_menu; static menuaction_s s_join_network_server_action; static menuaction_s s_start_network_server_action; @@ -576,6 +587,7 @@ KEYS MENU ======================================================================= */ + char * bindnames[][2] = { { "+attack", "attack" }, @@ -1006,8 +1018,9 @@ CONTROLS MENU ======================================================================= */ -static cvar_t * win_noalttab; + extern cvar_t * in_joystick; +static cvar_t * win_noalttab; static menuframework_s s_options_menu; static menuaction_s s_options_defaults_action; @@ -1163,6 +1176,16 @@ static void ConsoleFunc(void * unused) static void UpdateSoundQualityFunc(void * unused) { + // + // LAMPERT 2015-10-29 + // + // FIXME: + // Can't for the life of me figure out what's wrong here! + // Somehow this still gets called outside Begin/End frame, + // breaking on the PS2. Commenting it out for now. + // + + /* if (s_options_quality_list.curvalue) { Cvar_SetValue("s_khz", 22); @@ -1182,9 +1205,13 @@ static void UpdateSoundQualityFunc(void * unused) M_Print(16 + 16, 120 - 48 + 24, "please be patient."); // the text box won't show up unless we do a buffer swap - re.EndFrame(); + // + // LAMPERT 2015-10-29: + // FIXME This won't work in the PS2, we need consistent Begin/End frame states! + //re.EndFrame(); CL_Snd_Restart_f(); + */ } void Options_MenuInit(void) @@ -1313,6 +1340,7 @@ void Options_MenuInit(void) s_options_crosshair_box.generic.name = "crosshair"; s_options_crosshair_box.generic.callback = CrosshairFunc; s_options_crosshair_box.itemnames = crosshair_names; + /* s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL; s_options_noalttab_box.generic.x = 0; @@ -1320,7 +1348,8 @@ void Options_MenuInit(void) s_options_noalttab_box.generic.name = "disable alt-tab"; s_options_noalttab_box.generic.callback = NoAltTabFunc; s_options_noalttab_box.itemnames = yesno_names; -*/ + */ + s_options_joystick_box.generic.type = MTYPE_SPINCONTROL; s_options_joystick_box.generic.x = 0; s_options_joystick_box.generic.y = 120; @@ -1404,10 +1433,12 @@ END GAME MENU ============================================================================= */ + static int credits_start_time; static const char ** credits; static char * creditsIndex[256]; static char * creditsBuffer; + static const char * idcredits[] = { "+QUAKE II BY ID SOFTWARE", @@ -2035,10 +2066,12 @@ LOADGAME MENU ============================================================================= */ -#define MAX_SAVEGAMES 15 +enum +{ + MAX_SAVEGAMES = 15 +}; static menuframework_s s_savegame_menu; - static menuframework_s s_loadgame_menu; static menuaction_s s_loadgame_actions[MAX_SAVEGAMES]; @@ -2137,6 +2170,7 @@ SAVEGAME MENU ============================================================================= */ + static menuframework_s s_savegame_menu; static menuaction_s s_savegame_actions[MAX_SAVEGAMES]; @@ -2210,7 +2244,11 @@ JOIN SERVER MENU ============================================================================= */ -#define MAX_LOCAL_SERVERS 8 + +enum +{ + MAX_LOCAL_SERVERS = 8 +}; static menuframework_s s_joinserver_menu; static menuseparator_s s_joinserver_server_title; @@ -2275,6 +2313,16 @@ void NullCursorDraw(void * self) void SearchLocalGames(void) { + // + // LAMPERT 2015-10-29 + // + // FIXME: + // Can't for the life of me figure out what's wrong here! + // Somehow this still gets called outside Begin/End frame, + // breaking on the PS2. Commenting it out for now. + // + + /* int i; m_num_servers = 0; @@ -2287,10 +2335,14 @@ void SearchLocalGames(void) M_Print(16 + 16, 120 - 48 + 24, "please be patient."); // the text box won't show up unless we do a buffer swap - re.EndFrame(); + // + // LAMPERT 2015-10-29: + // FIXME This won't work in the PS2, we need consistent Begin/End frame states! + //re.EndFrame(); // send out info packets CL_PingServers_f(); + */ } void SearchLocalGamesFunc(void * self) @@ -2373,6 +2425,7 @@ START SERVER MENU ============================================================================= */ + static menuframework_s s_startserver_menu; static char ** mapnames; static int nummaps; @@ -2390,6 +2443,7 @@ void DMOptionsFunc(void * self) { if (s_rules_box.curvalue == 1) return; + M_Menu_DMOptions_f(); } @@ -2424,7 +2478,7 @@ void RulesChangeFunc(void * self) s_maxclients_field.generic.statusbar = NULL; s_startserver_dmoptions_action.generic.statusbar = NULL; } -*/ + */ } //PGM //===== @@ -2509,6 +2563,7 @@ void StartServer_MenuInit(void) "cooperative", 0 }; + //======= //PGM static const char * dm_coop_names_rogue[] = @@ -2521,6 +2576,7 @@ void StartServer_MenuInit(void) }; //PGM //======= + char * buffer; char mapsname[1024]; char * s; @@ -2535,18 +2591,21 @@ void StartServer_MenuInit(void) if ((fp = fopen(mapsname, "rb")) == 0) { if ((length = FS_LoadFile("maps.lst", (void **)&buffer)) == -1) - Com_Error(ERR_DROP, "couldn't find maps.lst\n"); + { + Com_Error(ERR_DROP, "Couldn't find maps.lst\n"); + } } else { -#ifdef _WIN32 + #ifdef _WIN32 length = filelength(fileno(fp)); -#else + #else fseek(fp, 0, SEEK_END); length = ftell(fp); fseek(fp, 0, SEEK_SET); -#endif - buffer = malloc(length); + #endif + + buffer = Z_Malloc(length); fread(buffer, length, 1, fp); } @@ -2561,9 +2620,11 @@ void StartServer_MenuInit(void) } if (nummaps == 0) + { Com_Error(ERR_DROP, "no maps in maps.lst\n"); + } - mapnames = malloc(sizeof(char *) * (nummaps + 1)); + mapnames = Z_Malloc(sizeof(char *) * (nummaps + 1)); memset(mapnames, 0, sizeof(char *) * (nummaps + 1)); s = buffer; @@ -2582,7 +2643,7 @@ void StartServer_MenuInit(void) strcpy(longname, COM_Parse(&s)); Com_sprintf(scratch, sizeof(scratch), "%s\n%s", longname, shortname); - mapnames[i] = malloc(strlen(scratch) + 1); + mapnames[i] = Z_Malloc(strlen(scratch) + 1); strcpy(mapnames[i], scratch); } mapnames[nummaps] = 0; @@ -2590,7 +2651,7 @@ void StartServer_MenuInit(void) if (fp != 0) { fp = 0; - free(buffer); + Z_Free(buffer); } else { @@ -2669,6 +2730,7 @@ void StartServer_MenuInit(void) s_maxclients_field.generic.statusbar = NULL; s_maxclients_field.length = 3; s_maxclients_field.visible_length = 3; + if (Cvar_VariableValue("maxclients") == 1) strcpy(s_maxclients_field.buffer, "8"); else @@ -2728,8 +2790,11 @@ const char * StartServer_MenuKey(int key) int i; for (i = 0; i < nummaps; i++) - free(mapnames[i]); - free(mapnames); + { + Z_Free(mapnames[i]); + } + + Z_Free(mapnames); } mapnames = 0; nummaps = 0; @@ -2751,8 +2816,8 @@ DMOPTIONS BOOK MENU ============================================================================= */ -static char dmoptions_statusbar[128]; +static char dmoptions_statusbar[128]; static menuframework_s s_dmoptions_menu; static menulist_s s_friendlyfire_box; @@ -3152,6 +3217,7 @@ DOWNLOADOPTIONS BOOK MENU ============================================================================= */ + static menuframework_s s_downloadoptions_menu; static menuseparator_s s_download_title; @@ -3283,7 +3349,11 @@ ADDRESS BOOK MENU ============================================================================= */ -#define NUM_ADDRESSBOOK_ENTRIES 9 + +enum +{ + NUM_ADDRESSBOOK_ENTRIES = 9 +}; static menuframework_s s_addressbook_menu; static menufield_s s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES]; @@ -3356,6 +3426,7 @@ PLAYER CONFIG MENU ============================================================================= */ + static menuframework_s s_player_config_menu; static menufield_s s_player_name_field; static menulist_s s_player_model_box; @@ -3368,8 +3439,11 @@ static menuseparator_s s_player_hand_title; static menuseparator_s s_player_rate_title; static menuaction_s s_player_download_action; -#define MAX_DISPLAYNAME 16 -#define MAX_PLAYERMODELS 1024 +enum +{ + MAX_DISPLAYNAME = 16, + MAX_PLAYERMODELS = 1024 +}; typedef struct { @@ -3417,11 +3491,11 @@ static void FreeFileList(char ** list, int n) { if (list[i]) { - free(list[i]); + Z_Free(list[i]); list[i] = 0; } } - free(list); + Z_Free(list); } static qboolean IconOfSkinExists(char * skin, char ** pcxfiles, int npcxfiles) @@ -3494,7 +3568,7 @@ static qboolean PlayerConfig_ScanDirectories(void) strcat(scratch, "/tris.md2"); if (!Sys_FindFirst(scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM)) { - free(dirnames[i]); + Z_Free(dirnames[i]); dirnames[i] = 0; Sys_FindClose(); continue; @@ -3508,7 +3582,7 @@ static qboolean PlayerConfig_ScanDirectories(void) if (!pcxnames) { - free(dirnames[i]); + Z_Free(dirnames[i]); dirnames[i] = 0; continue; } @@ -3527,7 +3601,7 @@ static qboolean PlayerConfig_ScanDirectories(void) if (!nskins) continue; - skinnames = malloc(sizeof(char *) * (nskins + 1)); + skinnames = Z_Malloc(sizeof(char *) * (nskins + 1)); memset(skinnames, 0, sizeof(char *) * (nskins + 1)); // copy the valid skins @@ -3552,7 +3626,7 @@ static qboolean PlayerConfig_ScanDirectories(void) if (strrchr(scratch, '.')) *strrchr(scratch, '.') = 0; - skinnames[s] = strdup(scratch); + skinnames[s] = Q_CopyString(scratch); s++; } } @@ -3849,10 +3923,14 @@ const char * PlayerConfig_MenuKey(int key) for (j = 0; j < s_pmi[i].nskins; j++) { if (s_pmi[i].skindisplaynames[j]) - free(s_pmi[i].skindisplaynames[j]); + { + Z_Free(s_pmi[i].skindisplaynames[j]); + } + s_pmi[i].skindisplaynames[j] = 0; } - free(s_pmi[i].skindisplaynames); + + Z_Free(s_pmi[i].skindisplaynames); s_pmi[i].skindisplaynames = 0; s_pmi[i].nskins = 0; } @@ -3878,15 +3956,16 @@ GALLERY MENU ======================================================================= */ -#if 0 -void M_Menu_Gallery_f( void ) -{ - extern void Gallery_MenuDraw( void ); - extern const char *Gallery_MenuKey( int key ); - M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey ); +#if 0 +void M_Menu_Gallery_f(void) +{ + extern void Gallery_MenuDraw(void); + extern const char * Gallery_MenuKey(int key); + + M_PushMenu(Gallery_MenuDraw, Gallery_MenuKey); } -#endif +#endif // 0 /* ======================================================================= @@ -4005,12 +4084,11 @@ M_Keydown void M_Keydown(int key) { const char * s; - if (m_keyfunc) { if ((s = m_keyfunc(key)) != 0) { - S_StartLocalSound((char *)s); + S_StartLocalSound(s); } } } diff --git a/src/client/qmenu.c b/src/client/qmenu.c index 8b438e6..045349d 100644 --- a/src/client/qmenu.c +++ b/src/client/qmenu.c @@ -24,28 +24,35 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "client.h" #include "qmenu.h" -void Action_DoEnter(menuaction_s * a); -void Action_Draw(menuaction_s * a); -void Menu_DrawStatusBar(const char * string); -void Menulist_DoEnter(menulist_s * l); -void MenuList_Draw(menulist_s * l); -void Separator_Draw(menuseparator_s * s); -void Slider_DoSlide(menuslider_s * s, int dir); -void Slider_Draw(menuslider_s * s); -void SpinControl_DoEnter(menulist_s * s); -void SpinControl_Draw(menulist_s * s); -void SpinControl_DoSlide(menulist_s * s, int dir); +static void Action_DoEnter(menuaction_s * a); +static void Action_Draw(menuaction_s * a); +static void Menu_DrawStatusBar(const char * string); +static void Menulist_DoEnter(menulist_s * l); +static void MenuList_Draw(menulist_s * l); +static void Separator_Draw(menuseparator_s * s); +static void Slider_DoSlide(menuslider_s * s, int dir); +static void Slider_Draw(menuslider_s * s); +static void SpinControl_DoEnter(menulist_s * s); +static void SpinControl_Draw(menulist_s * s); +static void SpinControl_DoSlide(menulist_s * s, int dir); extern refexport_t re; extern viddef_t viddef; -#define RCOLUMN_OFFSET 16 -#define LCOLUMN_OFFSET -16 +enum +{ + RCOLUMN_OFFSET = 16, + LCOLUMN_OFFSET = -16 +}; + +//============================================================================= void Action_DoEnter(menuaction_s * a) { if (a->generic.callback) + { a->generic.callback(a); + } } void Action_Draw(menuaction_s * a) @@ -187,8 +194,8 @@ qboolean Field_Key(menufield_s * f, int key) } /* - ** support pasting from the clipboard - */ + ** support pasting from the clipboard + */ if ((toupper(key) == 'V' && keydown[K_CTRL]) || (((key == K_INS) || (key == K_KP_INS)) && keydown[K_SHIFT])) { @@ -201,10 +208,13 @@ qboolean Field_Key(menufield_s * f, int key) strncpy(f->buffer, cbd, f->length - 1); f->cursor = strlen(f->buffer); f->visible_offset = f->cursor - f->visible_length; - if (f->visible_offset < 0) - f->visible_offset = 0; - free(cbd); + if (f->visible_offset < 0) + { + f->visible_offset = 0; + } + + Z_Free(cbd); } return true; } @@ -284,8 +294,8 @@ void Menu_AdjustCursor(menuframework_s * m, int dir) menucommon_s * citem; /* - ** see if it's in a valid spot - */ + ** see if it's in a valid spot + */ if (m->cursor >= 0 && m->cursor < m->nitems) { if ((citem = Menu_ItemAtCursor(m)) != 0) @@ -296,9 +306,9 @@ void Menu_AdjustCursor(menuframework_s * m, int dir) } /* - ** it's not in a valid spot, so crawl in the direction indicated until we - ** find a valid spot - */ + ** it's not in a valid spot, so crawl in the direction indicated until we + ** find a valid spot + */ if (dir == 1) { while (1) @@ -343,8 +353,8 @@ void Menu_Draw(menuframework_s * menu) menucommon_s * item; /* - ** draw contents - */ + ** draw contents + */ for (i = 0; i < menu->nitems; i++) { switch (((menucommon_s *)menu->items[i])->type) @@ -487,10 +497,10 @@ qboolean Menu_SelectItem(menuframework_s * s) Action_DoEnter((menuaction_s *)item); return true; case MTYPE_LIST: - // Menulist_DoEnter( ( menulist_s * ) item ); + // Menulist_DoEnter( ( menulist_s * ) item ); return false; case MTYPE_SPINCONTROL: - // SpinControl_DoEnter( ( menulist_s * ) item ); + // SpinControl_DoEnter( ( menulist_s * ) item ); return false; } } @@ -596,7 +606,10 @@ void Slider_DoSlide(menuslider_s * s, int dir) s->generic.callback(s); } -#define SLIDER_RANGE 10 +enum +{ + SLIDER_RANGE = 10 +}; void Slider_Draw(menuslider_s * s) { @@ -612,9 +625,12 @@ void Slider_Draw(menuslider_s * s) s->range = 0; if (s->range > 1) s->range = 1; + re.DrawChar(s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET, s->generic.y + s->generic.parent->y, 128); + for (i = 0; i < SLIDER_RANGE; i++) re.DrawChar(RCOLUMN_OFFSET + s->generic.x + i * 8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 129); + re.DrawChar(RCOLUMN_OFFSET + s->generic.x + i * 8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 130); re.DrawChar((int)(8 + RCOLUMN_OFFSET + s->generic.parent->x + s->generic.x + (SLIDER_RANGE - 1) * 8 * s->range), s->generic.y + s->generic.parent->y, 131); } diff --git a/src/client/qmenu.h b/src/client/qmenu.h index 7deb200..939ce4d 100644 --- a/src/client/qmenu.h +++ b/src/client/qmenu.h @@ -23,31 +23,31 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAXMENUITEMS 64 -#define MTYPE_SLIDER 0 -#define MTYPE_LIST 1 -#define MTYPE_ACTION 2 +#define MTYPE_SLIDER 0 +#define MTYPE_LIST 1 +#define MTYPE_ACTION 2 #define MTYPE_SPINCONTROL 3 -#define MTYPE_SEPARATOR 4 -#define MTYPE_FIELD 5 +#define MTYPE_SEPARATOR 4 +#define MTYPE_FIELD 5 -#define K_TAB 9 -#define K_ENTER 13 +#define K_TAB 9 +#define K_ENTER 13 #define K_ESCAPE 27 -#define K_SPACE 32 +#define K_SPACE 32 // normal keys should be passed as lowercased ascii -#define K_BACKSPACE 127 -#define K_UPARROW 128 -#define K_DOWNARROW 129 -#define K_LEFTARROW 130 +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 #define K_RIGHTARROW 131 #define QMF_LEFT_JUSTIFY 0x00000001 -#define QMF_GRAYED 0x00000002 -#define QMF_NUMBERSONLY 0x00000004 +#define QMF_GRAYED 0x00000002 +#define QMF_NUMBERSONLY 0x00000004 -typedef struct _tag_menuframework +typedef struct menuframework_struct { int x, y; int cursor; @@ -58,7 +58,7 @@ typedef struct _tag_menuframework const char * statusbar; - void (*cursordraw)(struct _tag_menuframework * m); + void (*cursordraw)(struct menuframework_struct * m); } menuframework_s; @@ -83,7 +83,6 @@ typedef struct typedef struct { menucommon_s generic; - char buffer[80]; int cursor; int length; @@ -94,20 +93,16 @@ typedef struct typedef struct { menucommon_s generic; - float minvalue; float maxvalue; float curvalue; - float range; } menuslider_s; typedef struct { menucommon_s generic; - int curvalue; - const char ** itemnames; } menulist_s; diff --git a/src/client/snd_dma.c b/src/client/snd_dma.c index f93ab01..97c2725 100644 --- a/src/client/snd_dma.c +++ b/src/client/snd_dma.c @@ -192,10 +192,9 @@ void S_Shutdown(void) /* ================== S_FindName - ================== */ -sfx_t * S_FindName(char * name, qboolean create) +sfx_t * S_FindName(const char * name, qboolean create) { int i; sfx_t * sfx; @@ -221,7 +220,7 @@ sfx_t * S_FindName(char * name, qboolean create) // find a free sfx for (i = 0; i < num_sfx; i++) if (!known_sfx[i].name[0]) - // registration_sequence < s_registration_sequence) + // registration_sequence < s_registration_sequence) break; if (i == num_sfx) @@ -293,7 +292,7 @@ S_RegisterSound ================== */ -sfx_t * S_RegisterSound(char * name) +sfx_t * S_RegisterSound(const char * name) { sfx_t * sfx; @@ -716,7 +715,7 @@ void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t * sfx, float S_StartLocalSound ================== */ -void S_StartLocalSound(char * sound) +void S_StartLocalSound(const char * sound) { sfx_t * sfx; diff --git a/src/client/sound.h b/src/client/sound.h index b9a6d17..36e5baa 100644 --- a/src/client/sound.h +++ b/src/client/sound.h @@ -27,8 +27,10 @@ void S_Init(void); void S_Shutdown(void); // if origin is NULL, the sound will be dynamically sourced from the entity -void S_StartSound(vec3_t origin, int entnum, int entchannel, struct sfx_s * sfx, float fvol, float attenuation, float timeofs); -void S_StartLocalSound(char * s); +void S_StartSound(vec3_t origin, int entnum, int entchannel, struct sfx_s * sfx, + float fvol, float attenuation, float timeofs); + +void S_StartLocalSound(const char * s); void S_RawSamples(int samples, int rate, int width, int channels, byte * data); @@ -38,10 +40,10 @@ void S_Update(vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up); void S_Activate(qboolean active); void S_BeginRegistration(void); -struct sfx_s * S_RegisterSound(char * sample); +struct sfx_s * S_RegisterSound(const char * sample); void S_EndRegistration(void); -struct sfx_s * S_FindName(char * name, qboolean create); +struct sfx_s * S_FindName(const char * name, qboolean create); // the sound code makes callbacks to the client for entitiy position // information, so entities can be dynamically re-spatialized diff --git a/src/common/cmd.c b/src/common/cmd.c index 38e0f74..6dc440e 100644 --- a/src/common/cmd.c +++ b/src/common/cmd.c @@ -475,7 +475,7 @@ void Cmd_Alias_f(void) } strcat(cmd, "\n"); - a->value = CopyString(cmd); + a->value = Q_CopyString(cmd); } /* diff --git a/src/common/cmodel.c b/src/common/cmodel.c index 62d73dd..7ec74d1 100644 --- a/src/common/cmodel.c +++ b/src/common/cmodel.c @@ -61,60 +61,67 @@ typedef struct int floodvalid; } carea_t; -int checkcount; - -char map_name[MAX_QPATH]; - -int numbrushsides; -cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES]; +// +// LAMPERT 2015-10-27 +// Made a bunch local data in this file 'static', +// since most global variables in here are never exported. +// +// Referenced by cl_main.c int numtexinfo; mapsurface_t map_surfaces[MAX_MAP_TEXINFO]; -int numplanes; -cplane_t map_planes[MAX_MAP_PLANES + 6]; // extra for box hull +static int checkcount; +static char map_name[MAX_QPATH]; -int numnodes; -cnode_t map_nodes[MAX_MAP_NODES + 6]; // extra for box hull +static int numbrushsides; +static cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES]; -int numleafs = 1; // allow leaf funcs to be called without a map -cleaf_t map_leafs[MAX_MAP_LEAFS]; -int emptyleaf, solidleaf; +static int numplanes; +static cplane_t map_planes[MAX_MAP_PLANES + 6]; // extra for box hull -int numleafbrushes; -unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES]; +static int numnodes; +static cnode_t map_nodes[MAX_MAP_NODES + 6]; // extra for box hull -int numcmodels; -cmodel_t map_cmodels[MAX_MAP_MODELS]; +static int numleafs = 1; // allow leaf funcs to be called without a map +static cleaf_t map_leafs[MAX_MAP_LEAFS]; +static int emptyleaf, solidleaf; -int numbrushes; -cbrush_t map_brushes[MAX_MAP_BRUSHES]; +static int numleafbrushes; +static unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES]; -int numvisibility; -byte map_visibility[MAX_MAP_VISIBILITY]; -dvis_t * map_vis = (dvis_t *)map_visibility; +static int numcmodels; +static cmodel_t map_cmodels[MAX_MAP_MODELS]; -int numentitychars; -char map_entitystring[MAX_MAP_ENTSTRING]; +static int numbrushes; +static cbrush_t map_brushes[MAX_MAP_BRUSHES]; -int numareas = 1; -carea_t map_areas[MAX_MAP_AREAS]; +static int numvisibility; +static byte map_visibility[MAX_MAP_VISIBILITY]; +static dvis_t * map_vis = (dvis_t *)map_visibility; -int numareaportals; -dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS]; +static int numentitychars; +static char map_entitystring[MAX_MAP_ENTSTRING]; -int numclusters = 1; +static int numareas = 1; +static carea_t map_areas[MAX_MAP_AREAS]; -mapsurface_t nullsurface; +static int numareaportals; +static dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS]; -int floodvalid; +static int numclusters = 1; +static int floodvalid; -qboolean portalopen[MAX_MAP_AREAPORTALS]; +static mapsurface_t nullsurface; +static qboolean portalopen[MAX_MAP_AREAPORTALS]; -cvar_t * map_noareas; +static byte * cmod_base; +static cvar_t * map_noareas; +// These counters are referenced by Qcommon_Frame(). int c_pointcontents; -int c_traces, c_brush_traces; +int c_traces; +int c_brush_traces; void CM_InitBoxHull(void); void FloodAreaConnections(void); @@ -122,13 +129,11 @@ void FloodAreaConnections(void); /* =============================================================================== - MAP LOADING + MAP LOADING =============================================================================== */ -byte * cmod_base; - /* ================= CMod_LoadSubmodels @@ -143,10 +148,12 @@ void CMod_LoadSubmodels(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count < 1) Com_Error(ERR_DROP, "Map with no models"); + if (count > MAX_MAP_MODELS) Com_Error(ERR_DROP, "Map has too many models"); @@ -180,9 +187,11 @@ void CMod_LoadSurfaces(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count < 1) Com_Error(ERR_DROP, "Map with no surfaces"); + if (count > MAX_MAP_TEXINFO) Com_Error(ERR_DROP, "Map has too many surfaces"); @@ -201,7 +210,6 @@ void CMod_LoadSurfaces(lump_t * l) /* ================= CMod_LoadNodes - ================= */ void CMod_LoadNodes(lump_t * l) @@ -214,10 +222,12 @@ void CMod_LoadNodes(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count < 1) Com_Error(ERR_DROP, "Map has no nodes"); + if (count > MAX_MAP_NODES) Com_Error(ERR_DROP, "Map has too many nodes"); @@ -239,7 +249,6 @@ void CMod_LoadNodes(lump_t * l) /* ================= CMod_LoadBrushes - ================= */ void CMod_LoadBrushes(lump_t * l) @@ -251,6 +260,7 @@ void CMod_LoadBrushes(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count > MAX_MAP_BRUSHES) @@ -283,10 +293,12 @@ void CMod_LoadLeafs(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count < 1) Com_Error(ERR_DROP, "Map with no leafs"); + // need to save space for box planes if (count > MAX_MAP_PLANES) Com_Error(ERR_DROP, "Map has too many planes"); @@ -309,6 +321,7 @@ void CMod_LoadLeafs(lump_t * l) if (map_leafs[0].contents != CONTENTS_SOLID) Com_Error(ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); + solidleaf = 0; emptyleaf = -1; for (i = 1; i < numleafs; i++) @@ -319,6 +332,7 @@ void CMod_LoadLeafs(lump_t * l) break; } } + if (emptyleaf == -1) Com_Error(ERR_DROP, "Map does not have an empty leaf"); } @@ -339,10 +353,12 @@ void CMod_LoadPlanes(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count < 1) Com_Error(ERR_DROP, "Map with no planes"); + // need to save space for box planes if (count > MAX_MAP_PLANES) Com_Error(ERR_DROP, "Map has too many planes"); @@ -381,10 +397,12 @@ void CMod_LoadLeafBrushes(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count < 1) Com_Error(ERR_DROP, "Map with no planes"); + // need to save space for box planes if (count > MAX_MAP_LEAFBRUSHES) Com_Error(ERR_DROP, "Map has too many leafbrushes"); @@ -412,6 +430,7 @@ void CMod_LoadBrushSides(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); // need to save space for box planes @@ -426,8 +445,10 @@ void CMod_LoadBrushSides(lump_t * l) num = LittleShort(in->planenum); out->plane = &map_planes[num]; j = LittleShort(in->texinfo); + if (j >= numtexinfo) Com_Error(ERR_DROP, "Bad brushside texinfo"); + out->surface = &map_surfaces[j]; } } @@ -447,6 +468,7 @@ void CMod_LoadAreas(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count > MAX_MAP_AREAS) @@ -479,6 +501,7 @@ void CMod_LoadAreaPortals(lump_t * l) in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l->filelen / sizeof(*in); if (count > MAX_MAP_AREAS) @@ -593,7 +616,10 @@ cmodel_t * CM_LoadMap(char * name, qboolean clientload, unsigned * checksum) ((int *)&header)[i] = LittleLong(((int *)&header)[i]); if (header.version != BSPVERSION) - Com_Error(ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)", name, header.version, BSPVERSION); + { + Com_Error(ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)", + name, header.version, BSPVERSION); + } cmod_base = (byte *)buf; @@ -634,7 +660,9 @@ cmodel_t * CM_InlineModel(char * name) if (!name || name[0] != '*') Com_Error(ERR_DROP, "CM_InlineModel: bad name"); + num = atoi(name + 1); + if (num < 1 || num >= numcmodels) Com_Error(ERR_DROP, "CM_InlineModel: bad number"); @@ -679,10 +707,10 @@ int CM_LeafArea(int leafnum) //======================================================================= -cplane_t * box_planes; -int box_headnode; -cbrush_t * box_brush; -cleaf_t * box_leaf; +static int box_headnode; +static cplane_t * box_planes; +static cbrush_t * box_brush; +static cleaf_t * box_leaf; /* =================== @@ -779,7 +807,6 @@ int CM_HeadnodeForBox(vec3_t mins, vec3_t maxs) /* ================== CM_PointLeafnum_r - ================== */ int CM_PointLeafnum_r(vec3_t p, int num) @@ -815,18 +842,20 @@ int CM_PointLeafnum(vec3_t p) return CM_PointLeafnum_r(p, 0); } +static int leaf_topnode; +static int leaf_count; +static int leaf_maxcount; +static int * leaf_list; +static float * leaf_mins; +static float * leaf_maxs; + /* ============= -CM_BoxLeafnums +CM_BoxLeafnums_r Fills in a list of all the leafs touched ============= */ -int leaf_count, leaf_maxcount; -int * leaf_list; -float *leaf_mins, *leaf_maxs; -int leaf_topnode; - void CM_BoxLeafnums_r(int nodenum) { cplane_t * plane; @@ -839,7 +868,7 @@ void CM_BoxLeafnums_r(int nodenum) { if (leaf_count >= leaf_maxcount) { - // Com_Printf ("CM_BoxLeafnums_r: overflow\n"); + // Com_Printf ("CM_BoxLeafnums_r: overflow\n"); return; } leaf_list[leaf_count++] = -1 - nodenum; @@ -848,7 +877,7 @@ void CM_BoxLeafnums_r(int nodenum) node = &map_nodes[nodenum]; plane = node->plane; - // s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane); + // s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane); s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane); if (s == 1) nodenum = node->children[0]; @@ -885,13 +914,13 @@ int CM_BoxLeafnums_headnode(vec3_t mins, vec3_t maxs, int * list, int listsize, int CM_BoxLeafnums(vec3_t mins, vec3_t maxs, int * list, int listsize, int * topnode) { return CM_BoxLeafnums_headnode(mins, maxs, list, - listsize, map_cmodels[0].headnode, topnode); + listsize, map_cmodels[0].headnode, + topnode); } /* ================== CM_PointContents - ================== */ int CM_PointContents(vec3_t p, int headnode) @@ -952,13 +981,15 @@ BOX TRACING // 1/32 epsilon to keep floating point happy #define DIST_EPSILON (0.03125) -vec3_t trace_start, trace_end; -vec3_t trace_mins, trace_maxs; -vec3_t trace_extents; +static vec3_t trace_start; +static vec3_t trace_end; +static vec3_t trace_mins; +static vec3_t trace_maxs; +static vec3_t trace_extents; -trace_t trace_trace; -int trace_contents; -qboolean trace_ispoint; // optimized case +static trace_t trace_trace; +static int trace_contents; +static qboolean trace_ispoint; // optimized case /* ================ @@ -1149,10 +1180,12 @@ void CM_TraceToLeaf(int leafnum) b = &map_brushes[brushnum]; if (b->checkcount == checkcount) continue; // already checked this brush in another leaf + b->checkcount = checkcount; if (!(b->contents & trace_contents)) continue; + CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b); if (!trace_trace.fraction) return; @@ -1181,10 +1214,12 @@ void CM_TestInLeaf(int leafnum) b = &map_brushes[brushnum]; if (b->checkcount == checkcount) continue; // already checked this brush in another leaf + b->checkcount = checkcount; if (!(b->contents & trace_contents)) continue; + CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, &trace_trace, b); if (!trace_trace.fraction) return; @@ -1194,7 +1229,6 @@ void CM_TestInLeaf(int leafnum) /* ================== CM_RecursiveHullCheck - ================== */ void CM_RecursiveHullCheck(int num, float p1f, float p2f, vec3_t p1, vec3_t p2) @@ -1323,8 +1357,7 @@ trace_t CM_BoxTrace(vec3_t start, vec3_t end, int i; checkcount++; // for multi-check avoidance - - c_traces++; // for statistics, may be zeroed + c_traces++; // for statistics, may be zeroed // fill in a default trace memset(&trace_trace, 0, sizeof(trace_trace)); @@ -1482,12 +1515,7 @@ PVS / PHS =============================================================================== */ -/* -=================== -CM_DecompressVis -=================== -*/ -void CM_DecompressVis(byte * in, byte * out) +static void CM_DecompressVis(byte * in, byte * out) { int c; byte * out_p; @@ -1529,8 +1557,8 @@ void CM_DecompressVis(byte * in, byte * out) } while (out_p - out < row); } -byte pvsrow[MAX_MAP_LEAFS / 8]; -byte phsrow[MAX_MAP_LEAFS / 8]; +static byte pvsrow[MAX_MAP_LEAFS / 8]; +static byte phsrow[MAX_MAP_LEAFS / 8]; byte * CM_ClusterPVS(int cluster) { @@ -1583,8 +1611,6 @@ void FloodArea_r(carea_t * area, int floodnum) /* ==================== FloodAreaConnections - - ==================== */ void FloodAreaConnections(void) diff --git a/src/common/common.c b/src/common/common.c index ca99cf9..0f64f1b 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -1031,7 +1031,7 @@ int memsearch(const byte * start, int count, int search) return -1; } -char * CopyString(const char * in) +char * Q_CopyString(const char * in) { char * out; out = Z_Malloc(strlen(in) + 1); @@ -1087,11 +1087,16 @@ void Info_Print(char * s) ZONE MEMORY ALLOCATION -just cleared malloc with counters now... - ============================================================================== */ +// +// LAMPERT 2015-10-28 +// Replaced malloc/free with the PS2 memory allocation wrappers to keep +// count of all memory allocations, plus a few other minor changes. +// +#include "ps2/mem_alloc.h" + enum { Z_MAGIC = 0x1D1D @@ -1099,14 +1104,16 @@ enum typedef struct zhead_s { - struct zhead_s *prev, *next; + struct zhead_s * prev; + struct zhead_s * next; short magic; short tag; // for group free int size; } zhead_t; -zhead_t z_chain; -int z_count, z_bytes; +static zhead_t z_chain; +static int z_count; +static int z_bytes; /* ======================== @@ -1115,8 +1122,7 @@ Z_Free */ void Z_Free(void * ptr) { - zhead_t * z; - z = ((zhead_t *)ptr) - 1; + zhead_t * z = ((zhead_t *)ptr) - 1; if (z->magic != Z_MAGIC) { @@ -1128,17 +1134,8 @@ void Z_Free(void * ptr) z_count--; z_bytes -= z->size; - free(z); -} -/* -======================== -Z_Stats_f -======================== -*/ -void Z_Stats_f(void) -{ - Com_Printf("%i bytes in %i blocks\n", z_bytes, z_count); + PS2_MemFree(z, z->size, MEMTAG_QUAKE); } /* @@ -1148,7 +1145,8 @@ Z_FreeTags */ void Z_FreeTags(int tag) { - zhead_t *z, *next; + zhead_t * z; + zhead_t * next; for (z = z_chain.next; z != &z_chain; z = next) { next = z->next; @@ -1169,9 +1167,9 @@ void * Z_TagMalloc(int size, int tag) zhead_t * z; size = size + sizeof(zhead_t); - z = malloc(size); + z = PS2_MemAlloc(size, MEMTAG_QUAKE); - if (!z) + if (z == NULL) { Sys_Error("Z_Malloc: Failed on allocation of %i bytes!", size); } @@ -1180,8 +1178,8 @@ void * Z_TagMalloc(int size, int tag) z_count++; z_bytes += size; z->magic = Z_MAGIC; - z->tag = tag; - z->size = size; + z->tag = tag; + z->size = size; z->next = z_chain.next; z->prev = &z_chain; @@ -1201,6 +1199,16 @@ void * Z_Malloc(int size) return Z_TagMalloc(size, 0); } +/* +======================== +Z_Stats_f +======================== +*/ +void Z_Stats_f(void) +{ + Com_Printf("%i bytes in %i blocks\n", z_bytes, z_count); +} + //============================================================================ /* diff --git a/src/common/cvar.c b/src/common/cvar.c index 277d782..773eff5 100644 --- a/src/common/cvar.c +++ b/src/common/cvar.c @@ -174,8 +174,8 @@ cvar_t * Cvar_Get(const char * var_name, const char * var_value, int flags) } var = Z_Malloc(sizeof(*var)); - var->name = CopyString(var_name); - var->string = CopyString(var_value); + var->name = Q_CopyString(var_name); + var->string = Q_CopyString(var_value); var->modified = true; var->value = atof(var->string); @@ -240,11 +240,11 @@ cvar_t * Cvar_Set2(const char * var_name, const char * value, qboolean force) if (Com_ServerState()) { Com_Printf("%s will be changed for next game.\n", var_name); - var->latched_string = CopyString(value); + var->latched_string = Q_CopyString(value); } else { - var->string = CopyString(value); + var->string = Q_CopyString(value); var->value = atof(var->string); if (!strcmp(var->name, "game")) { @@ -278,7 +278,7 @@ cvar_t * Cvar_Set2(const char * var_name, const char * value, qboolean force) Z_Free(var->string); // free the old value string - var->string = CopyString(value); + var->string = Q_CopyString(value); var->value = atof(var->string); return var; @@ -329,7 +329,7 @@ cvar_t * Cvar_FullSet(const char * var_name, const char * value, int flags) Z_Free(var->string); // free the old value string - var->string = CopyString(value); + var->string = Q_CopyString(value); var->value = atof(var->string); var->flags = flags; diff --git a/src/common/filesys.c b/src/common/filesys.c index 5e01f04..0be863e 100644 --- a/src/common/filesys.c +++ b/src/common/filesys.c @@ -72,17 +72,24 @@ typedef struct searchpath_s struct searchpath_s * next; } searchpath_t; -char fs_gamedir[MAX_OSPATH]; -cvar_t * fs_basedir; -cvar_t * fs_cddir; -cvar_t * fs_gamedirvar; +// LAMPERT 2015-10-27 +// Marked these locals as 'static' + +static char fs_gamedir[MAX_OSPATH]; +static cvar_t * fs_basedir; +static cvar_t * fs_cddir; static filelink_t * fs_links; static searchpath_t * fs_searchpaths; -static searchpath_t * fs_base_searchpaths; // without gamedirs -static char fs_default_base_path[MAX_OSPATH] = "."; +static searchpath_t * fs_base_searchpaths; // Without gamedirs +static char fs_default_base_path[MAX_OSPATH] = "."; // Added for QPS2 + +// Externally referenced: +int file_from_pak = 0; +cvar_t * fs_gamedirvar = NULL; + +/* =========================================================================== -/* All of Quake's data access is through a hierarchical file system, but the contents of the file system can be transparently merged from several sources. @@ -96,7 +103,8 @@ files (savegames, screenshots, demos, config files) will be saved to. This can b with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precaution against having a malicious server instruct clients to write files over areas they shouldn't. -*/ + +============================================================================== */ /* ================ @@ -187,8 +195,6 @@ int Developer_searchpath(int who) return 0; } -int file_from_pak = 0; - /* =========== FS_FOpenFile @@ -714,7 +720,7 @@ void FS_Link_f(void) Z_Free(l); return; } - l->to = CopyString(Cmd_Argv(2)); + l->to = Q_CopyString(Cmd_Argv(2)); return; } prev = &l->next; @@ -724,9 +730,9 @@ void FS_Link_f(void) l = Z_Malloc(sizeof(*l)); l->next = fs_links; fs_links = l; - l->from = CopyString(Cmd_Argv(1)); + l->from = Q_CopyString(Cmd_Argv(1)); l->fromlength = strlen(l->from); - l->to = CopyString(Cmd_Argv(2)); + l->to = Q_CopyString(Cmd_Argv(2)); } /* @@ -757,7 +763,7 @@ char ** FS_ListFiles(char * findname, int * numfiles, unsigned musthave, unsigne nfiles++; // add space for a guard *numfiles = nfiles; - list = malloc(sizeof(char *) * nfiles); + list = Z_Malloc(sizeof(char *) * nfiles); memset(list, 0, sizeof(char *) * nfiles); s = Sys_FindFirst(findname, musthave, canthave); @@ -766,7 +772,7 @@ char ** FS_ListFiles(char * findname, int * numfiles, unsigned musthave, unsigne { if (s[strlen(s) - 1] != '.') { - list[nfiles] = strdup(s); + list[nfiles] = Q_CopyString(s); #ifdef _WIN32 strlwr(list[nfiles]); #endif // _WIN32 @@ -825,9 +831,9 @@ void FS_Dir_f(void) { Com_Printf("%s\n", dirnames[i]); } - free(dirnames[i]); + Z_Free(dirnames[i]); } - free(dirnames); + Z_Free(dirnames); } Com_Printf("\n"); } @@ -836,7 +842,6 @@ void FS_Dir_f(void) /* ============ FS_Path_f - ============ */ void FS_Path_f(void) @@ -907,6 +912,7 @@ char * FS_NextPath(char * prevpath) ================ FS_SetDefaultBasePath +LAMPERT: Added for QPS2 so we can change the game path prior to FS init and look for files in the USB drive or CDFS. ================ @@ -930,7 +936,7 @@ void FS_InitFilesystem(void) Cmd_AddCommand("path", FS_Path_f); Cmd_AddCommand("link", FS_Link_f); - Cmd_AddCommand("dir", FS_Dir_f); + Cmd_AddCommand("dir", FS_Dir_f); // // basedir diff --git a/src/common/net_chan.c b/src/common/net_chan.c index 97139ae..4974dc9 100644 --- a/src/common/net_chan.c +++ b/src/common/net_chan.c @@ -74,18 +74,17 @@ then a packet only needs to be delivered if there is something in the unacknowledged reliable */ -cvar_t * showpackets; -cvar_t * showdrop; -cvar_t * qport; +static cvar_t * showpackets; +static cvar_t * showdrop; +static cvar_t * qport; -netadr_t net_from; -sizebuf_t net_message; -byte net_message_buffer[MAX_MSGLEN]; +netadr_t net_from = {0}; +sizebuf_t net_message = {0}; +byte net_message_buffer[MAX_MSGLEN] = {0}; /* =============== Netchan_Init - =============== */ void Netchan_Init(void) diff --git a/src/common/pmove.c b/src/common/pmove.c index 626ac88..a1803bb 100644 --- a/src/common/pmove.c +++ b/src/common/pmove.c @@ -45,8 +45,10 @@ typedef struct qboolean ladder; } pml_t; -pmove_t * pm; -pml_t pml; +// LAMPERT 2015-10-27 +// Marked these locals as 'static' +static pmove_t * pm; +static pml_t pml; // movement parameters float pm_stopspeed = 100; diff --git a/src/common/q_common.h b/src/common/q_common.h index f07c664..b942ce4 100644 --- a/src/common/q_common.h +++ b/src/common/q_common.h @@ -69,6 +69,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #elif defined PS2_QUAKE // LAMPERT: 2015-10-26 +// So the console prints a proper version string, instead of "NON-WIN32" #define BUILDSTRING "PS2-QUAKE" #define CPUSTRING "EE-MIPS-R5900-LE" @@ -158,7 +159,7 @@ void COM_AddParm(char * parm); void COM_Init(void); void COM_InitArgv(int argc, char ** argv); -char * CopyString(const char * in); +char * Q_CopyString(const char * in); // strdup replaces that used Z_Malloc. //============================================================================ @@ -512,7 +513,7 @@ extern qboolean userinfo_modified; /* ============================================================== -NET +NET layer ============================================================== */ @@ -544,26 +545,25 @@ typedef enum typedef struct { netadrtype_t type; - byte ip[4]; byte ipx[10]; - unsigned short port; } netadr_t; void NET_Init(void); void NET_Shutdown(void); void NET_Config(qboolean multiplayer); +void NET_Sleep(int msec); qboolean NET_GetPacket(netsrc_t sock, netadr_t * net_from, sizebuf_t * net_message); -void NET_SendPacket(netsrc_t sock, int length, void * data, netadr_t to); +void NET_SendPacket(netsrc_t sock, int length, const void * data, netadr_t to); qboolean NET_CompareAdr(netadr_t a, netadr_t b); qboolean NET_CompareBaseAdr(netadr_t a, netadr_t b); qboolean NET_IsLocalAddress(netadr_t adr); -char * NET_AdrToString(netadr_t a); -qboolean NET_StringToAdr(char * s, netadr_t * a); -void NET_Sleep(int msec); + +char * NET_AdrToString(netadr_t addr); +qboolean NET_StringToAdr(const char * s, netadr_t * addr); //============================================================================ @@ -613,12 +613,13 @@ extern byte net_message_buffer[MAX_MSGLEN]; void Netchan_Init(void); void Netchan_Setup(netsrc_t sock, netchan_t * chan, netadr_t adr, int qport); -qboolean Netchan_NeedReliable(netchan_t * chan); void Netchan_Transmit(netchan_t * chan, int length, byte * data); void Netchan_OutOfBand(int net_socket, netadr_t adr, int length, byte * data); void Netchan_OutOfBandPrint(int net_socket, netadr_t adr, char * format, ...); + qboolean Netchan_Process(netchan_t * chan, sizebuf_t * msg); qboolean Netchan_CanReliable(netchan_t * chan); +qboolean Netchan_NeedReliable(netchan_t * chan); /* ============================================================== diff --git a/src/game/g_local.h b/src/game/g_local.h index 1880315..153ef2c 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -182,9 +182,8 @@ typedef enum MOVETYPE_NOCLIP, // origin and angles change with no interaction MOVETYPE_PUSH, // no clip to world, push on box contact MOVETYPE_STOP, // no clip to world, stops on box contact - - MOVETYPE_WALK, // gravity - MOVETYPE_STEP, // gravity, special edge handling + MOVETYPE_WALK, // gravity + MOVETYPE_STEP, // gravity, special edge handling MOVETYPE_FLY, MOVETYPE_TOSS, // gravity MOVETYPE_FLYMISSILE, // extra size to monsters @@ -482,10 +481,9 @@ extern int body_armor_index; #define MOD_FRIENDLY_FIRE 0x8000000 extern int meansOfDeath; - extern edict_t * g_edicts; -#define FOFS(x) (int) & (((edict_t *)0)->x) +#define FOFS(x) (int) & (((edict_t *)0)->x) #define STOFS(x) (int) & (((spawn_temp_t *)0)->x) #define LLOFS(x) (int) & (((level_locals_t *)0)->x) #define CLOFS(x) (int) & (((gclient_t *)0)->x) @@ -504,30 +502,23 @@ extern cvar_t * password; extern cvar_t * spectator_password; extern cvar_t * g_select_empty; extern cvar_t * dedicated; - extern cvar_t * filterban; - extern cvar_t * sv_gravity; extern cvar_t * sv_maxvelocity; - extern cvar_t *gun_x, *gun_y, *gun_z; extern cvar_t * sv_rollspeed; extern cvar_t * sv_rollangle; - extern cvar_t * run_pitch; extern cvar_t * run_roll; extern cvar_t * bob_up; extern cvar_t * bob_pitch; extern cvar_t * bob_roll; - extern cvar_t * sv_cheats; extern cvar_t * maxclients; extern cvar_t * maxspectators; - extern cvar_t * flood_msgs; extern cvar_t * flood_persecond; extern cvar_t * flood_waitdelay; - extern cvar_t * sv_maplist; #define world (&g_edicts[0]) diff --git a/src/game/g_main.c b/src/game/g_main.c index 692e03c..a63e918 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -45,30 +45,23 @@ cvar_t * maxspectators; cvar_t * maxentities; cvar_t * g_select_empty; cvar_t * dedicated; - cvar_t * filterban; - cvar_t * sv_maxvelocity; cvar_t * sv_gravity; - cvar_t * sv_rollspeed; cvar_t * sv_rollangle; cvar_t * gun_x; cvar_t * gun_y; cvar_t * gun_z; - cvar_t * run_pitch; cvar_t * run_roll; cvar_t * bob_up; cvar_t * bob_pitch; cvar_t * bob_roll; - cvar_t * sv_cheats; - cvar_t * flood_msgs; cvar_t * flood_persecond; cvar_t * flood_waitdelay; - cvar_t * sv_maplist; void SpawnEntities(char * mapname, char * entities, char * spawnpoint); @@ -132,9 +125,10 @@ game_export_t * GetGameAPI(game_import_t * import) return &globals; } -#ifndef GAME_HARD_LINKED // this is only here so the functions in q_shared.c and q_shwin.c can link -void Sys_Error(char * error, ...) +#ifndef GAME_HARD_LINKED + +void Sys_Error(const char * error, ...) { va_list argptr; char text[1024]; @@ -146,7 +140,7 @@ void Sys_Error(char * error, ...) gi.error(ERR_FATAL, "%s", text); } -void Com_Printf(char * msg, ...) +void Com_Printf(const char * msg, ...) { va_list argptr; char text[1024]; @@ -158,7 +152,7 @@ void Com_Printf(char * msg, ...) gi.dprintf("%s", text); } -#endif +#endif // GAME_HARD_LINKED //====================================================================== @@ -224,7 +218,7 @@ void EndDMLevel(void) // see if it's in the map list if (*sv_maplist->string) { - s = strdup(sv_maplist->string); + s = G_CopyString(sv_maplist->string); f = NULL; t = strtok(s, seps); while (t != NULL) @@ -241,19 +235,26 @@ void EndDMLevel(void) BeginIntermission(CreateTargetChangeLevel(f)); } else + { BeginIntermission(CreateTargetChangeLevel(t)); - free(s); + } + + gi.TagFree(s); return; } if (!f) + { f = t; + } t = strtok(NULL, seps); } - free(s); + gi.TagFree(s); } if (level.nextmap[0]) // go to a specific map + { BeginIntermission(CreateTargetChangeLevel(level.nextmap)); + } else { // search for a changelevel ent = G_Find(NULL, FOFS(classname), "target_changelevel"); diff --git a/src/game/g_save.c b/src/game/g_save.c index b47c82d..990884c 100644 --- a/src/game/g_save.c +++ b/src/game/g_save.c @@ -119,7 +119,6 @@ field_t fields[] = { { "nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP }, { 0, 0, 0, 0 } - }; field_t levelfields[] = @@ -760,7 +759,9 @@ void ReadLevel(char * filename) // fire any cross-level triggers if (ent->classname) + { if (strcmp(ent->classname, "target_crosslevel_target") == 0) ent->nextthink = level.time + ent->delay; + } } } diff --git a/src/game/g_utils.c b/src/game/g_utils.c index 185d46e..56bc700 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -379,7 +379,6 @@ void vectoangles(vec3_t value1, vec3_t angles) char * G_CopyString(char * in) { char * out; - out = gi.TagMalloc(strlen(in) + 1, TAG_LEVEL); strcpy(out, in); return out; diff --git a/src/game/game.h b/src/game/game.h index d488c06..e611170 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -118,10 +118,13 @@ struct edict_s typedef struct { // special messages - void (*bprintf)(int printlevel, char * fmt, ...); - void (*dprintf)(char * fmt, ...); - void (*cprintf)(edict_t * ent, int printlevel, char * fmt, ...); - void (*centerprintf)(edict_t * ent, char * fmt, ...); + void (*bprintf)(int printlevel, const char * fmt, ...); + void (*dprintf)(const char * fmt, ...); + void (*cprintf)(edict_t * ent, int printlevel, const char * fmt, ...); + void (*centerprintf)(edict_t * ent, const char * fmt, ...); + void (*error)(const char * fmt, ...); + + // sound system: void (*sound)(edict_t * ent, int channel, int soundindex, float volume, float attenuation, float timeofs); void (*positioned_sound)(vec3_t origin, edict_t * ent, int channel, int soundinedex, float volume, float attenuation, float timeofs); @@ -131,8 +134,6 @@ typedef struct // they connect, and changes are sent to all connected clients. void (*configstring)(int num, char * string); - void (*error)(char * fmt, ...); - // the *index functions create configstrings and some internal server state int (*modelindex)(char * name); int (*soundindex)(char * name); diff --git a/src/game/p_view.c b/src/game/p_view.c index 5db235b..85b87fb 100644 --- a/src/game/p_view.c +++ b/src/game/p_view.c @@ -368,7 +368,7 @@ void SV_CalcGunOffset(edict_t * ent) // gun height VectorClear(ent->client->ps.gunoffset); - // ent->ps->gunorigin[2] += bob; + // ent->ps->gunorigin[2] += bob; // gun_x / gun_y / gun_z are development tools for (i = 0; i < 3; i++) diff --git a/src/game/q_shared.h b/src/game/q_shared.h index cce3f5b..212e9fe 100644 --- a/src/game/q_shared.h +++ b/src/game/q_shared.h @@ -314,20 +314,18 @@ COLLISION DETECTION */ // lower bits are stronger, and will eat weaker brushes completely -#define CONTENTS_SOLID 1 // an eye is never valid in a solid +#define CONTENTS_SOLID 1 // an eye is never valid in a solid #define CONTENTS_WINDOW 2 // translucent, but not watery -#define CONTENTS_AUX 4 -#define CONTENTS_LAVA 8 -#define CONTENTS_SLIME 16 -#define CONTENTS_WATER 32 -#define CONTENTS_MIST 64 +#define CONTENTS_AUX 4 +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_MIST 64 #define LAST_VISIBLE_CONTENTS 64 // remaining contents are non-visible, and don't eat brushes - -#define CONTENTS_AREAPORTAL 0x8000 - -#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_AREAPORTAL 0x8000 +#define CONTENTS_PLAYERCLIP 0x10000 #define CONTENTS_MONSTERCLIP 0x20000 // currents can be added to any other contents, and may be mixed @@ -847,7 +845,6 @@ typedef struct #define MZ2_WIDOW2_BEAM_SWEEP_9 208 #define MZ2_WIDOW2_BEAM_SWEEP_10 209 #define MZ2_WIDOW2_BEAM_SWEEP_11 210 - // ROGUE extern vec3_t monster_flash_offset[]; diff --git a/src/null/cd_null.c b/src/null/cd_null.c index dfdd784..a5a5483 100644 --- a/src/null/cd_null.c +++ b/src/null/cd_null.c @@ -1,3 +1,22 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ // cd_null.c -- null CD audio API diff --git a/src/null/cl_null.c b/src/null/cl_null.c index 182a298..65dc85c 100644 --- a/src/null/cl_null.c +++ b/src/null/cl_null.c @@ -1,3 +1,22 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ // cl_null.c -- this file can stub out the entire client system // for pure dedicated servers diff --git a/src/null/glimp_null.c b/src/null/glimp_null.c index bd88083..1b0805b 100644 --- a/src/null/glimp_null.c +++ b/src/null/glimp_null.c @@ -1,3 +1,22 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ // glimp_null.c -- null OpenGL context. diff --git a/src/null/in_null.c b/src/null/in_null.c index 38e3979..4265809 100644 --- a/src/null/in_null.c +++ b/src/null/in_null.c @@ -1,3 +1,22 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ // in_null.c -- for systems without a mouse diff --git a/src/null/net_null.c b/src/null/net_null.c index 67a4147..18cb3e9 100644 --- a/src/null/net_null.c +++ b/src/null/net_null.c @@ -1,5 +1,24 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. -// net_null.c -- null network functions. +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// net_null.c -- null network driver. #include "common/q_common.h" @@ -11,22 +30,30 @@ NET_CompareAdr qboolean NET_CompareAdr(netadr_t a, netadr_t b) { if (a.type != b.type) + { return false; + } if (a.type == NA_LOOPBACK) + { return true; + } if (a.type == NA_IP) { if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port) + { return true; + } return false; } if (a.type == NA_IPX) { if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port) + { return true; + } return false; } } @@ -34,33 +61,51 @@ qboolean NET_CompareAdr(netadr_t a, netadr_t b) /* =================== NET_CompareBaseAdr - -Compares without the port =================== */ qboolean NET_CompareBaseAdr(netadr_t a, netadr_t b) { + // Compares without the port + if (a.type != b.type) + { return false; + } if (a.type == NA_LOOPBACK) + { return true; + } if (a.type == NA_IP) { if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]) + { return true; + } return false; } if (a.type == NA_IPX) { if ((memcmp(a.ipx, b.ipx, 10) == 0)) + { return true; + } return false; } } +/* +============= +NET_IsLocalAddress +============= +*/ +qboolean NET_IsLocalAddress(netadr_t adr) +{ + return adr.type == NA_LOOPBACK; +} + /* =================== NET_AdrToString @@ -77,105 +122,48 @@ char * NET_AdrToString(netadr_t a) NET_StringToAdr ============= */ -qboolean NET_StringToAdr(char * s, netadr_t * a) +qboolean NET_StringToAdr(const char * s, netadr_t * a) { return false; } /* -============= -NET_IsLocalAddress -============= +==================== +NET_GetPacket +==================== */ -qboolean NET_IsLocalAddress(netadr_t adr) -{ - return adr.type == NA_LOOPBACK; -} - -/* -============================================================================= - -LOOPBACK BUFFERS FOR LOCAL PLAYER - -============================================================================= -*/ - -qboolean NET_GetLoopPacket(netsrc_t sock, netadr_t * net_from, sizebuf_t * net_message) -{ - return false; -} - -void NET_SendLoopPacket(netsrc_t sock, int length, void * data, netadr_t to) -{ -} - -//============================================================================= - qboolean NET_GetPacket(netsrc_t sock, netadr_t * net_from, sizebuf_t * net_message) { return false; } -//============================================================================= - -void NET_SendPacket(netsrc_t sock, int length, void * data, netadr_t to) -{ -} - -//============================================================================= - /* ==================== -NET_Socket +NET_SendPacket ==================== */ -int NET_IPSocket(char * net_interface, int port) -{ - return 0; -} - -/* -==================== -NET_OpenIP -==================== -*/ -void NET_OpenIP(void) -{ -} - -/* -==================== -IPX_Socket -==================== -*/ -int NET_IPXSocket(int port) -{ - return 0; -} - -/* -==================== -NET_OpenIPX -==================== -*/ -void NET_OpenIPX(void) +void NET_SendPacket(netsrc_t sock, int length, const void * data, netadr_t to) { } /* ==================== NET_Config - -A single player game will only use the loopback code ==================== */ void NET_Config(qboolean multiplayer) { + // A single player game will only use the loopback code } -// sleeps msec or until net socket is ready +/* +==================== +NET_Sleep +==================== +*/ void NET_Sleep(int msec) { + // Sleeps msec or until net socket is ready } /* diff --git a/src/null/snddma_null.c b/src/null/snddma_null.c index c6d50a3..c8cdd4f 100644 --- a/src/null/snddma_null.c +++ b/src/null/snddma_null.c @@ -1,3 +1,22 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ // snddma_null.c // all other sound mixing is portable diff --git a/src/null/sv_null.c b/src/null/sv_null.c index 00c6e3c..3fb1e90 100644 --- a/src/null/sv_null.c +++ b/src/null/sv_null.c @@ -1,3 +1,22 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ // sv_null.c -- this file can stub out the entire server system // for pure net-only clients diff --git a/src/null/swimp_null.c b/src/null/swimp_null.c index 5168eab..fee1974 100644 --- a/src/null/swimp_null.c +++ b/src/null/swimp_null.c @@ -1,3 +1,24 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// swimp_null.h -- null software renderer driver #include "client/client.h" diff --git a/src/null/sys_null.c b/src/null/sys_null.c index 1e7bce4..b59c02c 100644 --- a/src/null/sys_null.c +++ b/src/null/sys_null.c @@ -1,3 +1,22 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ // sys_null.h -- null system driver to aid porting efforts @@ -8,11 +27,7 @@ unsigned sys_frame_time; //============================================================================= -void Sys_mkdir(char * path) -{ -} - -void Sys_Error(char * error, ...) +void Sys_Error(const char * error, ...) { va_list argptr; @@ -44,7 +59,7 @@ char * Sys_ConsoleInput(void) return NULL; } -void Sys_ConsoleOutput(char * string) +void Sys_ConsoleOutput(const char * string) { } diff --git a/src/null/vid_null.c b/src/null/vid_null.c index e846681..e3e5280 100644 --- a/src/null/vid_null.c +++ b/src/null/vid_null.c @@ -1,3 +1,22 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ // vid_null.c -- null video driver to aid porting efforts // this assumes that one of the refs is statically linked to the executable @@ -24,9 +43,9 @@ DIRECT LINK GLUE enum { MAXPRINTMSG = 4096 -} +}; -void VID_Printf(int print_level, char * fmt, ...) +void VID_Printf(int print_level, const char * fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; @@ -45,7 +64,7 @@ void VID_Printf(int print_level, char * fmt, ...) } } -void VID_Error(int err_level, char * fmt, ...) +void VID_Error(int err_level, const char * fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; diff --git a/src/ps2/main_ps2.c b/src/ps2/main_ps2.c index 98f98d1..6eaaf11 100644 --- a/src/ps2/main_ps2.c +++ b/src/ps2/main_ps2.c @@ -15,10 +15,13 @@ // // TODO: // -// - move main to a separate file (main_ps2.c) -// - replace raw malloc calls so we can account for memory +// - bring up the optimized asm math functions for the PS2 (on math_funcs.c) +// // - Need to find this 'ps2mkisofs' to be able to make a proper PS2 ISO!!! // +// - probably add a "welcome screen" right after load to display idSoftware +// copyright and maybe some self promoting as well ;) +// //FIXME TEMP testing stuff #include "client/client.h" @@ -26,6 +29,35 @@ extern refexport_t re; extern void Test_PS2_Draw2D(void); extern void Test_PS2_Cinematics(void); +static const char * all_menu_names[] = +{ + "menu_main", + "menu_game", + "menu_loadgame", + "menu_savegame", + "menu_joinserver", + "menu_addressbook", + "menu_startserver", + "menu_dmoptions", + "menu_playerconfig", + "menu_downloadoptions", + "menu_credits", + "menu_multiplayer", + "menu_video", + "menu_options", + "menu_keys", + "menu_quit" +}; + +enum +{ + NUM_MENUS = sizeof(all_menu_names) / sizeof(all_menu_names[0]), + MENU_MSEC = 6 * 1000 +}; + +static int next_menu = 0; +static int time_til_next_menu = MENU_MSEC; + /* ================ PS2 main() function @@ -75,6 +107,8 @@ int main(void) char * argv[] = { "QPS2.ELF" }; Qcommon_Init(argc, argv); + Cbuf_AddText((char *)all_menu_names[next_menu]); + oldtime = Sys_Milliseconds(); for (;;) { @@ -87,6 +121,15 @@ int main(void) Qcommon_Frame(time); oldtime = newtime; + + //TEST cycling all the menus + if (time_til_next_menu <= 0 && next_menu < NUM_MENUS) + { + Cbuf_AddText((char *)all_menu_names[next_menu++]); + time_til_next_menu = MENU_MSEC; + } + time_til_next_menu -= time; + //TEST cycling all the menus } #endif //0 diff --git a/src/ps2/mem_alloc.c b/src/ps2/mem_alloc.c index 880a3ad..f5d15d0 100644 --- a/src/ps2/mem_alloc.c +++ b/src/ps2/mem_alloc.c @@ -18,16 +18,21 @@ extern void Sys_Error(const char * error, ...); // For debug printing -static const char * mem_tag_names[MEMTAG_COUNT] = +const char * ps2_mem_tag_names[MEMTAG_COUNT] = { - "MEMTAG_FILESYS", - "MEMTAG_HUNK_ALLOC", - "MEMTAG_TEXIMAGE" + "MISC", + "QUAKE", + "RENDERER", + "TEX_IMAGE", + "HUNK_ALLOC" }; +// Tags updated on every alloc/free. +unsigned int ps2_mem_tag_counts[MEMTAG_COUNT] = {0}; + //============================================================================= // -// malloc/memalign hooks: +// malloc/free hooks: // //============================================================================= @@ -43,15 +48,14 @@ void * PS2_MemAlloc(int size_bytes, ps2_mem_tag_t tag) Sys_Error("Trying to allocate zero or negative size (%d)!", size_bytes); } - //TODO add tracking counters! - (void)tag; - void * ptr = malloc(size_bytes); if (ptr == NULL) { - Sys_Error("Out-of-memory for tag %s!", mem_tag_names[tag]); + Sys_Error("Out-of-memory for tag %s! Failed to alloc %d bytes.", + ps2_mem_tag_names[tag], size_bytes); } + ps2_mem_tag_counts[tag] += size_bytes; return ptr; } @@ -60,29 +64,118 @@ void * PS2_MemAlloc(int size_bytes, ps2_mem_tag_t tag) PS2_MemFree ================ */ -void PS2_MemFree(void * ptr, ps2_mem_tag_t tag) +void PS2_MemFree(void * ptr, int size_bytes, ps2_mem_tag_t tag) { if (ptr == NULL) { return; } - //TODO add tracking counters! - (void)tag; - + ps2_mem_tag_counts[tag] -= size_bytes; free(ptr); } /* ================ -PS2_AddRenderPacketMem +PS2_FormatMemoryUnit ================ */ -void PS2_AddRenderPacketMem(unsigned int size_bytes) +const char * PS2_FormatMemoryUnit(unsigned int size_bytes, int abbreviated) { - // TODO so we can keep track of memory allocated - // externally by the SDK for render packets! - (void)size_bytes; + enum + { + KILOBYTE = 1024, + MEGABYTE = 1024 * KILOBYTE, + GIGABYTE = 1024 * MEGABYTE + }; + + const char * mem_unit_str; + float adjusted_size; + + if (size_bytes < KILOBYTE) + { + mem_unit_str = abbreviated ? "B" : "Bytes"; + adjusted_size = (float)size_bytes; + } + else if (size_bytes < MEGABYTE) + { + mem_unit_str = abbreviated ? "KB" : "Kilobytes"; + adjusted_size = size_bytes / 1024.0f; + } + else if (size_bytes < GIGABYTE) + { + mem_unit_str = abbreviated ? "MB" : "Megabytes"; + adjusted_size = size_bytes / 1024.0f / 1024.0f; + } + else + { + mem_unit_str = abbreviated ? "GB" : "Gigabytes"; + adjusted_size = size_bytes / 1024.0f / 1024.0f / 1024.0f; + } + + char * fmtbuf; + int chars_written; + char num_str_buf[100]; + + // Max chars reserved for the output string, max `num_str_buf + 28` chars for the unit str: + enum + { + MEM_UNIT_STR_MAXLEN = sizeof(num_str_buf) + 28 + }; + static int bufnum = 0; + static char local_str_buf[8][MEM_UNIT_STR_MAXLEN]; + + fmtbuf = local_str_buf[bufnum]; + bufnum = (bufnum + 1) & 7; + + // We only care about the first 2 decimal digs + chars_written = snprintf(num_str_buf, 100, "%.2f", adjusted_size); + if (chars_written <= 0) + { + fmtbuf[0] = '?'; + fmtbuf[1] = '?'; + fmtbuf[2] = '?'; + fmtbuf[3] = '\0'; + return fmtbuf; // Error return + } + + // Remove trailing zeros if no significant decimal digits: + char * p = num_str_buf; + for (; *p; ++p) + { + if (*p == '.') + { + // Find the end of the string + while (*++p) + { + } + + // Remove trailing zeros + while (*--p == '0') + { + *p = '\0'; + } + // If the dot was left alone at the end, remove it too + if (*p == '.') + { + *p = '\0'; + } + break; + } + } + + // Consolidate the strings: + chars_written = snprintf(fmtbuf, MEM_UNIT_STR_MAXLEN, "%s %s", num_str_buf, mem_unit_str); + if (chars_written <= 0) + { + fmtbuf[0] = '?'; + fmtbuf[1] = '?'; + fmtbuf[2] = '?'; + fmtbuf[3] = '\0'; + return fmtbuf; // Error return + } + + return fmtbuf; } //============================================================================= @@ -148,7 +241,7 @@ void Hunk_Free(void * base) { if (base != NULL) { - PS2_MemFree(base, MEMTAG_HUNK_ALLOC); + PS2_MemFree(base, hunk_max_size, MEMTAG_HUNK_ALLOC); } --hunk_count; } diff --git a/src/ps2/mem_alloc.h b/src/ps2/mem_alloc.h index a0e90c0..0fa69f4 100644 --- a/src/ps2/mem_alloc.h +++ b/src/ps2/mem_alloc.h @@ -14,19 +14,28 @@ #define PS2_MEM_ALLOC_H // NOTE: -// Be sure to updated mem_tag_names[] in the .c when changing this! +// Be sure to updated ps2_mem_tag_names[] in the .c when changing this! typedef enum { - MEMTAG_FILESYS, // Miscellaneous file systems allocations. - MEMTAG_HUNK_ALLOC, // Allocs for the Hunk_*() functions. + MEMTAG_MISC, // Miscellaneous/uncategorized (includes the estimate size of the ELF executable). + MEMTAG_QUAKE, // Game allocations: Z_Malloc/Z_TagMalloc/etc. + MEMTAG_RENDERER, // Things related to rendering / the refresh module. MEMTAG_TEXIMAGE, // Allocs related to images/textures/palettes. + MEMTAG_HUNK_ALLOC, // Allocs for the Hunk_*() functions. MEMTAG_COUNT // Number of entries in this enum. Internal use only. } ps2_mem_tag_t; -void * PS2_MemAlloc(int size_bytes, ps2_mem_tag_t tag); -void PS2_MemFree(void * ptr, ps2_mem_tag_t tag); -void PS2_AddRenderPacketMem(unsigned int size_bytes); +extern const char * ps2_mem_tag_names[MEMTAG_COUNT]; // Printable strings for the above enum. +extern unsigned int ps2_mem_tag_counts[MEMTAG_COUNT]; // Current memory counts for each of the above tags. +// Allocators: +void * PS2_MemAlloc(int size_bytes, ps2_mem_tag_t tag); +void PS2_MemFree(void * ptr, int size_bytes, ps2_mem_tag_t tag); + +// Formatter for printing the memory tags. +const char * PS2_FormatMemoryUnit(unsigned int memorySizeInBytes, int abbreviated); + +// Wrapper for memseting pointers to objects/structures. #define PS2_MemClearObj(obj_ptr) memset((obj_ptr), 0, sizeof(*(obj_ptr))) #endif // PS2_MEM_ALLOC_H diff --git a/src/ps2/net_ps2.c b/src/ps2/net_ps2.c new file mode 100644 index 0000000..b078c39 --- /dev/null +++ b/src/ps2/net_ps2.c @@ -0,0 +1,329 @@ + +/* ================================================================================================ + * -*- C -*- + * File: net_ps2.c + * Author: Guilherme R. Lampert + * Created on: 27/10/15 + * Brief: Implementation of Quake2 NET_ functions (network module) for the PS2. + * + * This source code is released under the GNU GPL v2 license. + * Check the accompanying LICENSE file for details. + * ================================================================================================ */ + +#include "common/q_common.h" + +// +// Local loopback (localhost) buffers, adapted from net_wins.c +// + +enum +{ + MAX_LOOPBACK = 4 +}; + +typedef struct +{ + int datalen; + byte data[MAX_MSGLEN]; +} loopmsg_t; + +typedef struct +{ + int get; + int send; + loopmsg_t msgs[MAX_LOOPBACK]; +} loopback_t; + +// Alignment is not strictly necessary here, but might boost memcpy/memset perf. +static loopback_t loopbacks[2] __attribute__((aligned(16))); + +//============================================================================= +// +// Misc NET helpers: +// +//============================================================================= + +/* +=================== +NET_CompareAdr +=================== +*/ +qboolean NET_CompareAdr(netadr_t a, netadr_t b) +{ + if (a.type == NA_LOOPBACK) + { + return true; + } + + if (a.type != b.type) + { + return false; + } + + if (a.type == NA_IP) + { + if (a.ip[0] == b.ip[0] && + a.ip[1] == b.ip[1] && + a.ip[2] == b.ip[2] && + a.ip[3] == b.ip[3] && + a.port == b.port) + { + return true; + } + return false; + } + + if (a.type == NA_IPX) + { + if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port) + { + return true; + } + return false; + } +} + +/* +=================== +NET_CompareBaseAdr +=================== +*/ +qboolean NET_CompareBaseAdr(netadr_t a, netadr_t b) +{ + // Compares without the port num. + + if (a.type == NA_LOOPBACK) + { + return true; + } + + if (a.type != b.type) + { + return false; + } + + if (a.type == NA_IP) + { + if (a.ip[0] == b.ip[0] && + a.ip[1] == b.ip[1] && + a.ip[2] == b.ip[2] && + a.ip[3] == b.ip[3]) + { + return true; + } + return false; + } + + if (a.type == NA_IPX) + { + if ((memcmp(a.ipx, b.ipx, 10) == 0)) + { + return true; + } + return false; + } +} + +/* +=================== +NET_AdrToString +=================== +*/ +char * NET_AdrToString(netadr_t addr) +{ +// FIXME temp but fine, since we are currently localhost bound +#define ntohs(x) (x) + + static char s[64]; + + if (addr.type == NA_LOOPBACK) + { + Com_sprintf(s, sizeof(s), "loopback"); + } + else if (addr.type == NA_IP) + { + Com_sprintf(s, sizeof(s), "%i.%i.%i.%i:%i", + addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], + ntohs(addr.port)); + } + else + { + Com_sprintf(s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", + addr.ipx[0], addr.ipx[1], addr.ipx[2], addr.ipx[3], addr.ipx[4], + addr.ipx[5], addr.ipx[6], addr.ipx[7], addr.ipx[8], addr.ipx[9], + ntohs(addr.port)); + } + + return s; + +#undef ntohs +} + +/* +============= +NET_StringToAdr +============= +*/ +qboolean NET_StringToAdr(const char * s, netadr_t * addr) +{ + if (strcmp(s, "localhost") == 0 || strcmp(s, "loopback") == 0) + { + memset(addr, 0, sizeof(*addr)); + addr->type = NA_LOOPBACK; + return true; + } + + // TODO Only localhost is currently supported! + memset(addr, 0, sizeof(*addr)); + return false; +} + +/* +============= +NET_IsLocalAddress +============= +*/ +qboolean NET_IsLocalAddress(netadr_t adr) +{ + return adr.type == NA_LOOPBACK; +} + +//============================================================================= +// +// Loopback buffers for the local player: +// +//============================================================================= + +/* +==================== +NET_GetLoopPacket +==================== +*/ +static qboolean NET_GetLoopPacket(netsrc_t sock, netadr_t * net_from, sizebuf_t * net_message) +{ + // Same code from net_wins.c, Win32 Quake2. + + loopback_t * loop = &loopbacks[sock]; + + if (loop->send - loop->get > MAX_LOOPBACK) + { + loop->get = loop->send - MAX_LOOPBACK; + } + + if (loop->get >= loop->send) + { + return false; + } + + int i = loop->get & (MAX_LOOPBACK - 1); + loop->get++; + + memcpy(net_message->data, loop->msgs[i].data, loop->msgs[i].datalen); + net_message->cursize = loop->msgs[i].datalen; + + memset(net_from, 0, sizeof(*net_from)); + net_from->type = NA_LOOPBACK; + + return true; +} + +/* +==================== +NET_GetPacket +==================== +*/ +qboolean NET_GetPacket(netsrc_t sock, netadr_t * net_from, sizebuf_t * net_message) +{ + if (NET_GetLoopPacket(sock, net_from, net_message)) + { + return true; + } + + // TODO Only localhost is currently supported! + return false; +} + +/* +==================== +NET_SendLoopPacket +==================== +*/ +static void NET_SendLoopPacket(netsrc_t sock, int length, const void * data, netadr_t to) +{ + loopback_t * loop = &loopbacks[sock ^ 1]; + + int i = loop->send & (MAX_LOOPBACK - 1); + loop->send++; + + memcpy(loop->msgs[i].data, data, length); + loop->msgs[i].datalen = length; +} + +/* +==================== +NET_SendPacket +==================== +*/ +void NET_SendPacket(netsrc_t sock, int length, const void * data, netadr_t to) +{ + if (to.type == NA_LOOPBACK) + { + NET_SendLoopPacket(sock, length, data, to); + return; + } + + // TODO Only localhost is currently supported! +} + +//============================================================================= +// +// NET startup/shutdown: +// +//============================================================================= + +/* +==================== +NET_Config +==================== +*/ +void NET_Config(qboolean multiplayer) +{ + Com_DPrintf("---- NET_Config ----\n"); + + // A single player game will only use the loopback code + if (multiplayer) + { + Com_Error(ERR_DROP, "Quake2 multiplayer currently unsupported!\n"); + } +} + +/* +==================== +NET_Sleep +==================== +*/ +void NET_Sleep(int msec) +{ + // TODO This is where Quake calls select() with msec timeout. + (void)msec; +} + +/* +==================== +NET_Init +==================== +*/ +void NET_Init(void) +{ + Com_DPrintf("---- NET_Init ----\n"); +} + +/* +==================== +NET_Shutdown +==================== +*/ +void NET_Shutdown(void) +{ + Com_DPrintf("---- NET_Shutdown ----\n"); +} diff --git a/src/ps2/ref_ps2.c b/src/ps2/ref_ps2.c index fdd8142..28cb6a3 100644 --- a/src/ps2/ref_ps2.c +++ b/src/ps2/ref_ps2.c @@ -31,6 +31,7 @@ static cvar_t * r_ps2_vid_height = NULL; static cvar_t * r_ps2_ui_brightness = NULL; static cvar_t * r_ps2_fade_scr_alpha = NULL; static cvar_t * r_ps2_show_fps = NULL; +static cvar_t * r_ps2_show_mem_tags = NULL; // Average multiple frames together to smooth changes out a bit. enum { MAX_FPS_HIST = 4 }; @@ -55,7 +56,7 @@ typedef struct u16 u0, v0; u16 u1, v1; byte r, g, b, a; -} ps2_2d_quad_t; +} screen_quad_t; enum { @@ -75,7 +76,7 @@ static int fade_scr_index = -1; // 2D draw calls are always batched to try avoiding unnecessary texture switches. static int next_in_2d_batch = 0; -static ps2_2d_quad_t draw2d_batch[DRAW2D_BATCH_SIZE] __attribute__((aligned(16))); +static screen_quad_t draw2d_batch[DRAW2D_BATCH_SIZE] __attribute__((aligned(16))); #define DRAW2D_NEXT_BATCH_ELEMENT() (&draw2d_batch[next_in_2d_batch++]) // @@ -265,30 +266,6 @@ static void PS2_InitDrawingEnvironment(void) wrap.maxv = MAX_TEXIMAGE_SIZE; q = draw_texture_wrapping(q, 0, &wrap); -///////// - - //FIXME TEMP clean this up - /* - atest_t atest; - dtest_t dtest; - ztest_t ztest; - - atest.enable = DRAW_ENABLE; - atest.method = ATEST_METHOD_GREATER; - atest.compval = 0; - atest.keep = ATEST_KEEP_FRAMEBUFFER; - - dtest.enable = DRAW_DISABLE; - dtest.pass = DRAW_DISABLE; - - ztest.enable = DRAW_ENABLE; - ztest.method = ZTEST_METHOD_GREATER_EQUAL; - - q = draw_pixel_test(q, 0, &atest, &dtest, &ztest); - //*/ - -///////// - q = draw_finish(q); dma_channel_send_normal(DMA_CHANNEL_GIF, packet->data, (q - packet->data), 0, 0); dma_wait_fast(); @@ -391,7 +368,7 @@ enum elem2d_type ELEM_2D_COLOR_ONLY, ELEM_2D_FADE_SCR }; -static qword_t * PS2_Draw2DAddToPacket(qword_t * qwptr, const ps2_2d_quad_t * quad, enum elem2d_type type) +static qword_t * PS2_Draw2DAddToPacket(qword_t * qwptr, const screen_quad_t * quad, enum elem2d_type type) { rect_t rect; texrect_t texrect; @@ -509,8 +486,8 @@ PS2_Draw2DBatchSortPredicate */ static int PS2_Draw2DBatchSortPredicate(const void * a, const void * b) { - const ps2_2d_quad_t * q1 = (const ps2_2d_quad_t *)a; - const ps2_2d_quad_t * q2 = (const ps2_2d_quad_t *)b; + const screen_quad_t * q1 = (const screen_quad_t *)a; + const screen_quad_t * q2 = (const screen_quad_t *)b; // Group by texture: int result = q1->tex_index - q2->tex_index; @@ -530,7 +507,7 @@ static int PS2_Draw2DBatchSortPredicate(const void * a, const void * b) PS2_SortAndDraw2DElements ================ */ -static void PS2_SortAndDraw2DElements(ps2_2d_quad_t * batch, int batch_size) +static void PS2_SortAndDraw2DElements(screen_quad_t * batch, int batch_size) { if (batch_size <= 0) { @@ -538,7 +515,7 @@ static void PS2_SortAndDraw2DElements(ps2_2d_quad_t * batch, int batch_size) } // Sort by texture, so we only switch once per texture image: - qsort(batch, batch_size, sizeof(ps2_2d_quad_t), &PS2_Draw2DBatchSortPredicate); + qsort(batch, batch_size, sizeof(screen_quad_t), &PS2_Draw2DBatchSortPredicate); // Non-textured elements draw first. Since those have negative // tex_index, they are at the front of the sorted batch. @@ -546,7 +523,7 @@ static void PS2_SortAndDraw2DElements(ps2_2d_quad_t * batch, int batch_size) int i; enum elem2d_type quad_type; - const ps2_2d_quad_t * quad; + const screen_quad_t * quad; for (i = 0; i < batch_size; ++i) { @@ -647,17 +624,14 @@ PS2_DrawFullScreenCinematic */ static void PS2_DrawFullScreenCinematic(void) { - if (!cinematic_frame.draw_pending) - { - return; - } - texrect_t texrect; - texrect.v0.x = cinematic_frame.x - 2; - texrect.v0.y = cinematic_frame.y - 2; - texrect.v1.x = cinematic_frame.x + cinematic_frame.w + 2; - texrect.v1.y = cinematic_frame.y + cinematic_frame.h + 2; + // Cinematic are not filling the screen properly on my tests... + // Adding these hackish offsets for now. + texrect.v0.x = cinematic_frame.x - 1; + texrect.v0.y = cinematic_frame.y - 1; + texrect.v1.x = cinematic_frame.x + cinematic_frame.w + 1; + texrect.v1.y = cinematic_frame.y + cinematic_frame.h + 45; texrect.v0.z = 0xFFFFFFFF; texrect.v1.z = 0xFFFFFFFF; @@ -694,39 +668,63 @@ PS2_DrawFPSCounter */ static void PS2_DrawFPSCounter(void) { - if (!ps2ref.show_fps_count) - { - return; - } + int time_millisec = Sys_Milliseconds(); // Real time clock + int frame_time = time_millisec - fps.previous_time; - int time_millisec = Sys_Milliseconds(); // Real time clock - int frame_time = time_millisec - fps.previous_time; - - fps.times_hist[fps.index++] = frame_time; - fps.previous_time = time_millisec; + fps.times_hist[fps.index++] = frame_time; + fps.previous_time = time_millisec; // Average our time history when we get enough samples: - if (fps.index == MAX_FPS_HIST) - { - int i, total = 0; - for (i = 0; i < MAX_FPS_HIST; ++i) - { - total += fps.times_hist[i]; - } + if (fps.index == MAX_FPS_HIST) + { + int i, total = 0; + for (i = 0; i < MAX_FPS_HIST; ++i) + { + total += fps.times_hist[i]; + } - if (total == 0) - { - total = 1; - } + if (total == 0) + { + total = 1; + } - fps.fps_count = (10000 * MAX_FPS_HIST / total); - fps.fps_count = (fps.fps_count + 5) / 10; - fps.index = 0; - } + fps.fps_count = (10000 * MAX_FPS_HIST / total); + fps.fps_count = (fps.fps_count + 5) / 10; + fps.index = 0; + } - // Draw it at the top-right corner of the screen: + // Draw it at the top-right corner of the screen: PS2_DrawFill(viddef.width - 65, 3, viddef.width - 10, 15, 0); // A black bg to give the text more contrast. - PS2_DrawString(viddef.width - 60, 6, va("FPS %u", fps.fps_count)); + PS2_DrawString(viddef.width - 60, 6, va("FPS %u", fps.fps_count)); +} + +/* +================ +PS2_DrawMemTags +================ +*/ +static void PS2_DrawMemTags(void) +{ + int i; + int y = 35; + u32 total = 0; + + for (i = 0; i < MEMTAG_COUNT; ++i) + { + total += ps2_mem_tag_counts[i]; + + const char * count_str = PS2_FormatMemoryUnit(ps2_mem_tag_counts[i], true); + const char * formatted_str = va("%-10s %s", ps2_mem_tag_names[i], count_str); + + PS2_DrawString(viddef.width - 170, y, formatted_str); + y += 12; + } + + // Total memory currently allocated (approximately): + PS2_DrawString(viddef.width - 170, y + 6, va("TOTAL: %s", PS2_FormatMemoryUnit(total, true))); + + // A darker background to give the text more contrast. + PS2_DrawFill(viddef.width - 180, 30, viddef.width - 10, 85, 2); } //============================================================================= @@ -754,7 +752,8 @@ qboolean PS2_RendererInit(void * unused1, void * unused2) r_ps2_vid_height = Cvar_Get("r_ps2_vid_height", va("%d", DEFAULT_VID_HEIGHT), 0); r_ps2_ui_brightness = Cvar_Get("r_ps2_ui_brightness", "128", 0); r_ps2_fade_scr_alpha = Cvar_Get("r_ps2_fade_scr_alpha", "100", 0); - r_ps2_show_fps = Cvar_Get("r_ps2_show_fps", "1", 0); + r_ps2_show_fps = Cvar_Get("r_ps2_show_fps", "1", 0); + r_ps2_show_mem_tags = Cvar_Get("r_ps2_show_mem_tags", "1", 0); // Cache these, since on the PS2 we don't have a way of interacting with the console. viddef.width = (int)r_ps2_vid_width->value; @@ -762,6 +761,7 @@ qboolean PS2_RendererInit(void * unused1, void * unused2) ps2ref.ui_brightness = (u32)r_ps2_ui_brightness->value; ps2ref.fade_scr_alpha = (u32)r_ps2_fade_scr_alpha->value; ps2ref.show_fps_count = (qboolean)r_ps2_show_fps->value; + ps2ref.show_mem_tags = (qboolean)r_ps2_show_mem_tags->value; // Renderer id. Used in a couple places by the game. vidref_val = VIDREF_OTHER; @@ -803,7 +803,7 @@ qboolean PS2_RendererInit(void * unused1, void * unused2) // Plus the five packet_ts just allocated above. renderer_packet_mem += sizeof(packet_t) * 5; - PS2_AddRenderPacketMem(renderer_packet_mem); + ps2_mem_tag_counts[MEMTAG_RENDERER] += renderer_packet_mem; // Reset these, to be sure... ps2ref.current_frame_packet = NULL; @@ -811,7 +811,7 @@ qboolean PS2_RendererInit(void * unused1, void * unused2) ps2ref.dmatag_draw2d = NULL; ps2ref.current_tex = NULL; ps2ref.frame_index = 0; - memset(&fps, 0, sizeof(fps)); + memset(&fps, 0, sizeof(fps)); // Init other aux data and default render states: ps2ref.prim_desc.type = PRIM_TRIANGLE; @@ -929,9 +929,9 @@ PS2_RegisterModel */ struct model_s * PS2_RegisterModel(const char * name) { - Com_DPrintf("PS2_RegisterModel: '%s'\n", name); //TODO - return NULL; + static int dummy1; + return (struct model_s *)&dummy1; } /* @@ -941,9 +941,7 @@ PS2_RegisterSkin */ struct image_s * PS2_RegisterSkin(const char * name) { - Com_DPrintf("PS2_RegisterSkin: '%s'\n", name); - //TODO - return NULL; + return (struct image_s *)PS2_TexImageFindOrLoad(name, IT_SKIN); } /* @@ -953,9 +951,7 @@ PS2_RegisterPic */ struct image_s * PS2_RegisterPic(const char * name) { - Com_DPrintf("PS2_RegisterPic: '%s'\n", name); - //TODO - return NULL; + return (struct image_s *)PS2_TexImageFindOrLoad(name, IT_PIC | IT_BUILTIN); } /* @@ -967,6 +963,10 @@ void PS2_SetSky(const char * name, float rotate, vec3_t axis) { Com_DPrintf("PS2_SetSky: '%s'\n", name); //TODO + // + // Looking at ref_gl, it seems that the renderer can decide + // between using TGA or PCX for the skyboxes. TGA should be + // a good choice for the PS2. } /* @@ -1021,15 +1021,26 @@ void PS2_EndFrame(void) Sys_Error("EndFrame: Inconsistent frame states!!!"); } + // // Finalize pending 2D draws. // - // All of our 2D drawings are now batched, so we concentrate + // All of our 2D drawings are batched, so we concentrate // 2D draw call here to ensure only one texture switch per // image being used by the 2D elements. // PS2_Draw2DBegin(); PS2_DrawFullScreenCinematic(); - PS2_DrawFPSCounter(); + + // Extra debug overlays: + if (ps2ref.show_fps_count) + { + PS2_DrawFPSCounter(); + } + if (ps2ref.show_mem_tags) + { + PS2_DrawMemTags(); + } + PS2_Flush2DBatch(); PS2_Draw2DEnd(); @@ -1078,12 +1089,13 @@ PS2_RenderFrame void PS2_RenderFrame(refdef_t * view_def) { CHECK_FRAME_STARTED(); + // + // Quake2 default render mode was 2D, only switching to 3D in here + // (probably in account of the software renderer). + // - // - // Quake2 default render mode was 2D, only switching to 3D in here. - // So RenderFrame always "restores" 2D when done. - // - Sys_Error("Not ready yet!");//TODO + (void)view_def; + //TODO } /* @@ -1279,7 +1291,7 @@ void PS2_DrawChar(int x, int y, int c) row = (c >> 4) * GLYPH_SIZE; col = (c & 15) * GLYPH_SIZE; - ps2_2d_quad_t * quad = DRAW2D_NEXT_BATCH_ELEMENT(); + screen_quad_t * quad = DRAW2D_NEXT_BATCH_ELEMENT(); quad->z_index = DRAW2D_NEXT_Z_INDEX(); quad->tex_index = TEXIMAGE_INDEX(builtin_tex_conchars); @@ -1367,7 +1379,7 @@ void PS2_DrawTileClear(int x, int y, int w, int h, const char * name) return; } - ps2_2d_quad_t * quad = DRAW2D_NEXT_BATCH_ELEMENT(); + screen_quad_t * quad = DRAW2D_NEXT_BATCH_ELEMENT(); quad->z_index = DRAW2D_NEXT_Z_INDEX(); quad->tex_index = TEXIMAGE_INDEX(teximage); @@ -1406,7 +1418,7 @@ void PS2_DrawFill(int x, int y, int w, int h, int c) Sys_Error("PS2_DrawFill: Bad color index %d!", c); } - ps2_2d_quad_t * quad; + screen_quad_t * quad; // Full screen wipe with black (happens on pause and menus), treat it as a screen fade. if (c == 0 && x == 0 && y == 0 && w == viddef.width && h == viddef.height) @@ -1474,7 +1486,7 @@ void PS2_DrawFadeScreen(void) return; // Already issued one this frame! } - ps2_2d_quad_t * quad = DRAW2D_NEXT_BATCH_ELEMENT(); + screen_quad_t * quad = DRAW2D_NEXT_BATCH_ELEMENT(); quad->z_index = DRAW2D_NEXT_Z_INDEX(); quad->tex_index = DRAW2D_TEX_INDEX_FADE_SCR; @@ -1600,7 +1612,7 @@ void PS2_DrawStretchTexImage(int x, int y, int w, int h, ps2_teximage_t * texima return; // No more space this frame! } - ps2_2d_quad_t * quad = DRAW2D_NEXT_BATCH_ELEMENT(); + screen_quad_t * quad = DRAW2D_NEXT_BATCH_ELEMENT(); quad->z_index = DRAW2D_NEXT_Z_INDEX(); quad->tex_index = TEXIMAGE_INDEX(teximage); diff --git a/src/ps2/ref_ps2.h b/src/ps2/ref_ps2.h index 222afcb..1c076b0 100644 --- a/src/ps2/ref_ps2.h +++ b/src/ps2/ref_ps2.h @@ -76,6 +76,7 @@ typedef struct { qboolean initialized; // Flag to keep track of initialization of our global ps2ref. qboolean show_fps_count; // Draws a frames per sec counter in the top-right corner of the screen. + qboolean show_mem_tags; // Draws a debug overlay with the current values of the memory tags. qboolean frame_started; // Set by BeginFrame, cleared at EndFrame. Some calls must be in between. zbuffer_t z_buffer; // PS2 depth buffer information. framebuffer_t frame_buffers[2]; // PS2 color framebuffers (double buffered). @@ -203,9 +204,6 @@ void PS2_TexImageSetup(ps2_teximage_t * teximage, const char * name, int w, int int func, int psm, int mag_filter, int min_filter, ps2_imagetype_t type, byte * pic); void PS2_TexImageFree(ps2_teximage_t * teximage); -// Scrap texture atlas: -ps2_teximage_t * Scrap_AllocBlock(const byte * pic8in, int w, int h, const char * pic_name); - /* * Image loading for textures/sprites: */ @@ -214,6 +212,8 @@ qboolean PCX_LoadFromMemory(const char * filename, const byte * data, int data_l byte ** pic, u32 * palette, int * width, int * height); qboolean PCX_LoadFromFile(const char * filename, byte ** pic, u32 * palette, int * width, int * height); +qboolean TGA_LoadFromFile(const char * filename, byte ** pic, + int * width, int * height); /* * Convert from 8bit palettized to RGB[A]: @@ -226,4 +226,16 @@ void Img_UnPalettize24(int width, int height, const byte * restrict pic8in, // P void Img_UnPalettize16(int width, int height, const byte * restrict pic8in, // Palettized 8bits to RGBA 16bits (1-5-5-5). const u32 * restrict palette, byte * restrict pic16out); +/* + * Other image utilities: + */ + +// Scrap texture atlas allocation. This is based on the same atlas used by ref_gl. +// Returns null if the atlas is full, a unique ps2_teximage_t handle referencing the atlas otherwise. +ps2_teximage_t * Scrap_AllocBlock(const byte * pic8in, int w, int h, const char * pic_name); + +// Resize the input RGBA image using a box filter. Output and input must point to different buffers. +void Img_Resample32(const u32 * restrict in_img, int in_width, int in_height, + u32 * restrict out_img, int out_width, int out_height); + #endif // PS2_REFRESH_H diff --git a/src/ps2/sys_ps2.c b/src/ps2/sys_ps2.c index 616571c..8349404 100644 --- a/src/ps2/sys_ps2.c +++ b/src/ps2/sys_ps2.c @@ -24,6 +24,13 @@ // ref_ps2.c extern void PS2_RendererShutdown(void); +// The program code and static data will use a fair slice of +// the main memory at all times. This is a rough estimate of that. +enum +{ + PROG_MEGABYTES = 2 +}; + //============================================================================= // // System init/shutdown and misc helpers: @@ -77,6 +84,10 @@ void Sys_Init(void) // Load the built-in IOP modules we need for the game. Sys_LoadIOPModules(); + + // Add our estimate of the amount of memory used to allocate + // the program executable and all the prog data: + ps2_mem_tag_counts[MEMTAG_MISC] += (PROG_MEGABYTES * 1024 * 1024); } /* @@ -355,7 +366,7 @@ qboolean Sys_LoadBinaryFile(const char * filename, int * size_bytes, void ** dat fioLseek(fd, 0, SEEK_SET); // rewind // Alloc or fail with a Sys_Error. - file_data = PS2_MemAlloc(file_len, MEMTAG_FILESYS); + file_data = PS2_MemAlloc(file_len, MEMTAG_MISC); num_read = fioRead(fd, file_data, file_len); if (num_read != file_len) @@ -375,7 +386,7 @@ BAIL: { if (file_data != NULL) { - PS2_MemFree(file_data, MEMTAG_FILESYS); + PS2_MemFree(file_data, file_len, MEMTAG_MISC); file_data = NULL; } file_len = 0; diff --git a/src/ps2/tex_image.c b/src/ps2/tex_image.c index e55868e..812b567 100644 --- a/src/ps2/tex_image.c +++ b/src/ps2/tex_image.c @@ -182,17 +182,265 @@ ps2_teximage_t * PS2_TexImageAlloc(void) } //TODO assume always sequential, or allow empty gaps??? + // -- should also look into the registration_sequence trick used by ref_gl return &ps2ref.teximages[ps2ref.num_teximages++]; } /* ============== -Img_NameHash +Local helpers: +- IsPowerOfTwo +- RoundToPowerOfTwo +============== +*/ + +static inline int IsPowerOfTwo(int x) +{ + return (x > 0) && (x & (x - 1)) == 0; +} + +static inline int RoundToPowerOfTwo(int x) +{ + if (IsPowerOfTwo(x)) + { + return x; + } + + // Round nearest: + int k; + for (k = sizeof(int) * 8 - 1; ((1 << k) & x) == 0; --k) + { + } + + if (((1 << (k - 1)) & x) == 0) + { + return 1 << k; + } + + int pot = 1 << (k + 1); + return (pot < MAX_TEXIMAGE_SIZE) ? pot : MAX_TEXIMAGE_SIZE; + + // Round down: + /* + int p2; + for (p2 = 1; (p2 * 2) <= x; p2 <<= 1) { } + return (p2 < MAX_TEXIMAGE_SIZE) ? p2 : MAX_TEXIMAGE_SIZE; + */ +} + +/* +============== +PS2_Common8BitTexSetup +============== +*/ +static ps2_teximage_t * PS2_Common8BitTexSetup(const byte * pic8, int width, int height, const char * name, int flags) +{ + byte * expanded_pic; + byte * scaled_pic; + ps2_teximage_t * teximage; + + int psm = GS_PSM_16; + int format = TEXTURE_COMPONENTS_RGB; + int mag_filter = LOD_MAG_LINEAR; + int min_filter = LOD_MIN_LINEAR; + + // Clamp down to our size limit or round to PoT. This will also force RGBA32. + if (width > MAX_TEXIMAGE_SIZE || + height > MAX_TEXIMAGE_SIZE || + !IsPowerOfTwo(width) || + !IsPowerOfTwo(height)) + { + psm = GS_PSM_32; + format = TEXTURE_COMPONENTS_RGBA; + + const int scaled_width = (width >= MAX_TEXIMAGE_SIZE) ? MAX_TEXIMAGE_SIZE : RoundToPowerOfTwo(width); + const int scaled_height = (height >= MAX_TEXIMAGE_SIZE) ? MAX_TEXIMAGE_SIZE : RoundToPowerOfTwo(height); + + expanded_pic = PS2_MemAlloc(width * height * 4, MEMTAG_TEXIMAGE); + scaled_pic = PS2_MemAlloc(scaled_width * scaled_height * 4, MEMTAG_TEXIMAGE); + + Img_UnPalettize32(width, height, pic8, global_palette, expanded_pic); + Img_Resample32((u32 *)expanded_pic, width, height, (u32 *)scaled_pic, scaled_width, scaled_height); + + PS2_MemFree(expanded_pic, (width * height * 4), MEMTAG_TEXIMAGE); + + width = scaled_width; + height = scaled_height; + expanded_pic = scaled_pic; + } + else + { + int i; + const int pixel_count = width * height; + + // Check if the image has transparency, if so, we need 32bit color. + for (i = 0; i < pixel_count; ++i) + { + if (pic8[i] == 255) // Transparent color + { + // Need 32bit RGBA. + psm = GS_PSM_32; + format = TEXTURE_COMPONENTS_RGBA; + break; + } + } + + if (format == TEXTURE_COMPONENTS_RGBA) + { + expanded_pic = PS2_MemAlloc(width * height * 4, MEMTAG_TEXIMAGE); + Img_UnPalettize32(width, height, pic8, global_palette, expanded_pic); + } + else // Use more compact 16bit RGB color. + { + expanded_pic = PS2_MemAlloc(width * height * 2, MEMTAG_TEXIMAGE); + Img_UnPalettize16(width, height, pic8, global_palette, expanded_pic); + } + } + + // IT_BUILTIN is only used internally as a type. + // Can't be present if loaded from file, so mask it off. + const int img_type = flags & (~IT_BUILTIN); + + // Sprites can do with a cheaper filtering. + // Pics (2D UI elements and such) actually look better with nearest sampling. + if (img_type & (IT_PIC | IT_SPRITE)) + { + mag_filter = LOD_MAG_NEAREST; + min_filter = LOD_MIN_NEAREST; + } + + // Finally, allocate and set up the image handle: + teximage = PS2_TexImageAlloc(); + PS2_TexImageSetup(teximage, name, width, height, format, TEXTURE_FUNCTION_MODULATE, + psm, mag_filter, min_filter, (ps2_imagetype_t)img_type, expanded_pic); + + return teximage; +} + +/* +============== +PS2_LoadPcxImpl +============== +*/ +static ps2_teximage_t * PS2_LoadPcxImpl(const char * name, int flags) +{ + int width; + int height; + byte * pic8; + ps2_teximage_t * teximage = NULL; + + if (!PCX_LoadFromFile(name, &pic8, NULL, &width, &height)) + { + Com_DPrintf("WARNING: Can't load PCX pic for '%s'\n", name); + return NULL; + } + + // Try placing small images in the scrap atlas: + if ((flags & IT_PIC) && width <= 64 && height <= 166) + { + // Notice that we allow some pretty tall images (h <= 166). + // That's the size of m_main_plaque, the Quake2 logo on + // the main menu. This image was impossible to resize in + // a descent way on allocation, so I've change the atlas + // allocation criteria here to allow it's height, so it + // will not be a standalone image and won't require a resize. + teximage = Scrap_AllocBlock(pic8, width, height, name); + } + + // Atlas full or image too big, create a standalone texture: + if (teximage == NULL) + { + teximage = PS2_Common8BitTexSetup(pic8, width, height, name, flags); + } + + // The palettized image is no longer needed. + PS2_MemFree(pic8, width * height, MEMTAG_TEXIMAGE); + return teximage; +} + +/* +============== +PS2_LoadWalImpl +============== +*/ +static ps2_teximage_t * PS2_LoadWalImpl(const char * name, int flags) +{ + ps2_teximage_t * teximage; + const miptex_t * wall; + const byte * pic8; + int width; + int height; + int offset; + int data_len; + + data_len = FS_LoadFile(name, (void **)&wall); + if (wall == NULL || data_len <= 0) + { + Com_DPrintf("WARNING: Can't load WAL texture for '%s'\n", name); + return NULL; + } + + width = LittleLong(wall->width); + height = LittleLong(wall->height); + offset = LittleLong(wall->offsets[0]); + pic8 = (const byte *)wall + offset; + + teximage = PS2_Common8BitTexSetup(pic8, width, height, name, flags | IT_WALL); + + FS_FreeFile((void *)wall); + return teximage; +} + +/* +============== +PS2_LoadTgaImpl +============== +*/ +static ps2_teximage_t * PS2_LoadTgaImpl(const char * name, int flags) +{ + byte * pic32; + int width; + int height; + + if (!TGA_LoadFromFile(name, &pic32, &width, &height)) + { + Com_DPrintf("WARNING: Can't load TGA texture for '%s'\n", name); + return NULL; + } + + // IT_BUILTIN is only used internally as a type. + // Can't be present if loaded from file, so mask it off. + const int img_type = flags & (~IT_BUILTIN); + + // TGA defaults: + const int psm = GS_PSM_32; + const int format = TEXTURE_COMPONENTS_RGBA; + const int mag_filter = LOD_MAG_LINEAR; + const int min_filter = LOD_MIN_LINEAR; + + // + // TGAs are always expanded to RGBA, so no extra conversion is needed. + // + // NOTE: We assume TGAs will always be under the maximum texture size (256^2). + // This should be true, since TGAs are only used for the skyboxes in Quake2. + // If that assumption is violated, you'll get a Sys_Error in the image setup. + // + ps2_teximage_t * teximage = PS2_TexImageAlloc(); + PS2_TexImageSetup(teximage, name, width, height, format, TEXTURE_FUNCTION_MODULATE, + psm, mag_filter, min_filter, (ps2_imagetype_t)img_type, pic32); + + return teximage; +} + +/* +============== +PS2_ImageNameHash + OAT - One-At-a-Time hash of the filename of an image. https://en.wikipedia.org/wiki/Jenkins_hash_function ============== */ -static inline u32 Img_NameHash(const char * name) +static inline u32 PS2_ImageNameHash(const char * name) { u32 hash = 0; @@ -212,28 +460,30 @@ static inline u32 Img_NameHash(const char * name) /* ============== -Img_FindImpl +PS2_FindImageImpl ============== */ -static ps2_teximage_t * Img_FindImpl(const char * name, int flags) +static ps2_teximage_t * PS2_FindImageImpl(const char * name, int flags) { if (name == NULL) { - Com_DPrintf("FindImage: Null name!"); + Com_DPrintf("PS2_FindImageImpl: Null name!\n"); return NULL; } const u32 name_len = strlen(name); - if (name_len < 5) + if (name_len < 5 || name_len >= MAX_QPATH) { - Com_DPrintf("FindImage: Bad name, too short: %s", name); + Com_DPrintf("PS2_FindImageImpl: Bad image name: '%s'\n", name); return NULL; } // Compare by hash code, much cheaper. - const u32 name_hash = Img_NameHash(name); + const u32 name_hash = PS2_ImageNameHash(name); + // // First, lookup our cache: + // u32 i; const u32 num_teximages = ps2ref.num_teximages; ps2_teximage_t * teximages = ps2ref.teximages; @@ -246,7 +496,25 @@ static ps2_teximage_t * Img_FindImpl(const char * name, int flags) } } - //TODO load form file + // + // Load from file for the first time: + // + if (strcmp(name + name_len - 4, ".pcx") == 0) + { + return PS2_LoadPcxImpl(name, flags); + } + + if (strcmp(name + name_len - 4, ".wal") == 0) + { + return PS2_LoadWalImpl(name, flags); + } + + if (strcmp(name + name_len - 4, ".tga") == 0) + { + return PS2_LoadTgaImpl(name, flags); + } + + Com_DPrintf("WARNING: Unable to find image '%s'\n", name); return NULL; } @@ -260,17 +528,25 @@ ps2_teximage_t * PS2_TexImageFindOrLoad(const char * name, int flags) ps2_teximage_t * teximage; char fullname[MAX_QPATH]; - // This is the same logic used by ref_gl. - // If the name doesn't start with a path separator, its just the base - // filename, like "conchars", otherwise the full file path is specified in 'name'. - if (name[0] != '/' && name[0] != '\\') + if (flags & (IT_PIC | IT_BUILTIN)) { - Com_sprintf(fullname, sizeof(fullname), "pics/%s.pcx", name); - teximage = Img_FindImpl(fullname, flags); + // This is the same logic used by ref_gl. + // If the name doesn't start with a path separator, its just the base + // filename, like "conchars", otherwise the full file path is specified in 'name'. + if (name[0] != '/' && name[0] != '\\') + { + Com_sprintf(fullname, sizeof(fullname), "pics/%s.pcx", name); + teximage = PS2_FindImageImpl(fullname, flags); + } + else + { + teximage = PS2_FindImageImpl(name + 1, flags); + } } else { - teximage = Img_FindImpl(name + 1, flags); + // Skins, walls, etc. + teximage = PS2_FindImageImpl(name, flags); } return teximage; @@ -318,7 +594,7 @@ void PS2_TexImageSetup(ps2_teximage_t * teximage, const char * name, int w, int // Finally, copy and hash the name string: strncpy(teximage->name, name, MAX_QPATH); - teximage->hash = Img_NameHash(name); + teximage->hash = PS2_ImageNameHash(name); } /* @@ -331,12 +607,88 @@ void PS2_TexImageFree(ps2_teximage_t * teximage) // Built-ins will always be referencing static program data. if (teximage->pic != NULL && teximage->type != IT_BUILTIN) { - PS2_MemFree(teximage->pic, MEMTAG_TEXIMAGE); + int size_bytes; + switch (teximage->texbuf.psm) + { + case GS_PSM_32 : + size_bytes = (teximage->width * teximage->height * 4); + break; + case GS_PSM_16 : + size_bytes = (teximage->width * teximage->height * 2); + break; + default : // Assume 8bits palettized. + size_bytes = (teximage->width * teximage->height * 1); + break; + } // switch (teximage->texbuf.psm) + + PS2_MemFree(teximage->pic, size_bytes, MEMTAG_TEXIMAGE); } PS2_MemClearObj(teximage); } +/* +============== +Img_Resample32 + +Adapted from ref_gl GL_ResampleTexture. +NOTE: Input and out images must be different buffers! +============== +*/ +void Img_Resample32(const u32 * restrict in_img, int in_width, int in_height, + u32 * restrict out_img, int out_width, int out_height) +{ + int i, j; + u32 frac; + const u32 * inrow; + const u32 * inrow2; + const byte * pix1; + const byte * pix2; + const byte * pix3; + const byte * pix4; + + // 512 is the max output w|h. We only really use up to 256 (MAX_TEXIMAGE_SIZE). + u32 p1[512] __attribute__((aligned(16))); + u32 p2[512] __attribute__((aligned(16))); + + const u32 fracstep = in_width * 0x10000 / out_width; + + frac = fracstep >> 2; + for (i = 0; i < out_width; i++) + { + p1[i] = 4 * (frac >> 16); + frac += fracstep; + } + + frac = 3 * (fracstep >> 2); + for (i = 0; i < out_width; i++) + { + p2[i] = 4 * (frac >> 16); + frac += fracstep; + } + + // This is a box filter, I think... + for (i = 0; i < out_height; i++, out_img += out_width) + { + inrow = in_img + in_width * (int)((i + 0.25) * in_height / out_height); + inrow2 = in_img + in_width * (int)((i + 0.75) * in_height / out_height); + frac = fracstep >> 1; + + for (j = 0; j < out_width; j++) + { + pix1 = (const byte *)inrow + p1[j]; + pix2 = (const byte *)inrow + p2[j]; + pix3 = (const byte *)inrow2 + p1[j]; + pix4 = (const byte *)inrow2 + p2[j]; + + ((byte *)(out_img + j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2; + ((byte *)(out_img + j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2; + ((byte *)(out_img + j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2; + ((byte *)(out_img + j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3]) >> 2; + } + } +} + //============================================================================= // // Scrap allocation - AKA texture atlas @@ -435,6 +787,7 @@ ps2_teximage_t * Scrap_AllocBlock(const byte * pic8in, int w, int h, const char /* ============== PCX_LoadFromMemory + 'pic' and 'palette' can be null if you want to ignore one or the other. If 'palette' is not null, it must point to an array of 256 32bit integers. Mostly adapted from ref_gl/gl_image.c @@ -466,7 +819,7 @@ qboolean PCX_LoadFromMemory(const char * filename, const byte * data, int data_l if (manufacturer != 0x0A || version != 5 || encoding != 1 || bits_per_pixel != 8 || xmax >= 640 || ymax >= 480) { - Sys_Error("Bad PCX file %s. Invalid header value(s)!", filename); + Com_DPrintf("Bad PCX file %s. Invalid header value(s)!\n", filename); return false; } @@ -537,9 +890,12 @@ qboolean PCX_LoadFromMemory(const char * filename, const byte * data, int data_l if ((data - (const byte *)pcx) > data_len) { - Sys_Error("PCX image %s was malformed!", filename); - PS2_MemFree(*pic, MEMTAG_TEXIMAGE); + Com_DPrintf("PCX image %s was malformed!\n", filename); + + int size_bytes = (xmax + 1) * (ymax + 1); + PS2_MemFree(*pic, size_bytes, MEMTAG_TEXIMAGE); *pic = NULL; + return false; } @@ -549,6 +905,7 @@ qboolean PCX_LoadFromMemory(const char * filename, const byte * data, int data_l /* ============== PCX_LoadFromFile + Mostly adapted from ref_gl/gl_image.c ============== */ @@ -562,7 +919,7 @@ qboolean PCX_LoadFromFile(const char * filename, byte ** pic, data_len = FS_LoadFile(filename, (void **)&data); if (data == NULL || data_len <= 0) { - Sys_Error("Bad PCX file %s", filename); + Com_DPrintf("Bad PCX file '%s'\n", filename); return false; } @@ -572,6 +929,271 @@ qboolean PCX_LoadFromFile(const char * filename, byte ** pic, return result; } +//============================================================================= +// +// TGA image loading helpers: +// +//============================================================================= + +typedef struct +{ + byte id_length; + byte colormap_type; + byte image_type; + u16 colormap_index; + u16 colormap_length; + byte colormap_size; + u16 x_origin; + u16 y_origin; + u16 width; + u16 height; + byte pixel_size; + byte attributes; +} tga_header_t; + +/* +============== +TGA_LoadFromFile + +Mostly adapted from LoadTGA, ref_gl/gl_image.c +NOTE: Output image is always RGBA 32bits. +============== +*/ +qboolean TGA_LoadFromFile(const char * filename, byte ** pic, int * width, int * height) +{ + tga_header_t targa_header; + + int data_len; + int pixel_count; + int column, columns; + int row, rows; + + byte * pixbuf; + byte * buf_p; + byte * buffer; + byte * targa_rgba; + byte tmp[2]; + + *pic = NULL; + + data_len = FS_LoadFile(filename, (void **)&buffer); + if (buffer == NULL || data_len <= 0) + { + Com_DPrintf("Bad TGA file '%s'\n", filename); + return false; + } + + buf_p = buffer; + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + tmp[0] = buf_p[0]; + tmp[1] = buf_p[1]; + targa_header.colormap_index = LittleShort(*((short *)tmp)); + buf_p += 2; + + tmp[0] = buf_p[0]; + tmp[1] = buf_p[1]; + targa_header.colormap_length = LittleShort(*((short *)tmp)); + buf_p += 2; + + targa_header.colormap_size = *buf_p++; + + targa_header.x_origin = LittleShort(*((short *)buf_p)); + buf_p += 2; + + targa_header.y_origin = LittleShort(*((short *)buf_p)); + buf_p += 2; + + targa_header.width = LittleShort(*((short *)buf_p)); + buf_p += 2; + + targa_header.height = LittleShort(*((short *)buf_p)); + buf_p += 2; + + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + if (targa_header.image_type != 2 && targa_header.image_type != 10) + { + Com_DPrintf("TGA_LoadFromFile: Only type 2 and 10 targa RGB images supported! %s\n", filename); + FS_FreeFile(buffer); + return false; + } + + if (targa_header.colormap_type != 0 || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) + { + Com_DPrintf("TGA_LoadFromFile: Only 32 or 24 bit images supported (no colormaps)! %s\n", filename); + FS_FreeFile(buffer); + return false; + } + + columns = targa_header.width; + rows = targa_header.height; + pixel_count = columns * rows; + + if (width != NULL) + { + *width = columns; + } + if (height != NULL) + { + *height = rows; + } + + targa_rgba = PS2_MemAlloc(pixel_count * 4, MEMTAG_TEXIMAGE); + *pic = targa_rgba; + + if (targa_header.id_length != 0) + { + buf_p += targa_header.id_length; // skip TARGA image comment + } + + if (targa_header.image_type == 2) // Uncompressed, RGB images + { + for (row = rows - 1; row >= 0; --row) + { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns; ++column) + { + byte red, green, blue, alpha; + + switch (targa_header.pixel_size) + { + case 24 : + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + + case 32 : + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alpha = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alpha; + break; + } // switch + } + } + } + else if (targa_header.image_type == 10) // Run-length encoded RGB images + { + byte red, green, blue, alpha; + byte packetHeader, packetSize, j; + + for (row = rows - 1; row >= 0; --row) + { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns;) + { + packetHeader = *buf_p++; + packetSize = 1 + (packetHeader & 0x7F); + + if (packetHeader & 0x80) // Run-length packet + { + switch (targa_header.pixel_size) + { + case 24 : + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alpha = 255; + break; + + case 32 : + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alpha = *buf_p++; + break; + } // switch + + for (j = 0; j < packetSize; ++j) + { + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alpha; + + ++column; + if (column == columns) // run spans across rows + { + column = 0; + if (row > 0) + { + --row; + } + else + { + goto BREAKOUT; + } + pixbuf = targa_rgba + row * columns * 4; + } + } + } + else // Non run-length packet + { + for (j = 0; j < packetSize; ++j) + { + switch (targa_header.pixel_size) + { + case 24 : + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + + case 32 : + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alpha = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alpha; + break; + } // switch + + ++column; + if (column == columns) // pixel packet run spans across rows + { + column = 0; + if (row > 0) + { + --row; + } + else + { + goto BREAKOUT; + } + pixbuf = targa_rgba + row * columns * 4; + } + } + } + } + BREAKOUT: + ; + } + } + + FS_FreeFile(buffer); + return true; +} + //============================================================================= // // Palettized image expansion: @@ -581,7 +1203,8 @@ qboolean PCX_LoadFromFile(const char * filename, byte ** pic, /* ============== Img_UnPalettize32 -Base algorithm adapted from GL_Upload8 in ref_gl/gl_image.c + +Transparency algorithm adapted from GL_Upload8 in ref_gl/gl_image.c ============== */ void Img_UnPalettize32(int width, int height, const byte * restrict pic8in, diff --git a/src/ps2/vid_ps2.c b/src/ps2/vid_ps2.c index 85130d8..f0a7926 100644 --- a/src/ps2/vid_ps2.c +++ b/src/ps2/vid_ps2.c @@ -29,6 +29,8 @@ VID_MenuInit */ void VID_MenuInit(void) { + // TODO + // Video config menu for Quake2. } /* @@ -38,6 +40,8 @@ VID_MenuDraw */ void VID_MenuDraw(void) { + // TODO + // Video config menu for Quake2. } /* @@ -47,7 +51,8 @@ VID_MenuKey */ const char * VID_MenuKey(int k) { - return NULL; + // TODO + return NULL; // Video config menu for Quake2. } /* diff --git a/src/server/server.h b/src/server/server.h index b8fdc80..620a34a 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -255,9 +255,9 @@ void SV_Multicast(vec3_t origin, multicast_t to); void SV_StartSound(vec3_t origin, edict_t * entity, int channel, int soundindex, float volume, float attenuation, float timeofs); -void SV_ClientPrintf(client_t * cl, int level, char * fmt, ...); -void SV_BroadcastPrintf(int level, char * fmt, ...); -void SV_BroadcastCommand(char * fmt, ...); +void SV_ClientPrintf(client_t * cl, int level, const char * fmt, ...); +void SV_BroadcastPrintf(int level, const char * fmt, ...); +void SV_BroadcastCommand(const char * fmt, ...); // // sv_user.c diff --git a/src/server/sv_ccmds.c b/src/server/sv_ccmds.c index 8cb5bcf..a3a3a94 100644 --- a/src/server/sv_ccmds.c +++ b/src/server/sv_ccmds.c @@ -512,7 +512,7 @@ void SV_GameMap_f(void) // clear all the client inuse flags before saving so that // when the level is re-entered, the clients will spawn // at spawn points instead of occupying body shells - savedInuse = malloc(maxclients->value * sizeof(qboolean)); + savedInuse = Z_Malloc(maxclients->value * sizeof(qboolean)); for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) { savedInuse[i] = cl->edict->inuse; @@ -523,8 +523,11 @@ void SV_GameMap_f(void) // we must restore these for clients to transfer over correctly for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) + { cl->edict->inuse = savedInuse[i]; - free(savedInuse); + } + + Z_Free(savedInuse); } } diff --git a/src/server/sv_game.c b/src/server/sv_game.c index edca285..bd92457 100644 --- a/src/server/sv_game.c +++ b/src/server/sv_game.c @@ -59,7 +59,7 @@ PF_dprintf Debug print to server console =============== */ -void PF_dprintf(char * fmt, ...) +void PF_dprintf(const char * fmt, ...) { char msg[1024]; va_list argptr; @@ -78,7 +78,7 @@ PF_cprintf Print to a single client =============== */ -void PF_cprintf(edict_t * ent, int level, char * fmt, ...) +void PF_cprintf(edict_t * ent, int level, const char * fmt, ...) { char msg[1024]; va_list argptr; @@ -114,7 +114,7 @@ PF_centerprintf centerprint to a single client =============== */ -void PF_centerprintf(edict_t * ent, char * fmt, ...) +void PF_centerprintf(edict_t * ent, const char * fmt, ...) { char msg[1024]; va_list argptr; @@ -142,7 +142,7 @@ PF_error Abort the server with a game error =============== */ -void PF_error(char * fmt, ...) +void PF_error(const char * fmt, ...) { char msg[1024]; va_list argptr; diff --git a/src/server/sv_init.c b/src/server/sv_init.c index 093cf0b..78cc89b 100644 --- a/src/server/sv_init.c +++ b/src/server/sv_init.c @@ -247,11 +247,15 @@ void SV_SpawnServer(char * server, char * spawnpoint, server_state_t serverstate } else { - Com_sprintf(sv.configstrings[CS_MODELS + 1], sizeof(sv.configstrings[CS_MODELS + 1]), + Com_sprintf(sv.configstrings[CS_MODELS + 1], + sizeof(sv.configstrings[CS_MODELS + 1]), "maps/%s.bsp", server); + sv.models[1] = CM_LoadMap(sv.configstrings[CS_MODELS + 1], false, &checksum); } - Com_sprintf(sv.configstrings[CS_MAPCHECKSUM], sizeof(sv.configstrings[CS_MAPCHECKSUM]), + + Com_sprintf(sv.configstrings[CS_MAPCHECKSUM], + sizeof(sv.configstrings[CS_MAPCHECKSUM]), "%i", checksum); // @@ -261,8 +265,10 @@ void SV_SpawnServer(char * server, char * spawnpoint, server_state_t serverstate for (i = 1; i < CM_NumInlineModels(); i++) { - Com_sprintf(sv.configstrings[CS_MODELS + 1 + i], sizeof(sv.configstrings[CS_MODELS + 1 + i]), + Com_sprintf(sv.configstrings[CS_MODELS + 1 + i], + sizeof(sv.configstrings[CS_MODELS + 1 + i]), "*%i", i); + sv.models[i + 1] = CM_InlineModel(sv.configstrings[CS_MODELS + 1 + i]); } diff --git a/src/server/sv_main.c b/src/server/sv_main.c index 1579c69..ec68c92 100644 --- a/src/server/sv_main.c +++ b/src/server/sv_main.c @@ -734,7 +734,6 @@ void SV_RunGameFrame(void) /* ================== SV_Frame - ================== */ void SV_Frame(int msec) diff --git a/src/server/sv_send.c b/src/server/sv_send.c index ee8219d..cfd1ca9 100644 --- a/src/server/sv_send.c +++ b/src/server/sv_send.c @@ -60,7 +60,7 @@ SV_ClientPrintf Sends text across to be displayed if the level passes ================= */ -void SV_ClientPrintf(client_t * cl, int level, char * fmt, ...) +void SV_ClientPrintf(client_t * cl, int level, const char * fmt, ...) { va_list argptr; char string[1024]; @@ -84,7 +84,7 @@ SV_BroadcastPrintf Sends text to all active clients ================= */ -void SV_BroadcastPrintf(int level, char * fmt, ...) +void SV_BroadcastPrintf(int level, const char * fmt, ...) { va_list argptr; char string[2048]; @@ -128,7 +128,7 @@ SV_BroadcastCommand Sends text to all active clients ================= */ -void SV_BroadcastCommand(char * fmt, ...) +void SV_BroadcastCommand(const char * fmt, ...) { va_list argptr; char string[1024]; @@ -492,7 +492,9 @@ void SV_SendClientMessages(void) if (sv.state == ss_demo && sv.demofile) { if (sv_paused->value) + { msglen = 0; + } else { // get the next message @@ -510,6 +512,7 @@ void SV_SendClientMessages(void) } if (msglen > MAX_MSGLEN) Com_Error(ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN"); + r = fread(msgbuf, msglen, 1, sv.demofile); if (r != 1) { @@ -535,7 +538,9 @@ void SV_SendClientMessages(void) } if (sv.state == ss_cinematic || sv.state == ss_demo || sv.state == ss_pic) + { Netchan_Transmit(&c->netchan, msglen, msgbuf); + } else if (c->state == cs_spawned) { // don't overrun bandwidth diff --git a/src/server/sv_user.c b/src/server/sv_user.c index 0ea5442..0822dac 100644 --- a/src/server/sv_user.c +++ b/src/server/sv_user.c @@ -43,8 +43,11 @@ void SV_BeginDemoserver(void) Com_sprintf(name, sizeof(name), "demos/%s", sv.name); FS_FOpenFile(name, &sv.demofile); + if (!sv.demofile) + { Com_Error(ERR_DROP, "Couldn't open %s\n", name); + } } /* @@ -93,6 +96,7 @@ void SV_New_f(void) playernum = -1; else playernum = sv_client - svs.clients; + MSG_WriteShort(&sv_client->netchan.message, playernum); // send full levelname @@ -408,12 +412,16 @@ void SV_Nextserver(void) //ZOID, ss_pic can be nextserver'd in coop mode if (sv.state == ss_game || (sv.state == ss_pic && !Cvar_VariableValue("coop"))) + { return; // can't nextserver while playing a normal game + } svs.spawncount++; // make sure another doesn't sneak in v = Cvar_VariableString("nextserver"); if (!v[0]) + { Cbuf_AddText("killserver\n"); + } else { Cbuf_AddText(v);