Merge remote-tracking branch 'remotes/pub/next' into followme

# Conflicts:
#	src/r_things.h
This commit is contained in:
wolfy852 2019-05-11 02:05:58 -05:00
commit 5d7b7afd17
79 changed files with 5111 additions and 1999 deletions

View file

@ -401,7 +401,11 @@ if(${SRB2_CONFIG_HWRENDER})
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_trick.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_trick.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.c
) )
set (SRB2_HWRENDER_HEADERS set (SRB2_HWRENDER_HEADERS
@ -415,6 +419,10 @@ if(${SRB2_CONFIG_HWRENDER})
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.h
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.h
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.h
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.h
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.h
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.h
${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.h
) )
set(SRB2_R_OPENGL_SOURCES set(SRB2_R_OPENGL_SOURCES

View file

@ -282,7 +282,8 @@ ifndef DC
endif endif
OPTS+=-DHWRENDER OPTS+=-DHWRENDER
OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \ OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \
$(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o $(OBJDIR)/hw_trick.o $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o $(OBJDIR)/hw_trick.o \
$(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o
endif endif
ifdef NOHS ifdef NOHS
@ -741,16 +742,18 @@ ifdef MINGW
$(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \
doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \
command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \
hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \
d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \
am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \
p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h
$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
else else
$(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \
doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \
command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \
hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \
d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \
am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \
p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h
$(CC) $(CFLAGS) $(WFLAGS) -I/usr/X11R6/include -c $< -o $@ $(CC) $(CFLAGS) $(WFLAGS) -I/usr/X11R6/include -c $< -o $@
endif endif
@ -902,24 +905,27 @@ ifndef NOHW
$(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \
doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \
command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \
hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \
d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \
am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \
p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h
$(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@ $(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@
$(OBJDIR)/ogl_win.o: hardware/r_opengl/ogl_win.c hardware/r_opengl/r_opengl.h \ $(OBJDIR)/ogl_win.o: hardware/r_opengl/ogl_win.c hardware/r_opengl/r_opengl.h \
doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \
command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \
hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \
d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \
am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \
p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h
$(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@ $(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@
$(OBJDIR)/r_minigl.o: hardware/r_minigl/r_minigl.c hardware/r_opengl/r_opengl.h \ $(OBJDIR)/r_minigl.o: hardware/r_minigl/r_minigl.c hardware/r_opengl/r_opengl.h \
doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \
command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \
hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \
d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \
am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \
p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h
$(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@ $(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@
endif endif

View file

@ -96,6 +96,37 @@ boolean I_SetSongSpeed(float speed)
return false; return false;
} }
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
return 0;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
(void)position;
return false;
}
UINT32 I_GetSongPosition(void)
{
return 0;
}
/// ------------------------ /// ------------------------
// MUSIC PLAYBACK // MUSIC PLAYBACK
/// ------------------------ /// ------------------------
@ -140,3 +171,44 @@ void I_SetMusicVolume(INT32 volume)
{ {
(void)volume; (void)volume;
} }
/// ------------------------
// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)source_volume;
(void)ms;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)ms;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}

View file

@ -50,6 +50,7 @@ static void COM_Exec_f(void);
static void COM_Wait_f(void); static void COM_Wait_f(void);
static void COM_Help_f(void); static void COM_Help_f(void);
static void COM_Toggle_f(void); static void COM_Toggle_f(void);
static void COM_Add_f(void);
static void CV_EnforceExecVersion(void); static void CV_EnforceExecVersion(void);
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr); static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr);
@ -156,6 +157,20 @@ void COM_BufInsertText(const char *ptext)
} }
} }
/** Progress the wait timer and flush waiting console commands when ready.
*/
void
COM_BufTicker(void)
{
if (com_wait)
{
com_wait--;
return;
}
COM_BufExecute();
}
/** Flushes (executes) console commands in the buffer. /** Flushes (executes) console commands in the buffer.
*/ */
void COM_BufExecute(void) void COM_BufExecute(void)
@ -165,12 +180,6 @@ void COM_BufExecute(void)
char line[1024] = ""; char line[1024] = "";
INT32 quotes; INT32 quotes;
if (com_wait)
{
com_wait--;
return;
}
while (com_text.cursize) while (com_text.cursize)
{ {
// find a '\n' or; line break // find a '\n' or; line break
@ -291,6 +300,7 @@ void COM_Init(void)
COM_AddCommand("wait", COM_Wait_f); COM_AddCommand("wait", COM_Wait_f);
COM_AddCommand("help", COM_Help_f); COM_AddCommand("help", COM_Help_f);
COM_AddCommand("toggle", COM_Toggle_f); COM_AddCommand("toggle", COM_Toggle_f);
COM_AddCommand("add", COM_Add_f);
RegisterNetXCmd(XD_NETVAR, Got_NetVar); RegisterNetXCmd(XD_NETVAR, Got_NetVar);
} }
@ -537,10 +547,41 @@ static void COM_ExecuteString(char *ptext)
{ {
CONS_Alert(CONS_WARNING, M_GetText("Alias recursion cycle detected!\n")); CONS_Alert(CONS_WARNING, M_GetText("Alias recursion cycle detected!\n"));
recursion = 0; recursion = 0;
return;
} }
recursion++; else
COM_BufInsertText(a->value); {
char buf[1024];
char *write = buf, *read = a->value, *seek = read;
while ((seek = strchr(seek, '$')) != NULL)
{
memcpy(write, read, seek-read);
write += seek-read;
seek++;
if (*seek >= '1' && *seek <= '9')
{
if (com_argc > (size_t)(*seek - '0'))
{
memcpy(write, com_argv[*seek - '0'], strlen(com_argv[*seek - '0']));
write += strlen(com_argv[*seek - '0']);
}
seek++;
}
else
{
*write = '$';
write++;
}
read = seek;
}
WRITESTRING(write, read);
recursion++;
COM_BufInsertText(buf);
}
return; return;
} }
} }
@ -563,8 +604,6 @@ static void COM_ExecuteString(char *ptext)
static void COM_Alias_f(void) static void COM_Alias_f(void)
{ {
cmdalias_t *a; cmdalias_t *a;
char cmd[1024];
size_t i, c;
if (COM_Argc() < 3) if (COM_Argc() < 3)
{ {
@ -577,19 +616,9 @@ static void COM_Alias_f(void)
com_alias = a; com_alias = a;
a->name = Z_StrDup(COM_Argv(1)); a->name = Z_StrDup(COM_Argv(1));
// Just use arg 2 if it's the only other argument, in case the alias is wrapped in quotes (backward compat, or multiple commands in one string).
// copy the rest of the command line // Otherwise pull the whole string and seek to the end of the alias name. The strctr is in case the alias is quoted.
cmd[0] = 0; // start out with a null string a->value = Z_StrDup(COM_Argc() == 3 ? COM_Argv(2) : (strchr(COM_Args() + strlen(a->name), ' ') + 1));
c = COM_Argc();
for (i = 2; i < c; i++)
{
strcat(cmd, COM_Argv(i));
if (i != c)
strcat(cmd, " ");
}
strcat(cmd, "\n");
a->value = Z_StrDup(cmd);
} }
/** Prints a line of text to the console. /** Prints a line of text to the console.
@ -855,6 +884,27 @@ static void COM_Toggle_f(void)
CV_AddValue(cvar, +1); CV_AddValue(cvar, +1);
} }
/** Command variant of CV_AddValue
*/
static void COM_Add_f(void)
{
consvar_t *cvar;
if (COM_Argc() != 3)
{
CONS_Printf(M_GetText("Add <cvar_name> <value>: Add to the value of a cvar. Negative values work too!\n"));
return;
}
cvar = CV_FindVar(COM_Argv(1));
if (!cvar)
{
CONS_Alert(CONS_NOTICE, M_GetText("%s is not a cvar\n"), COM_Argv(1));
return;
}
CV_AddValue(cvar, atoi(COM_Argv(2)));
}
// ========================================================================= // =========================================================================
// VARIABLE SIZE BUFFERS // VARIABLE SIZE BUFFERS
// ========================================================================= // =========================================================================

View file

@ -45,6 +45,9 @@ void COM_ImmedExecute(const char *ptext);
// Execute commands in buffer, flush them // Execute commands in buffer, flush them
void COM_BufExecute(void); void COM_BufExecute(void);
// As above; and progress the wait timer.
void COM_BufTicker(void);
// setup command buffer, at game tartup // setup command buffer, at game tartup
void COM_Init(void); void COM_Init(void);

View file

@ -96,6 +96,7 @@ static size_t input_len; // length of current line, used to bound cursor and suc
// protos. // protos.
static void CON_InputInit(void); static void CON_InputInit(void);
static void CON_RecalcSize(void); static void CON_RecalcSize(void);
static void CON_ChangeHeight(void);
static void CONS_hudlines_Change(void); static void CONS_hudlines_Change(void);
static void CONS_backcolor_Change(void); static void CONS_backcolor_Change(void);
@ -467,6 +468,12 @@ static void CON_RecalcSize(void)
con_destlines = vid.height; con_destlines = vid.height;
} }
if (con_destlines > 0) // Resize console if already open
{
CON_ChangeHeight();
con_curlines = con_destlines;
}
// check for change of video width // check for change of video width
if (conw == con_width) if (conw == con_width)
return; // didn't change return; // didn't change
@ -516,6 +523,20 @@ static void CON_RecalcSize(void)
Z_Free(tmp_buffer); Z_Free(tmp_buffer);
} }
static void CON_ChangeHeight(void)
{
INT32 minheight = 20 * con_scalefactor; // 20 = 8+8+4
// toggle console in
con_destlines = (cons_height.value*vid.height)/100;
if (con_destlines < minheight)
con_destlines = minheight;
else if (con_destlines > vid.height)
con_destlines = vid.height;
con_destlines &= ~0x3; // multiple of text row height
}
// Handles Console moves in/out of screen (per frame) // Handles Console moves in/out of screen (per frame)
// //
static void CON_MoveConsole(void) static void CON_MoveConsole(void)
@ -620,16 +641,7 @@ void CON_Ticker(void)
CON_ClearHUD(); CON_ClearHUD();
} }
else else
{ CON_ChangeHeight();
// toggle console in
con_destlines = (cons_height.value*vid.height)/100;
if (con_destlines < minheight)
con_destlines = minheight;
else if (con_destlines > vid.height)
con_destlines = vid.height;
con_destlines &= ~0x3; // multiple of text row height
}
} }
// console movement // console movement
@ -1149,6 +1161,7 @@ static void CON_Print(char *msg)
{ {
size_t l; size_t l;
INT32 controlchars = 0; // for color changing INT32 controlchars = 0; // for color changing
char color = '\x80'; // keep color across lines
if (msg == NULL) if (msg == NULL)
return; return;
@ -1174,7 +1187,7 @@ static void CON_Print(char *msg)
{ {
if (*msg & 0x80) if (*msg & 0x80)
{ {
con_line[con_cx++] = *(msg++); color = con_line[con_cx++] = *(msg++);
controlchars++; controlchars++;
continue; continue;
} }
@ -1182,12 +1195,14 @@ static void CON_Print(char *msg)
{ {
con_cy--; con_cy--;
CON_Linefeed(); CON_Linefeed();
color = '\x80';
controlchars = 0; controlchars = 0;
} }
else if (*msg == '\n') // linefeed else if (*msg == '\n') // linefeed
{ {
CON_Linefeed(); CON_Linefeed();
controlchars = 0; con_line[con_cx++] = color;
controlchars = 1;
} }
else if (*msg == ' ') // space else if (*msg == ' ') // space
{ {
@ -1195,7 +1210,8 @@ static void CON_Print(char *msg)
if (con_cx - controlchars >= con_width-11) if (con_cx - controlchars >= con_width-11)
{ {
CON_Linefeed(); CON_Linefeed();
controlchars = 0; con_line[con_cx++] = color;
controlchars = 1;
} }
} }
else if (*msg == '\t') else if (*msg == '\t')
@ -1210,7 +1226,8 @@ static void CON_Print(char *msg)
if (con_cx - controlchars >= con_width-11) if (con_cx - controlchars >= con_width-11)
{ {
CON_Linefeed(); CON_Linefeed();
controlchars = 0; con_line[con_cx++] = color;
controlchars = 1;
} }
} }
msg++; msg++;
@ -1227,7 +1244,8 @@ static void CON_Print(char *msg)
if ((con_cx - controlchars) + l > con_width-11) if ((con_cx - controlchars) + l > con_width-11)
{ {
CON_Linefeed(); CON_Linefeed();
controlchars = 0; con_line[con_cx++] = color;
controlchars = 1;
} }
// a word at a time // a word at a time
@ -1582,8 +1600,7 @@ static void CON_DrawConsole(void)
i = con_cy - con_scrollup; i = con_cy - con_scrollup;
// skip the last empty line due to the cursor being at the start of a new line // skip the last empty line due to the cursor being at the start of a new line
if (!con_scrollup && !con_cx) i--;
i--;
i -= (con_curlines - minheight) / charheight; i -= (con_curlines - minheight) / charheight;

View file

@ -91,12 +91,10 @@ tic_t jointimeout = (3*TICRATE);
static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame? static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame?
static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout?
#ifdef NEWPING
UINT16 pingmeasurecount = 1; UINT16 pingmeasurecount = 1;
UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone.
UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values.
tic_t servermaxping = 800; // server's max ping. Defaults to 800 tic_t servermaxping = 800; // server's max ping. Defaults to 800
#endif
SINT8 nodetoplayer[MAXNETNODES]; SINT8 nodetoplayer[MAXNETNODES];
SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
SINT8 nodetoplayer3[MAXNETNODES]; // say the numplayer for this node if any (splitscreen == 2) SINT8 nodetoplayer3[MAXNETNODES]; // say the numplayer for this node if any (splitscreen == 2)
@ -167,7 +165,7 @@ ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL};
consvar_t cv_showjoinaddress = {"showjoinaddress", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_showjoinaddress = {"showjoinaddress", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}};
consvar_t cv_playbackspeed = {"playbackspeed", "1", 0, playbackspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_playbackspeed = {"playbackspeed", "1", 0, playbackspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -1451,33 +1449,13 @@ static void SV_SendPlayerInfo(INT32 node)
continue; continue;
} }
netbuffer->u.playerinfo[i].node = (UINT8)playernode[i]; netbuffer->u.playerinfo[i].node = i;
strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1); strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1);
netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0'; netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0';
//fetch IP address //fetch IP address
{ //No, don't do that, you fuckface.
const char *claddress; memset(netbuffer->u.playerinfo[i].address, 0, 4);
UINT32 numericaddress[4];
memset(netbuffer->u.playerinfo[i].address, 0, 4);
if (playernode[i] == 0)
{
//127.0.0.1
netbuffer->u.playerinfo[i].address[0] = 127;
netbuffer->u.playerinfo[i].address[3] = 1;
}
else if (playernode[i] > 0 && I_GetNodeAddress && (claddress = I_GetNodeAddress(playernode[i])) != NULL)
{
if (sscanf(claddress, "%d.%d.%d.%d", &numericaddress[0], &numericaddress[1], &numericaddress[2], &numericaddress[3]) < 4)
goto badaddress;
netbuffer->u.playerinfo[i].address[0] = (UINT8)numericaddress[0];
netbuffer->u.playerinfo[i].address[1] = (UINT8)numericaddress[1];
netbuffer->u.playerinfo[i].address[2] = (UINT8)numericaddress[2];
netbuffer->u.playerinfo[i].address[3] = (UINT8)numericaddress[3];
}
}
badaddress:
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
{ {
@ -2318,17 +2296,11 @@ static void CL_ConnectToServer(boolean viams)
if (i != -1) if (i != -1)
{ {
INT32 j; UINT8 num = serverlist[i].info.gametype;
const char *gametypestr = NULL; const char *gametypestr = NULL;
CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername);
for (j = 0; gametype_cons_t[j].strvalue; j++) if (num < NUMGAMETYPES)
{ gametypestr = Gametype_Names[num];
if (gametype_cons_t[j].value == serverlist[i].info.gametype)
{
gametypestr = gametype_cons_t[j].strvalue;
break;
}
}
if (gametypestr) if (gametypestr)
CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr);
CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100, CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100,
@ -3094,12 +3066,10 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false); HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false);
kickreason = KR_KICK; kickreason = KR_KICK;
break; break;
#ifdef NEWPING
case KICK_MSG_PING_HIGH: case KICK_MSG_PING_HIGH:
HU_AddChatText(va("\x82*%s left the game (Broke ping limit)", player_names[pnum]), false); HU_AddChatText(va("\x82*%s left the game (Broke ping limit)", player_names[pnum]), false);
kickreason = KR_PINGLIMIT; kickreason = KR_PINGLIMIT;
break; break;
#endif
case KICK_MSG_CON_FAIL: case KICK_MSG_CON_FAIL:
HU_AddChatText(va("\x82*%s left the game (Synch Failure)", player_names[pnum]), false); HU_AddChatText(va("\x82*%s left the game (Synch Failure)", player_names[pnum]), false);
kickreason = KR_SYNCH; kickreason = KR_SYNCH;
@ -3172,10 +3142,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
D_StartTitle(); D_StartTitle();
if (msg == KICK_MSG_CON_FAIL) if (msg == KICK_MSG_CON_FAIL)
M_StartMessage(M_GetText("Server closed connection\n(Synch failure)\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("Server closed connection\n(Synch failure)\nPress ESC\n"), NULL, MM_NOTHING);
#ifdef NEWPING
else if (msg == KICK_MSG_PING_HIGH) else if (msg == KICK_MSG_PING_HIGH)
M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING);
#endif
else if (msg == KICK_MSG_BANNED) else if (msg == KICK_MSG_BANNED)
M_StartMessage(M_GetText("You have been banned by the server\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("You have been banned by the server\n\nPress ESC\n"), NULL, MM_NOTHING);
else if (msg == KICK_MSG_CUSTOM_KICK) else if (msg == KICK_MSG_CUSTOM_KICK)
@ -3219,15 +3187,15 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}};
consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
#ifdef VANILLAJOINNEXTROUND #ifdef VANILLAJOINNEXTROUND
consvar_t cv_joinnextround = {"joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done
#endif #endif
static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {MAXPLAYERS, "MAX"}, {0, NULL}}; static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {MAXPLAYERS, "MAX"}, {0, NULL}};
consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t resynchattempts_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}}; static CV_PossibleValue_t resynchattempts_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}};
consvar_t cv_resynchattempts = {"resynchattempts", "5", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL }; consvar_t cv_resynchattempts = {"resynchattempts", "5", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
consvar_t cv_blamecfail = {"blamecfail", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; consvar_t cv_blamecfail = {"blamecfail", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
// max file size to send to a player (in kilobytes) // max file size to send to a player (in kilobytes)
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}}; static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
@ -3270,12 +3238,6 @@ void D_ClientServerInit(void)
RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer);
RegisterNetXCmd(XD_REMOVEPLAYER, Got_RemovePlayer); RegisterNetXCmd(XD_REMOVEPLAYER, Got_RemovePlayer);
#ifndef NONET #ifndef NONET
CV_RegisterVar(&cv_allownewplayer);
#ifdef VANILLAJOINNEXTROUND
CV_RegisterVar(&cv_joinnextround);
#endif
CV_RegisterVar(&cv_showjoinaddress);
CV_RegisterVar(&cv_blamecfail);
#ifdef DUMPCONSISTENCY #ifdef DUMPCONSISTENCY
CV_RegisterVar(&cv_dumpconsistency); CV_RegisterVar(&cv_dumpconsistency);
#endif #endif
@ -4630,7 +4592,6 @@ FILESTAMP
resynch_local_inprogress = true; resynch_local_inprogress = true;
CL_AcknowledgeResynch(&netbuffer->u.resynchpak); CL_AcknowledgeResynch(&netbuffer->u.resynchpak);
break; break;
#ifdef NEWPING
case PT_PING: case PT_PING:
// Only accept PT_PING from the server. // Only accept PT_PING from the server.
if (node != servernode) if (node != servernode)
@ -4660,7 +4621,6 @@ FILESTAMP
} }
break; break;
#endif
case PT_SERVERCFG: case PT_SERVERCFG:
break; break;
case PT_FILEFRAGMENT: case PT_FILEFRAGMENT:
@ -5232,7 +5192,7 @@ void TryRunTics(tic_t realtics)
if (realtics >= 1) if (realtics >= 1)
{ {
COM_BufExecute(); COM_BufTicker();
if (mapchangepending) if (mapchangepending)
D_MapChange(-1, 0, encoremode, false, 2, false, fromlevelselect); // finish the map change D_MapChange(-1, 0, encoremode, false, 2, false, fromlevelselect); // finish the map change
} }
@ -5298,7 +5258,6 @@ void TryRunTics(tic_t realtics)
} }
} }
#ifdef NEWPING
/* Ping Update except better: /* Ping Update except better:
We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out.
@ -5382,11 +5341,9 @@ static inline void PingUpdate(void)
pingmeasurecount = 1; //Reset count pingmeasurecount = 1; //Reset count
} }
#endif
static tic_t gametime = 0; static tic_t gametime = 0;
#ifdef NEWPING
static void UpdatePingTable(void) static void UpdatePingTable(void)
{ {
INT32 i; INT32 i;
@ -5401,7 +5358,6 @@ static void UpdatePingTable(void)
pingmeasurecount++; pingmeasurecount++;
} }
} }
#endif
// Handle timeouts to prevent definitive freezes from happenning // Handle timeouts to prevent definitive freezes from happenning
static void HandleNodeTimeouts(void) static void HandleNodeTimeouts(void)
@ -5426,9 +5382,7 @@ void NetKeepAlive(void)
if (realtics <= 0) // nothing new to update if (realtics <= 0) // nothing new to update
return; return;
#ifdef NEWPING
UpdatePingTable(); UpdatePingTable();
#endif
if (server) if (server)
CL_SendClientKeepAlive(); CL_SendClientKeepAlive();
@ -5475,9 +5429,7 @@ void NetUpdate(void)
gametime = nowtime; gametime = nowtime;
#ifdef NEWPING
UpdatePingTable(); UpdatePingTable();
#endif
if (client) if (client)
maketic = neededtic; maketic = neededtic;

View file

@ -93,9 +93,7 @@ typedef enum
PT_NODETIMEOUT, // Packet sent to self if the connection times out. PT_NODETIMEOUT, // Packet sent to self if the connection times out.
PT_RESYNCHING, // Packet sent to resync players. PT_RESYNCHING, // Packet sent to resync players.
// Blocks game advance until synched. // Blocks game advance until synched.
#ifdef NEWPING
PT_PING, // Packet sent to tell clients the other client's latency to server. PT_PING, // Packet sent to tell clients the other client's latency to server.
#endif
NUMPACKETTYPE NUMPACKETTYPE
} packettype_t; } packettype_t;
@ -473,9 +471,7 @@ typedef struct
msaskinfo_pak msaskinfo; // 22 bytes msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?)
#ifdef NEWPING
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
#endif
} u; // This is needed to pack diff packet types data together } u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t; } ATTRPACK doomdata_t;
@ -509,9 +505,7 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_PLAYER_QUIT 3 #define KICK_MSG_PLAYER_QUIT 3
#define KICK_MSG_TIMEOUT 4 #define KICK_MSG_TIMEOUT 4
#define KICK_MSG_BANNED 5 #define KICK_MSG_BANNED 5
#ifdef NEWPING
#define KICK_MSG_PING_HIGH 6 #define KICK_MSG_PING_HIGH 6
#endif
#define KICK_MSG_CUSTOM_KICK 7 #define KICK_MSG_CUSTOM_KICK 7
#define KICK_MSG_CUSTOM_BAN 8 #define KICK_MSG_CUSTOM_BAN 8
@ -536,12 +530,10 @@ extern SINT8 servernode;
void Command_Ping_f(void); void Command_Ping_f(void);
extern tic_t connectiontimeout; extern tic_t connectiontimeout;
extern tic_t jointimeout; extern tic_t jointimeout;
#ifdef NEWPING
extern UINT16 pingmeasurecount; extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping; extern tic_t servermaxping;
#endif
extern consvar_t extern consvar_t
#ifdef VANILLAJOINNEXTROUND #ifdef VANILLAJOINNEXTROUND

View file

@ -636,9 +636,6 @@ void D_SRB2Loop(void)
if (dedicated) if (dedicated)
server = true; server = true;
if (M_CheckParm("-voodoo")) // 256x256 Texture Limiter
COM_BufAddText("gr_voodoocompatibility on\n");
// Pushing of + parameters is now done back in D_SRB2Main, not here. // Pushing of + parameters is now done back in D_SRB2Main, not here.
CONS_Printf("I_StartupKeyboard()...\n"); CONS_Printf("I_StartupKeyboard()...\n");
@ -820,7 +817,6 @@ void D_StartTitle(void)
paused = false; paused = false;
advancedemo = false; advancedemo = false;
F_StartTitleScreen(); F_StartTitleScreen();
CON_ToggleOff();
// Reset the palette -- SRB2Kart: actually never mind let's do this in the middle of every fade // Reset the palette -- SRB2Kart: actually never mind let's do this in the middle of every fade
/*if (rendermode != render_none) /*if (rendermode != render_none)
@ -1218,6 +1214,10 @@ void D_SRB2Main(void)
// Setup default unlockable conditions // Setup default unlockable conditions
M_SetupDefaultConditionSets(); M_SetupDefaultConditionSets();
// Setup character tables
// Have to be done here before files are loaded
M_InitCharacterTables();
// load wad, including the main wad file // load wad, including the main wad file
CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n"); CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n");
if (!W_InitMultipleFiles(startupwadfiles, false)) if (!W_InitMultipleFiles(startupwadfiles, false))
@ -1391,10 +1391,9 @@ void D_SRB2Main(void)
midi_disabled = true; midi_disabled = true;
#endif #endif
} }
if (M_CheckParm("-nosound")) if (M_CheckParm("-noaudio")) // combines -nosound and -nomusic
sound_disabled = true;
if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic
{ {
sound_disabled = true;
digital_disabled = true; digital_disabled = true;
#ifndef NO_MIDI #ifndef NO_MIDI
midi_disabled = true; midi_disabled = true;
@ -1402,12 +1401,24 @@ void D_SRB2Main(void)
} }
else else
{ {
if (M_CheckParm("-nosound"))
sound_disabled = true;
if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic
{
digital_disabled = true;
#ifndef NO_MIDI #ifndef NO_MIDI
if (M_CheckParm("-nomidimusic")) midi_disabled = true;
midi_disabled = true; // WARNING: DOS version initmusic in I_StartupSound
#endif #endif
if (M_CheckParm("-nodigmusic")) }
digital_disabled = true; // WARNING: DOS version initmusic in I_StartupSound else
{
#ifndef NO_MIDI
if (M_CheckParm("-nomidimusic"))
midi_disabled = true; // WARNING: DOS version initmusic in I_StartupSound
#endif
if (M_CheckParm("-nodigmusic"))
digital_disabled = true; // WARNING: DOS version initmusic in I_StartupSound
}
} }
if (!( sound_disabled && digital_disabled if (!( sound_disabled && digital_disabled
#ifndef NO_MIDI #ifndef NO_MIDI
@ -1537,13 +1548,9 @@ void D_SRB2Main(void)
INT16 newgametype = -1; INT16 newgametype = -1;
const char *sgametype = M_GetNextParm(); const char *sgametype = M_GetNextParm();
for (j = 0; gametype_cons_t[j].strvalue; j++) newgametype = G_GetGametypeByName(sgametype);
if (!strcasecmp(gametype_cons_t[j].strvalue, sgametype))
{ if (newgametype == -1) // reached end of the list with no match
newgametype = (INT16)gametype_cons_t[j].value;
break;
}
if (!gametype_cons_t[j].strvalue) // reached end of the list with no match
{ {
j = atoi(sgametype); // assume they gave us a gametype number, which is okay too j = atoi(sgametype); // assume they gave us a gametype number, which is okay too
if (j >= 0 && j < NUMGAMETYPES) if (j >= 0 && j < NUMGAMETYPES)
@ -1598,13 +1605,13 @@ void D_SRB2Main(void)
} }
else if (M_CheckParm("-skipintro")) else if (M_CheckParm("-skipintro"))
{ {
CON_ToggleOff();
CON_ClearHUD();
F_StartTitleScreen(); F_StartTitleScreen();
} }
else else
F_StartIntro(); // Tails 03-03-2002 F_StartIntro(); // Tails 03-03-2002
CON_ToggleOff();
if (dedicated && server) if (dedicated && server)
{ {
pagename = "TITLESKY"; pagename = "TITLESKY";

View file

@ -185,22 +185,10 @@ typedef struct
UINT8 nextacknum; UINT8 nextacknum;
UINT8 flags; UINT8 flags;
#ifndef NEWPING
// jacobson tcp timeout evaluation algorithm (Karn variation)
fixed_t ping;
fixed_t varping;
INT32 timeout; // computed with ping and varping
#endif
} node_t; } node_t;
static node_t nodes[MAXNETNODES]; static node_t nodes[MAXNETNODES];
#ifndef NEWPING #define NODETIMEOUT 14
#define PINGDEFAULT ((200*TICRATE*FRACUNIT)/1000)
#define VARPINGDEFAULT ((50*TICRATE*FRACUNIT)/1000)
#define TIMEOUT(p,v) (p+4*v+FRACUNIT/2)>>FRACBITS;
#else
#define NODETIMEOUT 14 //What the above boiled down to...
#endif
#ifndef NONET #ifndef NONET
// return <0 if a < b (mod 256) // return <0 if a < b (mod 256)
@ -320,19 +308,7 @@ static UINT8 GetAcktosend(INT32 node)
static void RemoveAck(INT32 i) static void RemoveAck(INT32 i)
{ {
INT32 node = ackpak[i].destinationnode; INT32 node = ackpak[i].destinationnode;
#ifndef NEWPING
fixed_t trueping = (I_GetTime() - ackpak[i].senttime)<<FRACBITS;
if (ackpak[i].resentnum)
{
// +FRACUNIT/2 for round
nodes[node].ping = (nodes[node].ping*7 + trueping)/8;
nodes[node].varping = (nodes[node].varping*7 + abs(nodes[node].ping-trueping))/8;
nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
}
DEBFILE(va("Remove ack %d trueping %d ping %f var %f timeout %d\n",ackpak[i].acknum,trueping>>FRACBITS,(double)FIXED_TO_FLOAT(nodes[node].ping),(double)FIXED_TO_FLOAT(nodes[node].varping),nodes[node].timeout));
#else
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum)); DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
#endif
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
if (nodes[node].flags & NF_CLOSE) if (nodes[node].flags & NF_CLOSE)
Net_CloseConnection(node); Net_CloseConnection(node);
@ -519,11 +495,7 @@ void Net_AckTicker(void)
{ {
const INT32 nodei = ackpak[i].destinationnode; const INT32 nodei = ackpak[i].destinationnode;
node_t *node = &nodes[nodei]; node_t *node = &nodes[nodei];
#ifdef NEWPING
if (ackpak[i].acknum && ackpak[i].senttime + NODETIMEOUT < I_GetTime()) if (ackpak[i].acknum && ackpak[i].senttime + NODETIMEOUT < I_GetTime())
#else
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
#endif
{ {
if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE)) if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
{ {
@ -534,13 +506,8 @@ void Net_AckTicker(void)
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
continue; continue;
} }
#ifdef NEWPING
DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime, DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime,
NODETIMEOUT, I_GetTime())); NODETIMEOUT, I_GetTime()));
#else
DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime,
node->timeout, I_GetTime()));
#endif
M_Memcpy(netbuffer, ackpak[i].pak.raw, ackpak[i].length); M_Memcpy(netbuffer, ackpak[i].pak.raw, ackpak[i].length);
ackpak[i].senttime = I_GetTime(); ackpak[i].senttime = I_GetTime();
ackpak[i].resentnum++; ackpak[i].resentnum++;
@ -658,11 +625,6 @@ void Net_WaitAllAckReceived(UINT32 timeout)
static void InitNode(node_t *node) static void InitNode(node_t *node)
{ {
node->acktosend_head = node->acktosend_tail = 0; node->acktosend_head = node->acktosend_tail = 0;
#ifndef NEWPING
node->ping = PINGDEFAULT;
node->varping = VARPINGDEFAULT;
node->timeout = TIMEOUT(node->ping, node->varping);
#endif
node->firstacktosend = 0; node->firstacktosend = 0;
node->nextacknum = 1; node->nextacknum = 1;
node->remotefirstack = 0; node->remotefirstack = 0;
@ -854,9 +816,7 @@ static const char *packettypename[NUMPACKETTYPE] =
"CLIENTJOIN", "CLIENTJOIN",
"NODETIMEOUT", "NODETIMEOUT",
"RESYNCHING", "RESYNCHING",
#ifdef NEWPING
"PING" "PING"
#endif
}; };
static void DebugPrintpacket(const char *header) static void DebugPrintpacket(const char *header)
@ -1410,30 +1370,73 @@ boolean D_CheckNetGame(void)
return ret; return ret;
} }
struct pingcell
{
INT32 num;
INT32 ms;
};
static int pingcellcmp(const void *va, const void *vb)
{
const struct pingcell *a, *b;
a = va;
b = vb;
return ( a->ms - b->ms );
}
/*
New ping command formatted nicely to present ping in
ascending order. And with equally spaced columns.
The caller's ping is presented at the bottom too, for
convenience.
*/
void Command_Ping_f(void) void Command_Ping_f(void)
{ {
#ifndef NEWPING struct pingcell pingv[MAXPLAYERS];
if(server) INT32 pingc;
int name_width = 0;
int ms_width = 0;
int n;
INT32 i;
pingc = 0;
for (i = 1; i < MAXPLAYERS; ++i)
if (playeringame[i])
{ {
#endif n = strlen(player_names[i]);
INT32 i; if (n > name_width)
for (i = 0; i < MAXPLAYERS;i++) name_width = n;
{
#ifndef NEWPING n = playerpingtable[i];
const INT32 node = playernode[i]; if (n > ms_width)
if (playeringame[i] && node != 0) ms_width = n;
CONS_Printf(M_GetText("%.2d : %s\n %d tics, %d ms.\n"), i, player_names[i],
GetLag(node), G_TicsToMilliseconds(GetLag(node))); pingv[pingc].num = i;
#else pingv[pingc].ms = playerpingtable[i];
if (playeringame[i] && i != 0) pingc++;
CONS_Printf(M_GetText("%.2d : %s\n %d ms\n"), i, player_names[i], playerpingtable[i]); }
#endif
} if (ms_width < 10) ms_width = 1;
#ifndef NEWPING else if (ms_width < 100) ms_width = 2;
else ms_width = 3;
qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp);
for (i = 0; i < pingc; ++i)
{
CONS_Printf("%02d : %-*s %*d ms\n",
pingv[i].num,
name_width, player_names[pingv[i].num],
ms_width, pingv[i].ms);
}
if (!server && playeringame[consoleplayer])
{
CONS_Printf("\nYour ping is %d ms\n", playerpingtable[consoleplayer]);
} }
else
CONS_Printf(M_GetText("Only the server can use this.\n"));
#endif
} }
void D_CloseConnection(void) void D_CloseConnection(void)

View file

@ -433,7 +433,7 @@ consvar_t cv_numlaps = {"numlaps", "3", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_con
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}}; static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}};
consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_forceskin = {"forceskin", "-1", CV_NETVAR|CV_CALL|CV_CHEAT, NULL, ForceSkin_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_forceskin = {"forceskin", "Off", CV_NETVAR|CV_CALL|CV_CHEAT, Forceskin_cons_t, ForceSkin_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_downloading = {"downloading", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_downloading = {"downloading", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_allowexitlevel = {"allowexitlevel", "No", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_allowexitlevel = {"allowexitlevel", "No", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -444,7 +444,6 @@ static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE
consvar_t cv_nettimeout = {"nettimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_nettimeout = {"nettimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
//static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}}; //static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
consvar_t cv_jointimeout = {"jointimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_jointimeout = {"jointimeout", "105", CV_CALL|CV_SAVE, nettimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
#ifdef NEWPING
static CV_PossibleValue_t maxping_cons_t[] = {{0, "MIN"}, {1000, "MAX"}, {0, NULL}}; static CV_PossibleValue_t maxping_cons_t[] = {{0, "MIN"}, {1000, "MAX"}, {0, NULL}};
consvar_t cv_maxping = {"maxping", "800", CV_SAVE, maxping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_maxping = {"maxping", "800", CV_SAVE, maxping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -455,7 +454,6 @@ consvar_t cv_pingtimeout = {"pingtimeout", "10", CV_SAVE, pingtimeout_cons_t, NU
static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}}; static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}};
consvar_t cv_showping = {"showping", "Always", CV_SAVE, showping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_showping = {"showping", "Always", CV_SAVE, showping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
// Intermission time Tails 04-19-2002 // Intermission time Tails 04-19-2002
static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}}; static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}};
consvar_t cv_inttime = {"inttime", "20", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_inttime = {"inttime", "20", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -524,6 +522,24 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
*/ */
void D_RegisterServerCommands(void) void D_RegisterServerCommands(void)
{ {
INT32 i;
Forceskin_cons_t[0].value = -1;
Forceskin_cons_t[0].strvalue = "Off";
for (i = 0; i < NUMGAMETYPES; i++)
{
gametype_cons_t[i].value = i;
gametype_cons_t[i].strvalue = Gametype_Names[i];
}
gametype_cons_t[NUMGAMETYPES].value = 0;
gametype_cons_t[NUMGAMETYPES].strvalue = NULL;
// Set the values to 0/NULL, it will be overwritten later when a skin is assigned to the slot.
for (i = 1; i < MAXSKINS; i++)
{
Forceskin_cons_t[i].value = 0;
Forceskin_cons_t[i].strvalue = NULL;
}
RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor); RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor);
RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref); RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref);
RegisterNetXCmd(XD_MAP, Got_Mapcmd); RegisterNetXCmd(XD_MAP, Got_Mapcmd);
@ -677,6 +693,14 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload); CV_RegisterVar(&cv_noticedownload);
CV_RegisterVar(&cv_downloadspeed); CV_RegisterVar(&cv_downloadspeed);
#ifndef NONET
CV_RegisterVar(&cv_allownewplayer);
#ifdef VANILLAJOINNEXTROUND
CV_RegisterVar(&cv_joinnextround);
#endif
CV_RegisterVar(&cv_showjoinaddress);
CV_RegisterVar(&cv_blamecfail);
#endif
COM_AddCommand("ping", Command_Ping_f); COM_AddCommand("ping", Command_Ping_f);
CV_RegisterVar(&cv_nettimeout); CV_RegisterVar(&cv_nettimeout);
@ -684,11 +708,9 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_skipmapcheck); CV_RegisterVar(&cv_skipmapcheck);
CV_RegisterVar(&cv_sleep); CV_RegisterVar(&cv_sleep);
#ifdef NEWPING
CV_RegisterVar(&cv_maxping); CV_RegisterVar(&cv_maxping);
CV_RegisterVar(&cv_pingtimeout); CV_RegisterVar(&cv_pingtimeout);
CV_RegisterVar(&cv_showping); CV_RegisterVar(&cv_showping);
#endif
#ifdef SEENAMES #ifdef SEENAMES
CV_RegisterVar(&cv_allowseenames); CV_RegisterVar(&cv_allowseenames);
@ -2261,13 +2283,15 @@ static void Command_Map_f(void)
{ {
const char *mapname; const char *mapname;
size_t i; size_t i;
INT32 j, newmapnum; INT32 newmapnum;
boolean newresetplayers; boolean newresetplayers, newencoremode;
INT32 newgametype = gametype; INT32 newgametype = gametype;
// max length of command: map map03 -gametype coop -noresetplayers -force // max length of command: map map03 -gametype race -noresetplayers -force -encore
// 1 2 3 4 5 6 // 1 2 3 4 5 6 7
// = 8 arg max // = 8 arg max
// i don't know whether this is intrinsic to the system or just someone being weird but
// "noresetplayers" is pretty useless for kart if it turns out this is too close to the limit
if (COM_Argc() < 2 || COM_Argc() > 8) if (COM_Argc() < 2 || COM_Argc() > 8)
{ {
CONS_Printf(M_GetText("map <mapname> [-gametype <type> [-force]: warp to map\n")); CONS_Printf(M_GetText("map <mapname> [-gametype <type> [-force]: warp to map\n"));
@ -2327,29 +2351,30 @@ static void Command_Map_f(void)
return; return;
} }
for (j = 0; gametype_cons_t[j].strvalue; j++) newgametype = G_GetGametypeByName(COM_Argv(i+1));
if (!strcasecmp(gametype_cons_t[j].strvalue, COM_Argv(i+1))) if (newgametype == -1) // reached end of the list with no match
{
// Don't do any variable setting here. Wait until you get your
// map packet first to avoid sending the same info twice!
newgametype = gametype_cons_t[j].value;
break;
}
if (!gametype_cons_t[j].strvalue) // reached end of the list with no match
{ {
// assume they gave us a gametype number, which is okay too INT32 j = atoi(COM_Argv(i+1)); // assume they gave us a gametype number, which is okay too
for (j = 0; gametype_cons_t[j].strvalue != NULL; j++) if (j >= 0 && j < NUMGAMETYPES)
{ newgametype = (INT16)j;
if (atoi(COM_Argv(i+1)) == gametype_cons_t[j].value)
{
newgametype = gametype_cons_t[j].value;
break;
}
}
} }
} }
// new encoremode value
// use cvar by default
newencoremode = (boolean)cv_kartencore.value;
if (COM_CheckParm("-encore"))
{
if (!M_SecretUnlocked(SECRET_ENCORE) && !newencoremode)
{
CONS_Alert(CONS_NOTICE, M_GetText("You haven't unlocked Encore Mode yet!\n"));
return;
}
newencoremode = !newencoremode;
}
if (!(i = COM_CheckParm("-force")) && newgametype == gametype) // SRB2Kart if (!(i = COM_CheckParm("-force")) && newgametype == gametype) // SRB2Kart
newresetplayers = false; // if not forcing and gametypes is the same newresetplayers = false; // if not forcing and gametypes is the same
@ -2358,15 +2383,20 @@ static void Command_Map_f(void)
; // The player wants us to trek on anyway. Do so. ; // The player wants us to trek on anyway. Do so.
// G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer // G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer
// Alternatively, bail if the map header is completely missing anyway. // Alternatively, bail if the map header is completely missing anyway.
else else if (!mapheaderinfo[newmapnum-1]
|| !(mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)))
{ {
if (!mapheaderinfo[newmapnum-1] char gametypestring[32] = "Single Player";
|| !(mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)))
if (multiplayer)
{ {
CONS_Alert(CONS_WARNING, M_GetText("%s doesn't support %s mode!\n(Use -force to override)\n"), mapname, if (newgametype >= 0 && newgametype < NUMGAMETYPES
(multiplayer ? gametype_cons_t[newgametype].strvalue : "Single Player")); && Gametype_Names[newgametype])
return; strcpy(gametypestring, Gametype_Names[newgametype]);
} }
CONS_Alert(CONS_WARNING, M_GetText("%s doesn't support %s mode!\n(Use -force to override)\n"), mapname, gametypestring);
return;
} }
// Prevent warping to locked levels // Prevent warping to locked levels
@ -2380,7 +2410,7 @@ static void Command_Map_f(void)
} }
fromlevelselect = false; fromlevelselect = false;
D_MapChange(newmapnum, newgametype, (boolean)cv_kartencore.value, newresetplayers, 0, false, false); D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false);
} }
/** Receives a map command and changes the map. /** Receives a map command and changes the map.
@ -2451,9 +2481,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
CON_LogMessage(M_GetText("Speeding off to level...\n")); CON_LogMessage(M_GetText("Speeding off to level...\n"));
} }
CON_ToggleOff();
CON_ClearHUD();
if (demoplayback && !timingdemo) if (demoplayback && !timingdemo)
precache = false; precache = false;
@ -4426,12 +4453,22 @@ static void Command_ModDetails_f(void)
// //
static void Command_ShowGametype_f(void) static void Command_ShowGametype_f(void)
{ {
const char *gametypestr = NULL;
if (!(netgame || multiplayer)) // print "Single player" instead of "Race" if (!(netgame || multiplayer)) // print "Single player" instead of "Race"
{ {
CONS_Printf(M_GetText("Current gametype is %s\n"), "Single Player"); CONS_Printf(M_GetText("Current gametype is %s\n"), "Single Player");
return; return;
} }
CONS_Printf(M_GetText("Current gametype is %s\n"), gametype_cons_t[gametype].strvalue);
// get name string for current gametype
if (gametype >= 0 && gametype < NUMGAMETYPES)
gametypestr = Gametype_Names[gametype];
if (gametypestr)
CONS_Printf(M_GetText("Current gametype is %s\n"), gametypestr);
else // string for current gametype was not found above (should never happen)
CONS_Printf(M_GetText("Unknown gametype set (%d)\n"), gametype);
} }
/** Plays the intro. /** Plays the intro.
@ -4575,9 +4612,18 @@ static void TimeLimit_OnChange(void)
*/ */
void D_GameTypeChanged(INT32 lastgametype) void D_GameTypeChanged(INT32 lastgametype)
{ {
if (multiplayer) if (netgame)
CONS_Printf(M_GetText("Gametype was changed from %s to %s\n"), gametype_cons_t[lastgametype].strvalue, gametype_cons_t[gametype].strvalue); {
const char *oldgt = NULL, *newgt = NULL;
if (lastgametype >= 0 && lastgametype < NUMGAMETYPES)
oldgt = Gametype_Names[lastgametype];
if (gametype >= 0 && lastgametype < NUMGAMETYPES)
newgt = Gametype_Names[gametype];
if (oldgt && newgt)
CONS_Printf(M_GetText("Gametype was changed from %s to %s\n"), oldgt, newgt);
}
// Only do the following as the server, not as remote admin. // Only do the following as the server, not as remote admin.
// There will always be a server, and this only needs to be done once. // There will always be a server, and this only needs to be done once.
if (server && (multiplayer || netgame)) if (server && (multiplayer || netgame))
@ -5210,27 +5256,11 @@ static void Command_Archivetest_f(void)
/** Makes a change to ::cv_forceskin take effect immediately. /** Makes a change to ::cv_forceskin take effect immediately.
* *
* \todo Move the enforcement code out of SendNameAndColor() so this hack
* isn't needed.
* \sa Command_SetForcedSkin_f, cv_forceskin, forcedskin * \sa Command_SetForcedSkin_f, cv_forceskin, forcedskin
* \author Graue <graue@oceanbase.org> * \author Graue <graue@oceanbase.org>
*/ */
static void ForceSkin_OnChange(void) static void ForceSkin_OnChange(void)
{ {
if ((server || IsPlayerAdmin(consoleplayer)) && (cv_forceskin.value < -1 || cv_forceskin.value >= numskins))
{
if (cv_forceskin.value == -2)
CV_SetValue(&cv_forceskin, numskins-1);
else
{
// hack because I can't restrict this and still allow added skins to be used with forceskin.
if (!menuactive)
CONS_Printf(M_GetText("Valid skin numbers are 0 to %d (-1 disables)\n"), numskins - 1);
CV_SetValue(&cv_forceskin, -1);
}
return;
}
// NOT in SP, silly! // NOT in SP, silly!
if (!(netgame || multiplayer)) if (!(netgame || multiplayer))
return; return;
@ -5239,7 +5269,7 @@ static void ForceSkin_OnChange(void)
CONS_Printf("The server has lifted the forced skin restrictions.\n"); CONS_Printf("The server has lifted the forced skin restrictions.\n");
else else
{ {
CONS_Printf("The server is restricting all players to skin \"%s\".\n",skins[cv_forceskin.value].name); CONS_Printf("The server is restricting all players to skin \"%s\".\n",cv_forceskin.string);
ForceAllSkins(cv_forceskin.value); ForceAllSkins(cv_forceskin.value);
} }
} }

View file

@ -147,11 +147,9 @@ extern consvar_t cv_ringslinger, cv_soundtest;
extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes; extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes;
#ifdef NEWPING
extern consvar_t cv_maxping; extern consvar_t cv_maxping;
extern consvar_t cv_pingtimeout; extern consvar_t cv_pingtimeout;
extern consvar_t cv_showping; extern consvar_t cv_showping;
#endif
extern consvar_t cv_skipmapcheck; extern consvar_t cv_skipmapcheck;

View file

@ -1452,6 +1452,13 @@ static void readlevelheader(MYFILE *f, INT32 num)
#endif #endif
else if (fastcmp(word, "MUSICTRACK")) else if (fastcmp(word, "MUSICTRACK"))
mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1); mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1);
else if (fastcmp(word, "MUSICPOS"))
mapheaderinfo[num-1]->muspos = (UINT32)get_number(word2);
else if (fastcmp(word, "MUSICINTERFADEOUT"))
mapheaderinfo[num-1]->musinterfadeout = (UINT32)get_number(word2);
else if (fastcmp(word, "MUSICINTER"))
deh_strlcpy(mapheaderinfo[num-1]->musintername, word2,
sizeof(mapheaderinfo[num-1]->musintername), va("Level header %d: intermission music", num));
else if (fastcmp(word, "FORCECHARACTER")) else if (fastcmp(word, "FORCECHARACTER"))
{ {
strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1); strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1);
@ -1775,6 +1782,11 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musswitchflags), UNDO_NONE); DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musswitchflags), UNDO_NONE);
cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK;
} }
else if (fastcmp(word, "MUSICPOS"))
{
DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musswitchposition), UNDO_NONE);
cutscenes[num]->scene[scenenum].musswitchposition = (UINT32)get_number(word2);
}
else if (fastcmp(word, "MUSICLOOP")) else if (fastcmp(word, "MUSICLOOP"))
{ {
DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musicloop), UNDO_NONE); DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musicloop), UNDO_NONE);
@ -8757,6 +8769,7 @@ struct {
// doomdef.h constants // doomdef.h constants
{"TICRATE",TICRATE}, {"TICRATE",TICRATE},
{"MUSICRATE",MUSICRATE},
{"RING_DIST",RING_DIST}, {"RING_DIST",RING_DIST},
{"PUSHACCEL",PUSHACCEL}, {"PUSHACCEL",PUSHACCEL},
{"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into. {"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into.
@ -10139,6 +10152,9 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"mapmusflags")) { } else if (fastcmp(word,"mapmusflags")) {
lua_pushinteger(L, mapmusflags); lua_pushinteger(L, mapmusflags);
return 1; return 1;
} else if (fastcmp(word,"mapmusposition")) {
lua_pushinteger(L, mapmusposition);
return 1;
} else if (fastcmp(word,"server")) { } else if (fastcmp(word,"server")) {
if ((!multiplayer || !netgame) && !playeringame[serverplayer]) if ((!multiplayer || !netgame) && !playeringame[serverplayer])
return 0; return 0;
@ -10192,6 +10208,9 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"mapobjectscale")) { } else if (fastcmp(word,"mapobjectscale")) {
lua_pushinteger(L, mapobjectscale); lua_pushinteger(L, mapobjectscale);
return 1; return 1;
} else if (fastcmp(word,"numlaps")) {
lua_pushinteger(L, cv_numlaps.value);
return 1;
} }
return 0; return 0;
} }

View file

@ -438,6 +438,37 @@ boolean I_SetSongSpeed(float speed)
return false; return false;
} }
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
return 0;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
(void)position;
return false;
}
UINT32 I_GetSongPosition(void)
{
return 0;
}
/// ------------------------ /// ------------------------
// MUSIC PLAYBACK // MUSIC PLAYBACK
/// ------------------------ /// ------------------------
@ -545,3 +576,44 @@ int I_QrySongPlaying(int handle)
return (midi_pos==-1); return (midi_pos==-1);
} }
#endif #endif
/// ------------------------
// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)source_volume;
(void)ms;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)ms;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}

View file

@ -418,6 +418,8 @@ typedef enum
#define NEWTICRATERATIO 1 // try 4 for 140 fps :) #define NEWTICRATERATIO 1 // try 4 for 140 fps :)
#define NEWTICRATE (TICRATE*NEWTICRATERATIO) #define NEWTICRATE (TICRATE*NEWTICRATERATIO)
#define MUSICRATE 1000 // sound timing is calculated by milliseconds
#define RING_DIST 1280*FRACUNIT // how close you need to be to a ring to attract it #define RING_DIST 1280*FRACUNIT // how close you need to be to a ring to attract it
#define PUSHACCEL (2*FRACUNIT) // Acceleration for MF2_SLIDEPUSH items. #define PUSHACCEL (2*FRACUNIT) // Acceleration for MF2_SLIDEPUSH items.
@ -601,9 +603,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Polyobject fake flat code /// Polyobject fake flat code
#define POLYOBJECTS_PLANES #define POLYOBJECTS_PLANES
/// Improved way of dealing with ping values and a ping limit.
#define NEWPING
/// See name of player in your crosshair /// See name of player in your crosshair
#define SEENAMES #define SEENAMES

View file

@ -33,8 +33,10 @@
extern INT16 gamemap; extern INT16 gamemap;
extern char mapmusname[7]; extern char mapmusname[7];
extern UINT16 mapmusflags; extern UINT16 mapmusflags;
extern UINT32 mapmusposition;
#define MUSIC_TRACKMASK 0x0FFF // ----************ #define MUSIC_TRACKMASK 0x0FFF // ----************
#define MUSIC_RELOADRESET 0x8000 // *--------------- #define MUSIC_RELOADRESET 0x8000 // *---------------
#define MUSIC_FORCERESET 0x4000 // -*--------------
// Use other bits if necessary. // Use other bits if necessary.
extern INT16 maptol; extern INT16 maptol;
@ -156,6 +158,7 @@ typedef struct
char musswitch[7]; char musswitch[7];
UINT16 musswitchflags; UINT16 musswitchflags;
UINT32 musswitchposition;
UINT8 fadecolor; // Color number for fade, 0 means don't do the first fade UINT8 fadecolor; // Color number for fade, 0 means don't do the first fade
UINT8 fadeinid; // ID of the first fade, to a color -- ignored if fadecolor is 0 UINT8 fadeinid; // ID of the first fade, to a color -- ignored if fadecolor is 0
@ -227,6 +230,7 @@ typedef struct
INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end. INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end.
char musname[7]; ///< Music track to play. "" for no music. char musname[7]; ///< Music track to play. "" for no music.
UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
UINT32 muspos; ///< Music position to jump to.
char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable. char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable.
UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave. UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave.
INT16 skynum; ///< Sky number to use. INT16 skynum; ///< Sky number to use.
@ -260,6 +264,10 @@ typedef struct
//boolean automap; ///< Displays a level's white map outline in modified games //boolean automap; ///< Displays a level's white map outline in modified games
fixed_t mobj_scale; ///< Replacement for TOL_ERZ3 fixed_t mobj_scale; ///< Replacement for TOL_ERZ3
// Music stuff.
UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds
char musintername[7]; ///< Intermission screen music.
// Lua stuff. // Lua stuff.
// (This is not ifdeffed so the map header structure can stay identical, just in case.) // (This is not ifdeffed so the map header structure can stay identical, just in case.)
UINT8 numCustomOptions; ///< Internal. For Lua custom value support. UINT8 numCustomOptions; ///< Internal. For Lua custom value support.
@ -330,7 +338,10 @@ enum GameType // SRB2Kart
GT_HIDEANDSEEK, GT_HIDEANDSEEK,
GT_CTF GT_CTF
}; };
// If you alter this list, update gametype_cons_t in m_menu.c // If you alter this list, update dehacked.c, and Gametype_Names in g_game.c
// String names for gametypes
extern const char *Gametype_Names[NUMGAMETYPES];
extern tic_t totalplaytime; extern tic_t totalplaytime;
extern UINT32 matchesplayed; extern UINT32 matchesplayed;
@ -543,9 +554,7 @@ extern consvar_t cv_forceskin; // force clients to use the server's skin
extern consvar_t cv_downloading; // allow clients to downloading WADs. extern consvar_t cv_downloading; // allow clients to downloading WADs.
extern consvar_t cv_nettimeout; // SRB2Kart: Advanced server options menu extern consvar_t cv_nettimeout; // SRB2Kart: Advanced server options menu
extern consvar_t cv_jointimeout; extern consvar_t cv_jointimeout;
#ifdef NEWPING
extern consvar_t cv_maxping; extern consvar_t cv_maxping;
#endif
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
extern INT32 serverplayer; extern INT32 serverplayer;
extern INT32 adminplayers[MAXPLAYERS]; extern INT32 adminplayers[MAXPLAYERS];

View file

@ -366,16 +366,18 @@ size_t strlcpy(char *dst, const char *src, size_t siz);
/* Miscellaneous types that don't fit anywhere else (Can this be changed?) */ /* Miscellaneous types that don't fit anywhere else (Can this be changed?) */
typedef struct
{
UINT8 red;
UINT8 green;
UINT8 blue;
UINT8 alpha;
} byteColor_t;
union FColorRGBA union FColorRGBA
{ {
UINT32 rgba; UINT32 rgba;
struct byteColor_t s;
{
UINT8 red;
UINT8 green;
UINT8 blue;
UINT8 alpha;
} s;
} ATTRPACK; } ATTRPACK;
typedef union FColorRGBA RGBA_t; typedef union FColorRGBA RGBA_t;

View file

@ -95,6 +95,37 @@ boolean I_SetSongSpeed(float speed)
return false; return false;
} }
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
return 0;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
(void)position;
return false;
}
UINT32 I_GetSongPosition(void)
{
return 0;
}
/// ------------------------ /// ------------------------
// MUSIC PLAYBACK // MUSIC PLAYBACK
/// ------------------------ /// ------------------------
@ -142,4 +173,45 @@ boolean I_SetSongTrack(int track)
{ {
(void)track; (void)track;
return false; return false;
} }
/// ------------------------
// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)source_volume;
(void)ms;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
{
(void)target_volume;
(void)ms;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}

View file

@ -238,7 +238,6 @@ void F_StartIntro(void)
gameaction = ga_nothing; gameaction = ga_nothing;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD();
F_NewCutscene(introtext[0]); F_NewCutscene(introtext[0]);
intro_scenenum = 0; intro_scenenum = 0;
@ -580,7 +579,6 @@ void F_StartCredits(void)
gameaction = ga_nothing; gameaction = ga_nothing;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD();
S_StopMusic(); S_StopMusic();
S_ChangeMusicInternal("credit", false); S_ChangeMusicInternal("credit", false);
@ -773,7 +771,6 @@ void F_StartGameEvaluation(void)
gameaction = ga_nothing; gameaction = ga_nothing;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD();
finalecount = 0; finalecount = 0;
} }
@ -883,7 +880,6 @@ void F_StartGameEnd(void)
gameaction = ga_nothing; gameaction = ga_nothing;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD();
S_StopMusic(); S_StopMusic();
// In case menus are still up?!! // In case menus are still up?!!
@ -1177,7 +1173,6 @@ void F_StartContinue(void)
keypressed = false; keypressed = false;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
CON_ClearHUD();
// In case menus are still up?!! // In case menus are still up?!!
M_ClearMenus(true); M_ClearMenus(true);
@ -1297,9 +1292,10 @@ static void F_AdvanceToNextScene(void)
picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum]; picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum];
if (cutscenes[cutnum]->scene[scenenum].musswitch[0]) if (cutscenes[cutnum]->scene[scenenum].musswitch[0])
S_ChangeMusic(cutscenes[cutnum]->scene[scenenum].musswitch, S_ChangeMusicEx(cutscenes[cutnum]->scene[scenenum].musswitch,
cutscenes[cutnum]->scene[scenenum].musswitchflags, cutscenes[cutnum]->scene[scenenum].musswitchflags,
cutscenes[cutnum]->scene[scenenum].musicloop); cutscenes[cutnum]->scene[scenenum].musicloop,
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
// Fade to the next // Fade to the next
dofadenow = true; dofadenow = true;
@ -1348,8 +1344,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
F_NewCutscene(cutscenes[cutscenenum]->scene[0].text); F_NewCutscene(cutscenes[cutscenenum]->scene[0].text);
CON_ClearHUD();
cutsceneover = false; cutsceneover = false;
runningprecutscene = precutscene; runningprecutscene = precutscene;
precutresetplayer = resetplayer; precutresetplayer = resetplayer;
@ -1370,9 +1364,10 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
stoptimer = 0; stoptimer = 0;
if (cutscenes[cutnum]->scene[0].musswitch[0]) if (cutscenes[cutnum]->scene[0].musswitch[0])
S_ChangeMusic(cutscenes[cutnum]->scene[0].musswitch, S_ChangeMusicEx(cutscenes[cutnum]->scene[0].musswitch,
cutscenes[cutnum]->scene[0].musswitchflags, cutscenes[cutnum]->scene[0].musswitchflags,
cutscenes[cutnum]->scene[0].musicloop); cutscenes[cutnum]->scene[0].musicloop,
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
else else
S_StopMusic(); S_StopMusic();
} }

View file

@ -77,6 +77,7 @@ static void G_DoStartVote(void);
char mapmusname[7]; // Music name char mapmusname[7]; // Music name
UINT16 mapmusflags; // Track and reset bit UINT16 mapmusflags; // Track and reset bit
UINT32 mapmusposition; // Position to jump to
INT16 gamemap = 1; INT16 gamemap = 1;
INT16 maptol; INT16 maptol;
@ -2572,7 +2573,8 @@ void G_PlayerReborn(INT32 player)
{ {
strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7);
mapmusname[6] = 0; mapmusname[6] = 0;
mapmusflags = mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK; mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK);
mapmusposition = mapheaderinfo[gamemap-1]->muspos;
songcredit = true; songcredit = true;
} }
} }
@ -3103,6 +3105,36 @@ void G_ExitLevel(void)
} }
} }
// See also the enum GameType in doomstat.h
const char *Gametype_Names[NUMGAMETYPES] =
{
"Race", // GT_RACE
"Battle" // GT_MATCH
/*"Co-op", // GT_COOP
"Competition", // GT_COMPETITION
"Team Match", // GT_TEAMMATCH
"Tag", // GT_TAG
"Hide and Seek", // GT_HIDEANDSEEK
"CTF" // GT_CTF*/
};
//
// G_GetGametypeByName
//
// Returns the number for the given gametype name string, or -1 if not valid.
//
INT32 G_GetGametypeByName(const char *gametypestr)
{
INT32 i;
for (i = 0; i < NUMGAMETYPES; i++)
if (!stricmp(gametypestr, Gametype_Names[i]))
return i;
return -1; // unknown gametype
}
// //
// G_IsSpecialStage // G_IsSpecialStage
// //

View file

@ -195,6 +195,7 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(void);
void G_StopDemo(void); void G_StopDemo(void);
boolean G_CheckDemoStatus(void); boolean G_CheckDemoStatus(void);
INT32 G_GetGametypeByName(const char *gametypestr);
boolean G_IsSpecialStage(INT32 mapnum); boolean G_IsSpecialStage(INT32 mapnum);
boolean G_GametypeUsesLives(void); boolean G_GametypeUsesLives(void);
boolean G_GametypeHasTeams(void); boolean G_GametypeHasTeams(void);

View file

@ -1239,6 +1239,8 @@ void G_ClearAllControlKeys(void)
{ {
G_ClearControlKeys(gamecontrol, i); G_ClearControlKeys(gamecontrol, i);
G_ClearControlKeys(gamecontrolbis, i); G_ClearControlKeys(gamecontrolbis, i);
G_ClearControlKeys(gamecontrol3, i);
G_ClearControlKeys(gamecontrol4, i);
} }
} }

View file

@ -241,43 +241,6 @@ static void HWR_ResizeBlock(INT32 originalwidth, INT32 originalheight,
if (blockheight < 1) if (blockheight < 1)
I_Error("3D GenerateTexture : too small"); I_Error("3D GenerateTexture : too small");
} }
else if (cv_voodoocompatibility.value)
{
if (originalwidth > 256 || originalheight > 256)
{
blockwidth = 256;
while (originalwidth < blockwidth)
blockwidth >>= 1;
if (blockwidth < 1)
I_Error("3D GenerateTexture : too small");
blockheight = 256;
while (originalheight < blockheight)
blockheight >>= 1;
if (blockheight < 1)
I_Error("3D GenerateTexture : too small");
}
else
{
//size up to nearest power of 2
blockwidth = 1;
while (blockwidth < originalwidth)
blockwidth <<= 1;
// scale down the original graphics to fit in 256
if (blockwidth > 256)
blockwidth = 256;
//I_Error("3D GenerateTexture : too big");
//size up to nearest power of 2
blockheight = 1;
while (blockheight < originalheight)
blockheight <<= 1;
// scale down the original graphics to fit in 256
if (blockheight > 256)
blockheight = 255;
//I_Error("3D GenerateTexture : too big");
}
}
else else
{ {
//size up to nearest power of 2 //size up to nearest power of 2
@ -508,18 +471,6 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm
newwidth = blockwidth; newwidth = blockwidth;
newheight = blockheight; newheight = blockheight;
} }
else if (cv_voodoocompatibility.value) // Only scales down textures that exceed 256x256.
{
// no rounddown, do not size up patches, so they don't look 'scaled'
newwidth = min(grPatch->width, blockwidth);
newheight = min(grPatch->height, blockheight);
if (newwidth > 256 || newheight > 256)
{
newwidth = blockwidth;
newheight = blockheight;
}
}
else else
{ {
// no rounddown, do not size up patches, so they don't look 'scaled' // no rounddown, do not size up patches, so they don't look 'scaled'
@ -935,18 +886,6 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum)
newwidth = blockwidth; newwidth = blockwidth;
newheight = blockheight; newheight = blockheight;
} }
else if (cv_voodoocompatibility.value) // Only scales down textures that exceed 256x256.
{
// no rounddown, do not size up patches, so they don't look 'scaled'
newwidth = min(SHORT(pic->width),blockwidth);
newheight = min(SHORT(pic->height),blockheight);
if (newwidth > 256 || newheight > 256)
{
newwidth = blockwidth;
newheight = blockheight;
}
}
else else
{ {
// no rounddown, do not size up patches, so they don't look 'scaled' // no rounddown, do not size up patches, so they don't look 'scaled'

View file

@ -78,8 +78,8 @@
#include "r_opengl/r_opengl.h" #include "r_opengl/r_opengl.h"
#ifdef HAVE_SPHEREFRUSTRUM #ifdef HAVE_SPHEREFRUSTRUM
static GLdouble viewMatrix[16]; static GLfloat viewMatrix[16];
static GLdouble projMatrix[16]; static GLfloat projMatrix[16];
float frustum[6][4]; float frustum[6][4];
#endif #endif
@ -381,8 +381,8 @@ void gld_FrustrumSetup(void)
float t; float t;
float clip[16]; float clip[16];
pglGetDoublev(GL_PROJECTION_MATRIX, projMatrix); pglGeFloatv(GL_PROJECTION_MATRIX, projMatrix);
pglGetDoublev(GL_MODELVIEW_MATRIX, viewMatrix); pglGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix);
clip[0] = CALCMATRIX(0, 0, 1, 4, 2, 8, 3, 12); clip[0] = CALCMATRIX(0, 0, 1, 4, 2, 8, 3, 12);
clip[1] = CALCMATRIX(0, 1, 1, 5, 2, 9, 3, 13); clip[1] = CALCMATRIX(0, 1, 1, 5, 2, 9, 3, 13);

View file

@ -101,15 +101,29 @@ typedef struct
//Hurdler: Transform (coords + angles) //Hurdler: Transform (coords + angles)
//BP: transform order : scale(rotation_x(rotation_y(translation(v)))) //BP: transform order : scale(rotation_x(rotation_y(translation(v))))
// Kart features
#define USE_FTRANSFORM_ANGLEZ
#define USE_FTRANSFORM_MIRROR
// Vanilla features
//#define USE_MODEL_NEXTFRAME
typedef struct typedef struct
{ {
FLOAT x,y,z; // position FLOAT x,y,z; // position
#ifdef USE_FTRANSFORM_ANGLEZ
FLOAT anglex,angley,anglez; // aimingangle / viewangle FLOAT anglex,angley,anglez; // aimingangle / viewangle
#else
FLOAT anglex,angley; // aimingangle / viewangle
#endif
FLOAT scalex,scaley,scalez; FLOAT scalex,scaley,scalez;
FLOAT fovxangle, fovyangle; FLOAT fovxangle, fovyangle;
UINT8 splitscreen; UINT8 splitscreen;
boolean flip; // screenflip boolean flip; // screenflip
#ifdef USE_FTRANSFORM_MIRROR
boolean mirror; // SRB2Kart: Encore Mode boolean mirror; // SRB2Kart: Encore Mode
#endif
} FTransform; } FTransform;
// Transformed vector, as passed to HWR API // Transformed vector, as passed to HWR API
@ -152,7 +166,7 @@ enum EPolyFlags
// When set, pass the color constant into the FSurfaceInfo -> FlatColor // When set, pass the color constant into the FSurfaceInfo -> FlatColor
PF_NoTexture = 0x00002000, // Use the small white texture PF_NoTexture = 0x00002000, // Use the small white texture
PF_Corona = 0x00004000, // Tell the rendrer we are drawing a corona PF_Corona = 0x00004000, // Tell the rendrer we are drawing a corona
PF_MD2 = 0x00008000, // Tell the rendrer we are drawing an MD2 PF_Unused = 0x00008000, // Unused
PF_RemoveYWrap = 0x00010000, // Force clamp texture on Y PF_RemoveYWrap = 0x00010000, // Force clamp texture on Y
PF_ForceWrapX = 0x00020000, // Force repeat texture on X PF_ForceWrapX = 0x00020000, // Force repeat texture on X
PF_ForceWrapY = 0x00040000, // Force repeat texture on Y PF_ForceWrapY = 0x00040000, // Force repeat texture on Y
@ -210,8 +224,6 @@ enum hwdsetspecialstate
HWD_SET_FOG_COLOR, HWD_SET_FOG_COLOR,
HWD_SET_FOG_DENSITY, HWD_SET_FOG_DENSITY,
HWD_SET_FOV, HWD_SET_FOV,
HWD_SET_POLYGON_SMOOTH,
HWD_SET_PALETTECOLOR,
HWD_SET_TEXTUREFILTERMODE, HWD_SET_TEXTUREFILTERMODE,
HWD_SET_TEXTUREANISOTROPICMODE, HWD_SET_TEXTUREANISOTROPICMODE,
HWD_NUMSTATE HWD_NUMSTATE

View file

@ -58,20 +58,18 @@ EXPORT void HWRAPI(ClearMipMapCache) (void);
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development //Hurdler: added for new development
EXPORT void HWRAPI(DrawMD2) (INT32 *gl_cmd_buffer, md2_frame_t *frame, FTransform *pos, float scale); EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 *color);
EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, INT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color); EXPORT void HWRAPI(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT INT32 HWRAPI(GetTextureUsed) (void);
EXPORT INT32 HWRAPI(GetRenderVersion) (void); EXPORT INT32 HWRAPI(GetRenderVersion) (void);
#ifdef SHUFFLE
#define SCREENVERTS 10 #define SCREENVERTS 10
EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]);
#endif
EXPORT void HWRAPI(FlushScreenTextures) (void); EXPORT void HWRAPI(FlushScreenTextures) (void);
EXPORT void HWRAPI(StartScreenWipe) (void); EXPORT void HWRAPI(StartScreenWipe) (void);
EXPORT void HWRAPI(EndScreenWipe) (void); EXPORT void HWRAPI(EndScreenWipe) (void);
EXPORT void HWRAPI(DoScreenWipe) (float alpha); EXPORT void HWRAPI(DoScreenWipe) (void);
EXPORT void HWRAPI(DrawIntermissionBG) (void); EXPORT void HWRAPI(DrawIntermissionBG) (void);
EXPORT void HWRAPI(MakeScreenTexture) (void); EXPORT void HWRAPI(MakeScreenTexture) (void);
EXPORT void HWRAPI(MakeScreenFinalTexture) (void); EXPORT void HWRAPI(MakeScreenFinalTexture) (void);
@ -96,8 +94,8 @@ struct hwdriver_s
GClipRect pfnGClipRect; GClipRect pfnGClipRect;
ClearMipMapCache pfnClearMipMapCache; ClearMipMapCache pfnClearMipMapCache;
SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility
DrawMD2 pfnDrawMD2; DrawModel pfnDrawModel;
DrawMD2i pfnDrawMD2i; CreateModelVBOs pfnCreateModelVBOs;
SetTransform pfnSetTransform; SetTransform pfnSetTransform;
GetTextureUsed pfnGetTextureUsed; GetTextureUsed pfnGetTextureUsed;
GetRenderVersion pfnGetRenderVersion; GetRenderVersion pfnGetRenderVersion;
@ -107,9 +105,7 @@ struct hwdriver_s
#ifndef HAVE_SDL #ifndef HAVE_SDL
Shutdown pfnShutdown; Shutdown pfnShutdown;
#endif #endif
#ifdef SHUFFLE
PostImgRedraw pfnPostImgRedraw; PostImgRedraw pfnPostImgRedraw;
#endif
FlushScreenTextures pfnFlushScreenTextures; FlushScreenTextures pfnFlushScreenTextures;
StartScreenWipe pfnStartScreenWipe; StartScreenWipe pfnStartScreenWipe;
EndScreenWipe pfnEndScreenWipe; EndScreenWipe pfnEndScreenWipe;

View file

@ -4259,10 +4259,45 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
} }
} }
// This is expecting a pointer to an array containing 4 wallVerts for a sprite
static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts)
{
if (cv_grspritebillboarding.value
&& spr && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE)
&& wallVerts)
{
float basey = FIXED_TO_FLOAT(spr->mobj->z);
float lowy = wallVerts[0].y;
if (P_MobjFlip(spr->mobj) == -1)
{
basey = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height);
}
// Rotate sprites to fully billboard with the camera
// X, Y, AND Z need to be manipulated for the polys to rotate around the
// origin, because of how the origin setting works I believe that should
// be mobj->z or mobj->z + mobj->height
wallVerts[2].y = wallVerts[3].y = (spr->ty - basey) * gr_viewludsin + basey;
wallVerts[0].y = wallVerts[1].y = (lowy - basey) * gr_viewludsin + basey;
// translate back to be around 0 before translating back
wallVerts[3].x += ((spr->ty - basey) * gr_viewludcos) * gr_viewcos;
wallVerts[2].x += ((spr->ty - basey) * gr_viewludcos) * gr_viewcos;
wallVerts[0].x += ((lowy - basey) * gr_viewludcos) * gr_viewcos;
wallVerts[1].x += ((lowy - basey) * gr_viewludcos) * gr_viewcos;
wallVerts[3].z += ((spr->ty - basey) * gr_viewludcos) * gr_viewsin;
wallVerts[2].z += ((spr->ty - basey) * gr_viewludcos) * gr_viewsin;
wallVerts[0].z += ((lowy - basey) * gr_viewludcos) * gr_viewsin;
wallVerts[1].z += ((lowy - basey) * gr_viewludcos) * gr_viewsin;
}
}
static void HWR_SplitSprite(gr_vissprite_t *spr) static void HWR_SplitSprite(gr_vissprite_t *spr)
{ {
float this_scale = 1.0f; float this_scale = 1.0f;
FOutVector wallVerts[4]; FOutVector wallVerts[4];
FOutVector baseWallVerts[4]; // This is what the verts should end up as
GLPatch_t *gpatch; GLPatch_t *gpatch;
FSurfaceInfo Surf; FSurfaceInfo Surf;
const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
@ -4275,11 +4310,13 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
float realtop, realbot, top, bot; float realtop, realbot, top, bot;
float towtop, towbot, towmult; float towtop, towbot, towmult;
float bheight; float bheight;
float realheight, heightmult;
const sector_t *sector = spr->mobj->subsector->sector; const sector_t *sector = spr->mobj->subsector->sector;
const lightlist_t *list = sector->lightlist; const lightlist_t *list = sector->lightlist;
#ifdef ESLOPE #ifdef ESLOPE
float endrealtop, endrealbot, endtop, endbot; float endrealtop, endrealbot, endtop, endbot;
float endbheight; float endbheight;
float endrealheight;
fixed_t temp; fixed_t temp;
fixed_t v1x, v1y, v2x, v2y; fixed_t v1x, v1y, v2x, v2y;
#endif #endif
@ -4312,16 +4349,16 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
HWR_DrawSpriteShadow(spr, gpatch, this_scale); HWR_DrawSpriteShadow(spr, gpatch, this_scale);
} }
wallVerts[0].x = wallVerts[3].x = spr->x1; baseWallVerts[0].x = baseWallVerts[3].x = spr->x1;
wallVerts[2].x = wallVerts[1].x = spr->x2; baseWallVerts[2].x = baseWallVerts[1].x = spr->x2;
wallVerts[0].z = wallVerts[3].z = spr->z1; baseWallVerts[0].z = baseWallVerts[3].z = spr->z1;
wallVerts[1].z = wallVerts[2].z = spr->z2; baseWallVerts[1].z = baseWallVerts[2].z = spr->z2;
wallVerts[2].y = wallVerts[3].y = spr->ty; baseWallVerts[2].y = baseWallVerts[3].y = spr->ty;
if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f)
wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale; baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height * this_scale;
else else
wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height;
v1x = FLOAT_TO_FIXED(spr->x1); v1x = FLOAT_TO_FIXED(spr->x1);
v1y = FLOAT_TO_FIXED(spr->z1); v1y = FLOAT_TO_FIXED(spr->z1);
@ -4330,44 +4367,56 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
if (spr->flip) if (spr->flip)
{ {
wallVerts[0].sow = wallVerts[3].sow = gpatch->max_s; baseWallVerts[0].sow = baseWallVerts[3].sow = gpatch->max_s;
wallVerts[2].sow = wallVerts[1].sow = 0; baseWallVerts[2].sow = baseWallVerts[1].sow = 0;
}else{ }
wallVerts[0].sow = wallVerts[3].sow = 0; else
wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s; {
baseWallVerts[0].sow = baseWallVerts[3].sow = 0;
baseWallVerts[2].sow = baseWallVerts[1].sow = gpatch->max_s;
} }
// flip the texture coords (look familiar?) // flip the texture coords (look familiar?)
if (spr->vflip) if (spr->vflip)
{ {
wallVerts[3].tow = wallVerts[2].tow = gpatch->max_t; baseWallVerts[3].tow = baseWallVerts[2].tow = gpatch->max_t;
wallVerts[0].tow = wallVerts[1].tow = 0; baseWallVerts[0].tow = baseWallVerts[1].tow = 0;
}else{ }
wallVerts[3].tow = wallVerts[2].tow = 0; else
wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t; {
baseWallVerts[3].tow = baseWallVerts[2].tow = 0;
baseWallVerts[0].tow = baseWallVerts[1].tow = gpatch->max_t;
} }
// if it has a dispoffset, push it a little towards the camera // if it has a dispoffset, push it a little towards the camera
if (spr->dispoffset) { if (spr->dispoffset) {
float co = -gr_viewcos*(0.05f*spr->dispoffset); float co = -gr_viewcos*(0.05f*spr->dispoffset);
float si = -gr_viewsin*(0.05f*spr->dispoffset); float si = -gr_viewsin*(0.05f*spr->dispoffset);
wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si;
wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si;
wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co;
wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co;
} }
realtop = top = wallVerts[3].y; // Let dispoffset work first since this adjust each vertex
realbot = bot = wallVerts[0].y; HWR_RotateSpritePolyToAim(spr, baseWallVerts);
towtop = wallVerts[3].tow;
towbot = wallVerts[0].tow; realtop = top = baseWallVerts[3].y;
realbot = bot = baseWallVerts[0].y;
towtop = baseWallVerts[3].tow;
towbot = baseWallVerts[0].tow;
towmult = (towbot - towtop) / (top - bot); towmult = (towbot - towtop) / (top - bot);
#ifdef ESLOPE #ifdef ESLOPE
endrealtop = endtop = wallVerts[2].y; endrealtop = endtop = baseWallVerts[2].y;
endrealbot = endbot = wallVerts[1].y; endrealbot = endbot = baseWallVerts[1].y;
#endif #endif
// copy the contents of baseWallVerts into the drawn wallVerts array
// baseWallVerts is used to know the final shape to easily get the vertex
// co-ordinates
memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
if (!cv_translucency.value) // translucency disabled if (!cv_translucency.value) // translucency disabled
{ {
Surf.FlatColor.s.alpha = 0xFF; Surf.FlatColor.s.alpha = 0xFF;
@ -4494,12 +4543,55 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
wallVerts[2].y = endtop; wallVerts[2].y = endtop;
wallVerts[0].y = bot; wallVerts[0].y = bot;
wallVerts[1].y = endbot; wallVerts[1].y = endbot;
// The x and y only need to be adjusted in the case that it's not a papersprite
if (cv_grspritebillboarding.value
&& spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE))
{
// Get the x and z of the vertices so billboarding draws correctly
realheight = realbot - realtop;
endrealheight = endrealbot - endrealtop;
heightmult = (realtop - top) / realheight;
wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
heightmult = (endrealtop - endtop) / endrealheight;
wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
heightmult = (realtop - bot) / realheight;
wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
heightmult = (endrealtop - endbot) / endrealheight;
wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
}
#else #else
wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult); wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult);
wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult); wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult);
wallVerts[2].y = wallVerts[3].y = top; wallVerts[2].y = wallVerts[3].y = top;
wallVerts[0].y = wallVerts[1].y = bot; wallVerts[0].y = wallVerts[1].y = bot;
// The x and y only need to be adjusted in the case that it's not a papersprite
if (cv_grspritebillboarding.value
&& spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE))
{
// Get the x and z of the vertices so billboarding draws correctly
realheight = realbot - realtop;
heightmult = (realtop - top) / realheight;
wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
heightmult = (realtop - bot) / realheight;
wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
}
#endif #endif
if (colormap) if (colormap)
@ -4669,6 +4761,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co;
} }
// Let dispoffset work first since this adjust each vertex
HWR_RotateSpritePolyToAim(spr, wallVerts);
// This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black. // This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black.
// sprite lighting by modulating the RGB components // sprite lighting by modulating the RGB components
/// \todo coloured /// \todo coloured
@ -4750,6 +4845,9 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
wallVerts[0].z = wallVerts[3].z = spr->z1; wallVerts[0].z = wallVerts[3].z = spr->z1;
wallVerts[1].z = wallVerts[2].z = spr->z2; wallVerts[1].z = wallVerts[2].z = spr->z2;
// Let dispoffset work first since this adjust each vertex
HWR_RotateSpritePolyToAim(spr, wallVerts);
wallVerts[0].sow = wallVerts[3].sow = 0; wallVerts[0].sow = wallVerts[3].sow = 0;
wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s; wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s;
@ -5261,14 +5359,14 @@ static void HWR_DrawSprites(void)
if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
{ {
// 8/1/19: Only don't display player models if no default SPR_PLAY is found. // 8/1/19: Only don't display player models if no default SPR_PLAY is found.
if (!cv_grmd2.value || ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) && (md2_models[SPR_PLAY].notfound || md2_models[SPR_PLAY].scale < 0.0f))) if (!cv_grmdls.value || ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) && (md2_models[SPR_PLAY].notfound || md2_models[SPR_PLAY].scale < 0.0f)))
HWR_DrawSprite(spr); HWR_DrawSprite(spr);
else else
HWR_DrawMD2(spr); HWR_DrawMD2(spr);
} }
else else
{ {
if (!cv_grmd2.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) if (!cv_grmdls.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f)
HWR_DrawSprite(spr); HWR_DrawSprite(spr);
else else
HWR_DrawMD2(spr); HWR_DrawMD2(spr);
@ -5435,7 +5533,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin); tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
// thing is behind view plane? // thing is behind view plane?
if (tz < ZCLIP_PLANE && !papersprite && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear if (tz < ZCLIP_PLANE && !papersprite && (!cv_grmdls.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear
return; return;
// The above can stay as it works for cutting sprites that are too close // The above can stay as it works for cutting sprites that are too close
@ -6795,11 +6893,6 @@ static void HWR_RenderWall(wallVert3D *wallVerts, FSurfaceInfo *pSurf, FBITFIE
#endif #endif
} }
void HWR_SetPaletteColor(INT32 palcolor)
{
HWD.pfnSetSpecialState(HWD_SET_PALETTECOLOR, palcolor);
}
INT32 HWR_GetTextureUsed(void) INT32 HWR_GetTextureUsed(void)
{ {
return HWD.pfnGetTextureUsed(); return HWD.pfnGetTextureUsed();
@ -6850,7 +6943,6 @@ void HWR_DoPostProcessor(player_t *player)
if (splitscreen) // Not supported in splitscreen - someone want to add support? if (splitscreen) // Not supported in splitscreen - someone want to add support?
return; return;
#ifdef SHUFFLE
// Drunken vision! WooOOooo~ // Drunken vision! WooOOooo~
if (*type == postimg_water || *type == postimg_heat) if (*type == postimg_water || *type == postimg_heat)
{ {
@ -6893,7 +6985,6 @@ void HWR_DoPostProcessor(player_t *player)
HWD.pfnMakeScreenTexture(); HWD.pfnMakeScreenTexture();
} }
// Flipping of the screen isn't done here anymore // Flipping of the screen isn't done here anymore
#endif // SHUFFLE
} }
void HWR_StartScreenWipe(void) void HWR_StartScreenWipe(void)
@ -6940,7 +7031,7 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum)
HWR_GetFadeMask(lumpnum); HWR_GetFadeMask(lumpnum);
HWD.pfnDoScreenWipe(HWRWipeCounter); // Still send in wipecounter since old stuff might not support multitexturing HWD.pfnDoScreenWipe();
HWRWipeCounter += 0.05f; // increase opacity of end screen HWRWipeCounter += 0.05f; // increase opacity of end screen

View file

@ -58,7 +58,6 @@ void HWR_AddCommands(void);
void HWR_CorrectSWTricks(void); void HWR_CorrectSWTricks(void);
void transform(float *cx, float *cy, float *cz); void transform(float *cx, float *cy, float *cz);
FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf);
void HWR_SetPaletteColor(INT32 palcolor);
INT32 HWR_GetTextureUsed(void); INT32 HWR_GetTextureUsed(void);
void HWR_DoPostProcessor(player_t *player); void HWR_DoPostProcessor(player_t *player);
void HWR_StartScreenWipe(void); void HWR_StartScreenWipe(void);
@ -80,7 +79,7 @@ extern consvar_t cv_grstaticlighting;
extern consvar_t cv_grcoronas; extern consvar_t cv_grcoronas;
extern consvar_t cv_grcoronasize; extern consvar_t cv_grcoronasize;
#endif #endif
extern consvar_t cv_grmd2; extern consvar_t cv_grmdls;
extern consvar_t cv_grfog; extern consvar_t cv_grfog;
extern consvar_t cv_grfogcolor; extern consvar_t cv_grfogcolor;
extern consvar_t cv_grfogdensity; extern consvar_t cv_grfogdensity;
@ -91,9 +90,9 @@ extern consvar_t cv_grgammablue;
extern consvar_t cv_grfiltermode; extern consvar_t cv_grfiltermode;
extern consvar_t cv_granisotropicmode; extern consvar_t cv_granisotropicmode;
extern consvar_t cv_grcorrecttricks; extern consvar_t cv_grcorrecttricks;
extern consvar_t cv_voodoocompatibility;
extern consvar_t cv_grfovchange; extern consvar_t cv_grfovchange;
extern consvar_t cv_grsolvetjoin; extern consvar_t cv_grsolvetjoin;
extern consvar_t cv_grspritebillboarding;
extern float gr_viewwidth, gr_viewheight, gr_baseviewwindowx, gr_baseviewwindowy; extern float gr_viewwidth, gr_viewheight, gr_baseviewwindowx, gr_baseviewwindowy;

View file

@ -43,6 +43,7 @@
#include "../r_draw.h" #include "../r_draw.h"
#include "../p_tick.h" #include "../p_tick.h"
#include "../k_kart.h" // colortranslations #include "../k_kart.h" // colortranslations
#include "hw_model.h"
#include "hw_main.h" #include "hw_main.h"
#include "../v_video.h" #include "../v_video.h"
@ -75,172 +76,6 @@
#include "errno.h" #include "errno.h"
#endif #endif
#define NUMVERTEXNORMALS 162
float avertexnormals[NUMVERTEXNORMALS][3] = {
{-0.525731f, 0.000000f, 0.850651f},
{-0.442863f, 0.238856f, 0.864188f},
{-0.295242f, 0.000000f, 0.955423f},
{-0.309017f, 0.500000f, 0.809017f},
{-0.162460f, 0.262866f, 0.951056f},
{0.000000f, 0.000000f, 1.000000f},
{0.000000f, 0.850651f, 0.525731f},
{-0.147621f, 0.716567f, 0.681718f},
{0.147621f, 0.716567f, 0.681718f},
{0.000000f, 0.525731f, 0.850651f},
{0.309017f, 0.500000f, 0.809017f},
{0.525731f, 0.000000f, 0.850651f},
{0.295242f, 0.000000f, 0.955423f},
{0.442863f, 0.238856f, 0.864188f},
{0.162460f, 0.262866f, 0.951056f},
{-0.681718f, 0.147621f, 0.716567f},
{-0.809017f, 0.309017f, 0.500000f},
{-0.587785f, 0.425325f, 0.688191f},
{-0.850651f, 0.525731f, 0.000000f},
{-0.864188f, 0.442863f, 0.238856f},
{-0.716567f, 0.681718f, 0.147621f},
{-0.688191f, 0.587785f, 0.425325f},
{-0.500000f, 0.809017f, 0.309017f},
{-0.238856f, 0.864188f, 0.442863f},
{-0.425325f, 0.688191f, 0.587785f},
{-0.716567f, 0.681718f, -0.147621f},
{-0.500000f, 0.809017f, -0.309017f},
{-0.525731f, 0.850651f, 0.000000f},
{0.000000f, 0.850651f, -0.525731f},
{-0.238856f, 0.864188f, -0.442863f},
{0.000000f, 0.955423f, -0.295242f},
{-0.262866f, 0.951056f, -0.162460f},
{0.000000f, 1.000000f, 0.000000f},
{0.000000f, 0.955423f, 0.295242f},
{-0.262866f, 0.951056f, 0.162460f},
{0.238856f, 0.864188f, 0.442863f},
{0.262866f, 0.951056f, 0.162460f},
{0.500000f, 0.809017f, 0.309017f},
{0.238856f, 0.864188f, -0.442863f},
{0.262866f, 0.951056f, -0.162460f},
{0.500000f, 0.809017f, -0.309017f},
{0.850651f, 0.525731f, 0.000000f},
{0.716567f, 0.681718f, 0.147621f},
{0.716567f, 0.681718f, -0.147621f},
{0.525731f, 0.850651f, 0.000000f},
{0.425325f, 0.688191f, 0.587785f},
{0.864188f, 0.442863f, 0.238856f},
{0.688191f, 0.587785f, 0.425325f},
{0.809017f, 0.309017f, 0.500000f},
{0.681718f, 0.147621f, 0.716567f},
{0.587785f, 0.425325f, 0.688191f},
{0.955423f, 0.295242f, 0.000000f},
{1.000000f, 0.000000f, 0.000000f},
{0.951056f, 0.162460f, 0.262866f},
{0.850651f, -0.525731f, 0.000000f},
{0.955423f, -0.295242f, 0.000000f},
{0.864188f, -0.442863f, 0.238856f},
{0.951056f, -0.162460f, 0.262866f},
{0.809017f, -0.309017f, 0.500000f},
{0.681718f, -0.147621f, 0.716567f},
{0.850651f, 0.000000f, 0.525731f},
{0.864188f, 0.442863f, -0.238856f},
{0.809017f, 0.309017f, -0.500000f},
{0.951056f, 0.162460f, -0.262866f},
{0.525731f, 0.000000f, -0.850651f},
{0.681718f, 0.147621f, -0.716567f},
{0.681718f, -0.147621f, -0.716567f},
{0.850651f, 0.000000f, -0.525731f},
{0.809017f, -0.309017f, -0.500000f},
{0.864188f, -0.442863f, -0.238856f},
{0.951056f, -0.162460f, -0.262866f},
{0.147621f, 0.716567f, -0.681718f},
{0.309017f, 0.500000f, -0.809017f},
{0.425325f, 0.688191f, -0.587785f},
{0.442863f, 0.238856f, -0.864188f},
{0.587785f, 0.425325f, -0.688191f},
{0.688191f, 0.587785f, -0.425325f},
{-0.147621f, 0.716567f, -0.681718f},
{-0.309017f, 0.500000f, -0.809017f},
{0.000000f, 0.525731f, -0.850651f},
{-0.525731f, 0.000000f, -0.850651f},
{-0.442863f, 0.238856f, -0.864188f},
{-0.295242f, 0.000000f, -0.955423f},
{-0.162460f, 0.262866f, -0.951056f},
{0.000000f, 0.000000f, -1.000000f},
{0.295242f, 0.000000f, -0.955423f},
{0.162460f, 0.262866f, -0.951056f},
{-0.442863f, -0.238856f, -0.864188f},
{-0.309017f, -0.500000f, -0.809017f},
{-0.162460f, -0.262866f, -0.951056f},
{0.000000f, -0.850651f, -0.525731f},
{-0.147621f, -0.716567f, -0.681718f},
{0.147621f, -0.716567f, -0.681718f},
{0.000000f, -0.525731f, -0.850651f},
{0.309017f, -0.500000f, -0.809017f},
{0.442863f, -0.238856f, -0.864188f},
{0.162460f, -0.262866f, -0.951056f},
{0.238856f, -0.864188f, -0.442863f},
{0.500000f, -0.809017f, -0.309017f},
{0.425325f, -0.688191f, -0.587785f},
{0.716567f, -0.681718f, -0.147621f},
{0.688191f, -0.587785f, -0.425325f},
{0.587785f, -0.425325f, -0.688191f},
{0.000000f, -0.955423f, -0.295242f},
{0.000000f, -1.000000f, 0.000000f},
{0.262866f, -0.951056f, -0.162460f},
{0.000000f, -0.850651f, 0.525731f},
{0.000000f, -0.955423f, 0.295242f},
{0.238856f, -0.864188f, 0.442863f},
{0.262866f, -0.951056f, 0.162460f},
{0.500000f, -0.809017f, 0.309017f},
{0.716567f, -0.681718f, 0.147621f},
{0.525731f, -0.850651f, 0.000000f},
{-0.238856f, -0.864188f, -0.442863f},
{-0.500000f, -0.809017f, -0.309017f},
{-0.262866f, -0.951056f, -0.162460f},
{-0.850651f, -0.525731f, 0.000000f},
{-0.716567f, -0.681718f, -0.147621f},
{-0.716567f, -0.681718f, 0.147621f},
{-0.525731f, -0.850651f, 0.000000f},
{-0.500000f, -0.809017f, 0.309017f},
{-0.238856f, -0.864188f, 0.442863f},
{-0.262866f, -0.951056f, 0.162460f},
{-0.864188f, -0.442863f, 0.238856f},
{-0.809017f, -0.309017f, 0.500000f},
{-0.688191f, -0.587785f, 0.425325f},
{-0.681718f, -0.147621f, 0.716567f},
{-0.442863f, -0.238856f, 0.864188f},
{-0.587785f, -0.425325f, 0.688191f},
{-0.309017f, -0.500000f, 0.809017f},
{-0.147621f, -0.716567f, 0.681718f},
{-0.425325f, -0.688191f, 0.587785f},
{-0.162460f, -0.262866f, 0.951056f},
{0.442863f, -0.238856f, 0.864188f},
{0.162460f, -0.262866f, 0.951056f},
{0.309017f, -0.500000f, 0.809017f},
{0.147621f, -0.716567f, 0.681718f},
{0.000000f, -0.525731f, 0.850651f},
{0.425325f, -0.688191f, 0.587785f},
{0.587785f, -0.425325f, 0.688191f},
{0.688191f, -0.587785f, 0.425325f},
{-0.955423f, 0.295242f, 0.000000f},
{-0.951056f, 0.162460f, 0.262866f},
{-1.000000f, 0.000000f, 0.000000f},
{-0.850651f, 0.000000f, 0.525731f},
{-0.955423f, -0.295242f, 0.000000f},
{-0.951056f, -0.162460f, 0.262866f},
{-0.864188f, 0.442863f, -0.238856f},
{-0.951056f, 0.162460f, -0.262866f},
{-0.809017f, 0.309017f, -0.500000f},
{-0.864188f, -0.442863f, -0.238856f},
{-0.951056f, -0.162460f, -0.262866f},
{-0.809017f, -0.309017f, -0.500000f},
{-0.681718f, 0.147621f, -0.716567f},
{-0.681718f, -0.147621f, -0.716567f},
{-0.850651f, 0.000000f, -0.525731f},
{-0.688191f, 0.587785f, -0.425325f},
{-0.587785f, 0.425325f, -0.688191f},
{-0.425325f, 0.688191f, -0.587785f},
{-0.425325f, -0.688191f, -0.587785f},
{-0.587785f, -0.425325f, -0.688191f},
{-0.688191f, -0.587785f, -0.425325f},
};
md2_t md2_models[NUMSPRITES]; md2_t md2_models[NUMSPRITES];
md2_t md2_playermodels[MAXSKINS]; md2_t md2_playermodels[MAXSKINS];
@ -248,198 +83,29 @@ md2_t md2_playermodels[MAXSKINS];
/* /*
* free model * free model
*/ */
static void md2_freeModel (md2_model_t *model) #if 0
static void md2_freeModel (model_t *model)
{ {
if (model) UnloadModel(model);
{
if (model->skins)
free(model->skins);
if (model->texCoords)
free(model->texCoords);
if (model->triangles)
free(model->triangles);
if (model->frames)
{
size_t i;
for (i = 0; i < model->header.numFrames; i++)
{
if (model->frames[i].vertices)
free(model->frames[i].vertices);
}
free(model->frames);
}
if (model->glCommandBuffer)
free(model->glCommandBuffer);
free(model);
}
} }
#endif
// //
// load model // load model
// //
// Hurdler: the current path is the Legacy.exe path // Hurdler: the current path is the Legacy.exe path
static md2_model_t *md2_readModel(const char *filename) static model_t *md2_readModel(const char *filename)
{ {
FILE *file;
md2_model_t *model;
UINT8 buffer[MD2_MAX_FRAMESIZE];
size_t i;
model = calloc(1, sizeof (*model));
if (model == NULL)
return 0;
//Filename checking fixed ~Monster Iestyn and Golden //Filename checking fixed ~Monster Iestyn and Golden
file = fopen(va("%s"PATHSEP"%s", srb2home, filename), "rb"); if (FIL_FileExists(va("%s"PATHSEP"%s", srb2home, filename)))
if (!file) return LoadModel(va("%s"PATHSEP"%s", srb2home, filename), PU_STATIC);
{ else if (FIL_FileExists(va("%s"PATHSEP"%s", srb2path, filename)))
file = fopen(va("%s"PATHSEP"%s", srb2path, filename), "rb"); return LoadModel(va("%s"PATHSEP"%s", srb2path, filename), PU_STATIC);
if (!file) return NULL;
{
free(model);
return 0;
}
}
// initialize model and read header
if (fread(&model->header, sizeof (model->header), 1, file) != 1
|| model->header.magic != MD2_IDENT
|| model->header.version != MD2_VERSION)
{
fclose(file);
free(model);
return 0;
}
model->header.numSkins = 1;
#define MD2LIMITCHECK(field, max, msgname) \
if (field > max) \
{ \
CONS_Alert(CONS_ERROR, "md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d)\n", filename, field, max); \
md2_freeModel (model); \
fclose(file); \
return 0; \
}
// Uncomment if these are actually needed
// MD2LIMITCHECK(model->header.numSkins, MD2_MAX_SKINS, "skins")
// MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates")
MD2LIMITCHECK(model->header.numTriangles, MD2_MAX_TRIANGLES, "triangles")
MD2LIMITCHECK(model->header.numFrames, MD2_MAX_FRAMES, "frames")
MD2LIMITCHECK(model->header.numVertices, MD2_MAX_VERTICES, "vertices")
#undef MD2LIMITCHECK
// read skins
fseek(file, model->header.offsetSkins, SEEK_SET);
if (model->header.numSkins > 0)
{
model->skins = calloc(sizeof (md2_skin_t), model->header.numSkins);
if (!model->skins || model->header.numSkins !=
fread(model->skins, sizeof (md2_skin_t), model->header.numSkins, file))
{
md2_freeModel (model);
fclose(file);
return 0;
}
}
// read texture coordinates
fseek(file, model->header.offsetTexCoords, SEEK_SET);
if (model->header.numTexCoords > 0)
{
model->texCoords = calloc(sizeof (md2_textureCoordinate_t), model->header.numTexCoords);
if (!model->texCoords || model->header.numTexCoords !=
fread(model->texCoords, sizeof (md2_textureCoordinate_t), model->header.numTexCoords, file))
{
md2_freeModel (model);
fclose(file);
return 0;
}
}
// read triangles
fseek(file, model->header.offsetTriangles, SEEK_SET);
if (model->header.numTriangles > 0)
{
model->triangles = calloc(sizeof (md2_triangle_t), model->header.numTriangles);
if (!model->triangles || model->header.numTriangles !=
fread(model->triangles, sizeof (md2_triangle_t), model->header.numTriangles, file))
{
md2_freeModel (model);
fclose(file);
return 0;
}
}
// read alias frames
fseek(file, model->header.offsetFrames, SEEK_SET);
if (model->header.numFrames > 0)
{
model->frames = calloc(sizeof (md2_frame_t), model->header.numFrames);
if (!model->frames)
{
md2_freeModel (model);
fclose(file);
return 0;
}
for (i = 0; i < model->header.numFrames; i++)
{
md2_alias_frame_t *frame = (md2_alias_frame_t *)(void *)buffer;
size_t j;
model->frames[i].vertices = calloc(sizeof (md2_triangleVertex_t), model->header.numVertices);
if (!model->frames[i].vertices || model->header.frameSize !=
fread(frame, 1, model->header.frameSize, file))
{
md2_freeModel (model);
fclose(file);
return 0;
}
strcpy(model->frames[i].name, frame->name);
for (j = 0; j < model->header.numVertices; j++)
{
model->frames[i].vertices[j].vertex[0] = (float) ((INT32) frame->alias_vertices[j].vertex[0]) * frame->scale[0] + frame->translate[0];
model->frames[i].vertices[j].vertex[2] = -1* ((float) ((INT32) frame->alias_vertices[j].vertex[1]) * frame->scale[1] + frame->translate[1]);
model->frames[i].vertices[j].vertex[1] = (float) ((INT32) frame->alias_vertices[j].vertex[2]) * frame->scale[2] + frame->translate[2];
model->frames[i].vertices[j].normal[0] = avertexnormals[frame->alias_vertices[j].lightNormalIndex][0];
model->frames[i].vertices[j].normal[1] = avertexnormals[frame->alias_vertices[j].lightNormalIndex][1];
model->frames[i].vertices[j].normal[2] = avertexnormals[frame->alias_vertices[j].lightNormalIndex][2];
}
}
}
// read gl commands
fseek(file, model->header.offsetGlCommands, SEEK_SET);
if (model->header.numGlCommands)
{
model->glCommandBuffer = calloc(sizeof (INT32), model->header.numGlCommands);
if (!model->glCommandBuffer || model->header.numGlCommands !=
fread(model->glCommandBuffer, sizeof (INT32), model->header.numGlCommands, file))
{
md2_freeModel (model);
fclose(file);
return 0;
}
}
fclose(file);
return model;
} }
static inline void md2_printModelInfo (md2_model_t *model) static inline void md2_printModelInfo (model_t *model)
{ {
#if 0 #if 0
INT32 i; INT32 i;
@ -498,13 +164,13 @@ static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_
#endif #endif
volatile png_FILE_p png_FILE; volatile png_FILE_p png_FILE;
//Filename checking fixed ~Monster Iestyn and Golden //Filename checking fixed ~Monster Iestyn and Golden
char *pngfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename); char *pngfilename = va("%s"PATHSEP"mdls"PATHSEP"%s", srb2home, filename);
FIL_ForceExtension(pngfilename, ".png"); FIL_ForceExtension(pngfilename, ".png");
png_FILE = fopen(pngfilename, "rb"); png_FILE = fopen(pngfilename, "rb");
if (!png_FILE) if (!png_FILE)
{ {
pngfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2path, filename); pngfilename = va("%s"PATHSEP"mdls"PATHSEP"%s", srb2path, filename);
FIL_ForceExtension(pngfilename, ".png"); FIL_ForceExtension(pngfilename, ".png");
png_FILE = fopen(pngfilename, "rb"); png_FILE = fopen(pngfilename, "rb");
//CONS_Debug(DBG_RENDER, "M_SavePNG: Error on opening %s for loading\n", filename); //CONS_Debug(DBG_RENDER, "M_SavePNG: Error on opening %s for loading\n", filename);
@ -631,13 +297,13 @@ static GrTextureFormat_t PCX_Load(const char *filename, int *w, int *h,
INT32 ch, rep; INT32 ch, rep;
FILE *file; FILE *file;
//Filename checking fixed ~Monster Iestyn and Golden //Filename checking fixed ~Monster Iestyn and Golden
char *pcxfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename); char *pcxfilename = va("%s"PATHSEP"mdls"PATHSEP"%s", srb2home, filename);
FIL_ForceExtension(pcxfilename, ".pcx"); FIL_ForceExtension(pcxfilename, ".pcx");
file = fopen(pcxfilename, "rb"); file = fopen(pcxfilename, "rb");
if (!file) if (!file)
{ {
pcxfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2path, filename); pcxfilename = va("%s"PATHSEP"mdls"PATHSEP"%s", srb2path, filename);
FIL_ForceExtension(pcxfilename, ".pcx"); FIL_ForceExtension(pcxfilename, ".pcx");
file = fopen(pcxfilename, "rb"); file = fopen(pcxfilename, "rb");
if (!file) if (!file)
@ -826,16 +492,16 @@ void HWR_InitMD2(void)
md2_models[i].error = false; md2_models[i].error = false;
} }
// read the md2.dat file // read the mdls.dat file
//Filename checking fixed ~Monster Iestyn and Golden //Filename checking fixed ~Monster Iestyn and Golden
f = fopen(va("%s"PATHSEP"%s", srb2home, "kmd2.dat"), "rt"); f = fopen(va("%s"PATHSEP"%s", srb2home, "mdls.dat"), "rt");
if (!f) if (!f)
{ {
f = fopen(va("%s"PATHSEP"%s", srb2path, "kmd2.dat"), "rt"); f = fopen(va("%s"PATHSEP"%s", srb2path, "mdls.dat"), "rt");
if (!f) if (!f)
{ {
CONS_Printf("%s %s\n", M_GetText("Error while loading kmd2.dat:"), strerror(errno)); CONS_Printf("%s %s\n", M_GetText("Error while loading mdls.dat:"), strerror(errno));
nomd2s = true; nomd2s = true;
return; return;
} }
@ -844,7 +510,7 @@ void HWR_InitMD2(void)
{ {
/*if (stricmp(name, "PLAY") == 0) /*if (stricmp(name, "PLAY") == 0)
{ {
CONS_Printf("MD2 for sprite PLAY detected in kmd2.dat, use a player skin instead!\n"); CONS_Printf("MD2 for sprite PLAY detected in mdls.dat, use a player skin instead!\n");
continue; continue;
}*/ }*/
// 8/1/19: Allow PLAY to load for default MD2. // 8/1/19: Allow PLAY to load for default MD2.
@ -879,7 +545,7 @@ void HWR_InitMD2(void)
} }
} }
// no sprite/player skin name found?!? // no sprite/player skin name found?!?
CONS_Printf("Unknown sprite/player skin %s detected in kmd2.dat\n", name); CONS_Printf("Unknown sprite/player skin %s detected in mdls.dat\n", name);
md2found: md2found:
// move on to next line... // move on to next line...
continue; continue;
@ -898,16 +564,16 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup
CONS_Printf("AddPlayerMD2()...\n"); CONS_Printf("AddPlayerMD2()...\n");
// read the md2.dat file // read the mdls.dat file
//Filename checking fixed ~Monster Iestyn and Golden //Filename checking fixed ~Monster Iestyn and Golden
f = fopen(va("%s"PATHSEP"%s", srb2home, "kmd2.dat"), "rt"); f = fopen(va("%s"PATHSEP"%s", srb2home, "mdls.dat"), "rt");
if (!f) if (!f)
{ {
f = fopen(va("%s"PATHSEP"%s", srb2path, "kmd2.dat"), "rt"); f = fopen(va("%s"PATHSEP"%s", srb2path, "mdls.dat"), "rt");
if (!f) if (!f)
{ {
CONS_Printf("%s %s\n", M_GetText("Error while loading kmd2.dat:"), strerror(errno)); CONS_Printf("%s %s\n", M_GetText("Error while loading mdls.dat:"), strerror(errno));
nomd2s = true; nomd2s = true;
return; return;
} }
@ -937,7 +603,7 @@ playermd2found:
void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startup void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startup
{ {
FILE *f; FILE *f;
// name[18] is used to check for names in the kmd2.dat file that match with sprites or player skins // name[18] is used to check for names in the mdls.dat file that match with sprites or player skins
// sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long // sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long
char name[18], filename[32]; char name[18], filename[32];
float scale, offset; float scale, offset;
@ -950,20 +616,20 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu
// Read the md2.dat file // Read the md2.dat file
//Filename checking fixed ~Monster Iestyn and Golden //Filename checking fixed ~Monster Iestyn and Golden
f = fopen(va("%s"PATHSEP"%s", srb2home, "kmd2.dat"), "rt"); f = fopen(va("%s"PATHSEP"%s", srb2home, "mdls.dat"), "rt");
if (!f) if (!f)
{ {
f = fopen(va("%s"PATHSEP"%s", srb2path, "kmd2.dat"), "rt"); f = fopen(va("%s"PATHSEP"%s", srb2path, "mdls.dat"), "rt");
if (!f) if (!f)
{ {
CONS_Printf("%s %s\n", M_GetText("Error while loading kmd2.dat:"), strerror(errno)); CONS_Printf("%s %s\n", M_GetText("Error while loading mdls.dat:"), strerror(errno));
nomd2s = true; nomd2s = true;
return; return;
} }
} }
// Check for any MD2s that match the names of player skins! // Check for any MD2s that match the names of sprite names!
while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4)
{ {
if (stricmp(name, sprnames[spritenum]) == 0) if (stricmp(name, sprnames[spritenum]) == 0)
@ -1195,12 +861,13 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
FSurfaceInfo Surf; FSurfaceInfo Surf;
char filename[64]; char filename[64];
INT32 frame; INT32 frame = 0;
INT32 nextFrame = -1;
FTransform p; FTransform p;
md2_t *md2; md2_t *md2;
UINT8 color[4]; UINT8 color[4];
if (!cv_grmd2.value) if (!cv_grmdls.value)
return; return;
if (spr->precip) if (spr->precip)
@ -1248,10 +915,9 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
// Look at HWR_ProjectSprite for more // Look at HWR_ProjectSprite for more
{ {
GLPatch_t *gpatch; GLPatch_t *gpatch;
INT32 *buff;
INT32 durs = spr->mobj->state->tics; INT32 durs = spr->mobj->state->tics;
INT32 tics = spr->mobj->tics; INT32 tics = spr->mobj->tics;
md2_frame_t *curr, *next = NULL; //mdlframe_t *next = NULL;
const UINT8 flip = (UINT8)((spr->mobj->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP); const UINT8 flip = (UINT8)((spr->mobj->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP);
spritedef_t *sprdef; spritedef_t *sprdef;
spriteframe_t *sprframe; spriteframe_t *sprframe;
@ -1285,13 +951,14 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
return; // we already failed loading this before :( return; // we already failed loading this before :(
if (!md2->model) if (!md2->model)
{ {
CONS_Debug(DBG_RENDER, "Loading MD2... (%s, %s)", sprnames[spr->mobj->sprite], md2->filename); CONS_Debug(DBG_RENDER, "Loading model... (%s, %s)", sprnames[spr->mobj->sprite], md2->filename);
sprintf(filename, "md2/%s", md2->filename); sprintf(filename, "mdls/%s", md2->filename);
md2->model = md2_readModel(filename); md2->model = md2_readModel(filename);
if (md2->model) if (md2->model)
{ {
md2_printModelInfo(md2->model); md2_printModelInfo(md2->model);
HWD.pfnCreateModelVBOs(md2->model);
} }
else else
{ {
@ -1364,27 +1031,27 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
} }
//FIXME: this is not yet correct //FIXME: this is not yet correct
frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->header.numFrames; frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->meshes[0].numFrames;
buff = md2->model->glCommandBuffer;
curr = &md2->model->frames[frame]; #ifdef USE_MODEL_NEXTFRAME
#if 0 if (cv_grmdls.value == 1 && tics <= durs)
if (cv_grmd2.value == 1 && tics <= durs)
{ {
// frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation // frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation
if (spr->mobj->frame & FF_ANIMATE) if (spr->mobj->frame & FF_ANIMATE)
{ {
UINT32 nextframe = (spr->mobj->frame & FF_FRAMEMASK) + 1; nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1;
if (nextframe >= (UINT32)spr->mobj->state->var1) if (nextFrame >= spr->mobj->state->var1)
nextframe = (spr->mobj->state->frame & FF_FRAMEMASK); nextFrame = (spr->mobj->state->frame & FF_FRAMEMASK);
nextframe %= md2->model->header.numFrames; nextFrame %= md2->model->meshes[0].numFrames;
next = &md2->model->frames[nextframe]; //next = &md2->model->meshes[0].frames[nextFrame];
} }
else else
{ {
if (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL) if (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL
&& !(spr->mobj->player && (spr->mobj->state->nextstate == S_PLAY_TAP1 || spr->mobj->state->nextstate == S_PLAY_TAP2) && spr->mobj->state == &states[S_PLAY_STND]))
{ {
const UINT32 nextframe = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->header.numFrames; nextFrame = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->meshes[0].numFrames;
next = &md2->model->frames[nextframe]; //next = &md2->model->meshes[0].frames[nextFrame];
} }
} }
} }
@ -1421,6 +1088,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
p.angley = FIXED_TO_FLOAT(anglef); p.angley = FIXED_TO_FLOAT(anglef);
} }
p.anglex = 0.0f; p.anglex = 0.0f;
#ifdef USE_FTRANSFORM_ANGLEZ
// Slope rotation from Kart
p.anglez = 0.0f; p.anglez = 0.0f;
if (spr->mobj->standingslope) if (spr->mobj->standingslope)
{ {
@ -1432,7 +1101,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy)); tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy));
p.anglex = FIXED_TO_FLOAT(tempangle); p.anglex = FIXED_TO_FLOAT(tempangle);
} }
#endif
color[0] = Surf.FlatColor.s.red; color[0] = Surf.FlatColor.s.red;
color[1] = Surf.FlatColor.s.green; color[1] = Surf.FlatColor.s.green;
@ -1443,9 +1112,11 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
finalscale *= FIXED_TO_FLOAT(spr->mobj->scale); finalscale *= FIXED_TO_FLOAT(spr->mobj->scale);
p.flip = atransform.flip; p.flip = atransform.flip;
p.mirror = atransform.mirror; #ifdef USE_FTRANSFORM_MIRROR
p.mirror = atransform.mirror; // from Kart
#endif
HWD.pfnDrawMD2i(buff, curr, durs, tics, next, &p, finalscale, flip, color); HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, color);
} }
} }

View file

@ -22,97 +22,7 @@
#define _HW_MD2_H_ #define _HW_MD2_H_
#include "hw_glob.h" #include "hw_glob.h"
#include "hw_model.h"
// magic number "IDP2" or 844121161
#define MD2_IDENT (INT32)(('2' << 24) + ('P' << 16) + ('D' << 8) + 'I')
// model version
#define MD2_VERSION 8
#define MD2_MAX_TRIANGLES 16384
#define MD2_MAX_VERTICES 4096
#define MD2_MAX_TEXCOORDS 4096
#define MD2_MAX_FRAMES 512
#define MD2_MAX_SKINS 32
#define MD2_MAX_FRAMESIZE (MD2_MAX_VERTICES * 4 + 128)
#if defined(_MSC_VER)
#pragma pack(1)
#endif
typedef struct
{
UINT32 magic;
UINT32 version;
UINT32 skinWidth;
UINT32 skinHeight;
UINT32 frameSize;
UINT32 numSkins;
UINT32 numVertices;
UINT32 numTexCoords;
UINT32 numTriangles;
UINT32 numGlCommands;
UINT32 numFrames;
UINT32 offsetSkins;
UINT32 offsetTexCoords;
UINT32 offsetTriangles;
UINT32 offsetFrames;
UINT32 offsetGlCommands;
UINT32 offsetEnd;
} ATTRPACK md2_header_t; //NOTE: each of md2_header's members are 4 unsigned bytes
typedef struct
{
UINT8 vertex[3];
UINT8 lightNormalIndex;
} ATTRPACK md2_alias_triangleVertex_t;
typedef struct
{
float vertex[3];
float normal[3];
} ATTRPACK md2_triangleVertex_t;
typedef struct
{
INT16 vertexIndices[3];
INT16 textureIndices[3];
} ATTRPACK md2_triangle_t;
typedef struct
{
INT16 s, t;
} ATTRPACK md2_textureCoordinate_t;
typedef struct
{
float scale[3];
float translate[3];
char name[16];
md2_alias_triangleVertex_t alias_vertices[1];
} ATTRPACK md2_alias_frame_t;
typedef struct
{
char name[16];
md2_triangleVertex_t *vertices;
} ATTRPACK md2_frame_t;
typedef char md2_skin_t[64];
typedef struct
{
float s, t;
INT32 vertexIndex;
} ATTRPACK md2_glCommandVertex_t;
typedef struct
{
md2_header_t header;
md2_skin_t *skins;
md2_textureCoordinate_t *texCoords;
md2_triangle_t *triangles;
md2_frame_t *frames;
INT32 *glCommandBuffer;
} ATTRPACK md2_model_t;
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack() #pragma pack()
@ -123,7 +33,7 @@ typedef struct
char filename[32]; char filename[32];
float scale; float scale;
float offset; float offset;
md2_model_t *model; model_t *model;
void *grpatch; void *grpatch;
void *blendgrpatch; void *blendgrpatch;
boolean notfound; boolean notfound;

564
src/hardware/hw_md2load.c Normal file
View file

@ -0,0 +1,564 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../doomdef.h"
#include "hw_md2load.h"
#include "hw_model.h"
#include "../z_zone.h"
#define NUMVERTEXNORMALS 162
// Quake 2 normals are indexed. Use avertexnormals[normalindex][x/y/z] and
// you'll have your normals.
float avertexnormals[NUMVERTEXNORMALS][3] = {
{-0.525731f, 0.000000f, 0.850651f},
{-0.442863f, 0.238856f, 0.864188f},
{-0.295242f, 0.000000f, 0.955423f},
{-0.309017f, 0.500000f, 0.809017f},
{-0.162460f, 0.262866f, 0.951056f},
{0.000000f, 0.000000f, 1.000000f},
{0.000000f, 0.850651f, 0.525731f},
{-0.147621f, 0.716567f, 0.681718f},
{0.147621f, 0.716567f, 0.681718f},
{0.000000f, 0.525731f, 0.850651f},
{0.309017f, 0.500000f, 0.809017f},
{0.525731f, 0.000000f, 0.850651f},
{0.295242f, 0.000000f, 0.955423f},
{0.442863f, 0.238856f, 0.864188f},
{0.162460f, 0.262866f, 0.951056f},
{-0.681718f, 0.147621f, 0.716567f},
{-0.809017f, 0.309017f, 0.500000f},
{-0.587785f, 0.425325f, 0.688191f},
{-0.850651f, 0.525731f, 0.000000f},
{-0.864188f, 0.442863f, 0.238856f},
{-0.716567f, 0.681718f, 0.147621f},
{-0.688191f, 0.587785f, 0.425325f},
{-0.500000f, 0.809017f, 0.309017f},
{-0.238856f, 0.864188f, 0.442863f},
{-0.425325f, 0.688191f, 0.587785f},
{-0.716567f, 0.681718f, -0.147621f},
{-0.500000f, 0.809017f, -0.309017f},
{-0.525731f, 0.850651f, 0.000000f},
{0.000000f, 0.850651f, -0.525731f},
{-0.238856f, 0.864188f, -0.442863f},
{0.000000f, 0.955423f, -0.295242f},
{-0.262866f, 0.951056f, -0.162460f},
{0.000000f, 1.000000f, 0.000000f},
{0.000000f, 0.955423f, 0.295242f},
{-0.262866f, 0.951056f, 0.162460f},
{0.238856f, 0.864188f, 0.442863f},
{0.262866f, 0.951056f, 0.162460f},
{0.500000f, 0.809017f, 0.309017f},
{0.238856f, 0.864188f, -0.442863f},
{0.262866f, 0.951056f, -0.162460f},
{0.500000f, 0.809017f, -0.309017f},
{0.850651f, 0.525731f, 0.000000f},
{0.716567f, 0.681718f, 0.147621f},
{0.716567f, 0.681718f, -0.147621f},
{0.525731f, 0.850651f, 0.000000f},
{0.425325f, 0.688191f, 0.587785f},
{0.864188f, 0.442863f, 0.238856f},
{0.688191f, 0.587785f, 0.425325f},
{0.809017f, 0.309017f, 0.500000f},
{0.681718f, 0.147621f, 0.716567f},
{0.587785f, 0.425325f, 0.688191f},
{0.955423f, 0.295242f, 0.000000f},
{1.000000f, 0.000000f, 0.000000f},
{0.951056f, 0.162460f, 0.262866f},
{0.850651f, -0.525731f, 0.000000f},
{0.955423f, -0.295242f, 0.000000f},
{0.864188f, -0.442863f, 0.238856f},
{0.951056f, -0.162460f, 0.262866f},
{0.809017f, -0.309017f, 0.500000f},
{0.681718f, -0.147621f, 0.716567f},
{0.850651f, 0.000000f, 0.525731f},
{0.864188f, 0.442863f, -0.238856f},
{0.809017f, 0.309017f, -0.500000f},
{0.951056f, 0.162460f, -0.262866f},
{0.525731f, 0.000000f, -0.850651f},
{0.681718f, 0.147621f, -0.716567f},
{0.681718f, -0.147621f, -0.716567f},
{0.850651f, 0.000000f, -0.525731f},
{0.809017f, -0.309017f, -0.500000f},
{0.864188f, -0.442863f, -0.238856f},
{0.951056f, -0.162460f, -0.262866f},
{0.147621f, 0.716567f, -0.681718f},
{0.309017f, 0.500000f, -0.809017f},
{0.425325f, 0.688191f, -0.587785f},
{0.442863f, 0.238856f, -0.864188f},
{0.587785f, 0.425325f, -0.688191f},
{0.688191f, 0.587785f, -0.425325f},
{-0.147621f, 0.716567f, -0.681718f},
{-0.309017f, 0.500000f, -0.809017f},
{0.000000f, 0.525731f, -0.850651f},
{-0.525731f, 0.000000f, -0.850651f},
{-0.442863f, 0.238856f, -0.864188f},
{-0.295242f, 0.000000f, -0.955423f},
{-0.162460f, 0.262866f, -0.951056f},
{0.000000f, 0.000000f, -1.000000f},
{0.295242f, 0.000000f, -0.955423f},
{0.162460f, 0.262866f, -0.951056f},
{-0.442863f, -0.238856f, -0.864188f},
{-0.309017f, -0.500000f, -0.809017f},
{-0.162460f, -0.262866f, -0.951056f},
{0.000000f, -0.850651f, -0.525731f},
{-0.147621f, -0.716567f, -0.681718f},
{0.147621f, -0.716567f, -0.681718f},
{0.000000f, -0.525731f, -0.850651f},
{0.309017f, -0.500000f, -0.809017f},
{0.442863f, -0.238856f, -0.864188f},
{0.162460f, -0.262866f, -0.951056f},
{0.238856f, -0.864188f, -0.442863f},
{0.500000f, -0.809017f, -0.309017f},
{0.425325f, -0.688191f, -0.587785f},
{0.716567f, -0.681718f, -0.147621f},
{0.688191f, -0.587785f, -0.425325f},
{0.587785f, -0.425325f, -0.688191f},
{0.000000f, -0.955423f, -0.295242f},
{0.000000f, -1.000000f, 0.000000f},
{0.262866f, -0.951056f, -0.162460f},
{0.000000f, -0.850651f, 0.525731f},
{0.000000f, -0.955423f, 0.295242f},
{0.238856f, -0.864188f, 0.442863f},
{0.262866f, -0.951056f, 0.162460f},
{0.500000f, -0.809017f, 0.309017f},
{0.716567f, -0.681718f, 0.147621f},
{0.525731f, -0.850651f, 0.000000f},
{-0.238856f, -0.864188f, -0.442863f},
{-0.500000f, -0.809017f, -0.309017f},
{-0.262866f, -0.951056f, -0.162460f},
{-0.850651f, -0.525731f, 0.000000f},
{-0.716567f, -0.681718f, -0.147621f},
{-0.716567f, -0.681718f, 0.147621f},
{-0.525731f, -0.850651f, 0.000000f},
{-0.500000f, -0.809017f, 0.309017f},
{-0.238856f, -0.864188f, 0.442863f},
{-0.262866f, -0.951056f, 0.162460f},
{-0.864188f, -0.442863f, 0.238856f},
{-0.809017f, -0.309017f, 0.500000f},
{-0.688191f, -0.587785f, 0.425325f},
{-0.681718f, -0.147621f, 0.716567f},
{-0.442863f, -0.238856f, 0.864188f},
{-0.587785f, -0.425325f, 0.688191f},
{-0.309017f, -0.500000f, 0.809017f},
{-0.147621f, -0.716567f, 0.681718f},
{-0.425325f, -0.688191f, 0.587785f},
{-0.162460f, -0.262866f, 0.951056f},
{0.442863f, -0.238856f, 0.864188f},
{0.162460f, -0.262866f, 0.951056f},
{0.309017f, -0.500000f, 0.809017f},
{0.147621f, -0.716567f, 0.681718f},
{0.000000f, -0.525731f, 0.850651f},
{0.425325f, -0.688191f, 0.587785f},
{0.587785f, -0.425325f, 0.688191f},
{0.688191f, -0.587785f, 0.425325f},
{-0.955423f, 0.295242f, 0.000000f},
{-0.951056f, 0.162460f, 0.262866f},
{-1.000000f, 0.000000f, 0.000000f},
{-0.850651f, 0.000000f, 0.525731f},
{-0.955423f, -0.295242f, 0.000000f},
{-0.951056f, -0.162460f, 0.262866f},
{-0.864188f, 0.442863f, -0.238856f},
{-0.951056f, 0.162460f, -0.262866f},
{-0.809017f, 0.309017f, -0.500000f},
{-0.864188f, -0.442863f, -0.238856f},
{-0.951056f, -0.162460f, -0.262866f},
{-0.809017f, -0.309017f, -0.500000f},
{-0.681718f, 0.147621f, -0.716567f},
{-0.681718f, -0.147621f, -0.716567f},
{-0.850651f, 0.000000f, -0.525731f},
{-0.688191f, 0.587785f, -0.425325f},
{-0.587785f, 0.425325f, -0.688191f},
{-0.425325f, 0.688191f, -0.587785f},
{-0.425325f, -0.688191f, -0.587785f},
{-0.587785f, -0.425325f, -0.688191f},
{-0.688191f, -0.587785f, -0.425325f},
};
typedef struct
{
int ident; // A "magic number" that's used to identify the .md2 file
int version; // The version of the file, always 8
int skinwidth; // Width of the skin(s) in pixels
int skinheight; // Height of the skin(s) in pixels
int framesize; // Size of each frame in bytes
int numSkins; // Number of skins with the model
int numXYZ; // Number of vertices in each frame
int numST; // Number of texture coordinates in each frame.
int numTris; // Number of triangles in each frame
int numGLcmds; // Number of dwords (4 bytes) in the gl command list.
int numFrames; // Number of frames
int offsetSkins; // Offset, in bytes from the start of the file, to the list of skin names.
int offsetST; // Offset, in bytes from the start of the file, to the list of texture coordinates
int offsetTris; // Offset, in bytes from the start of the file, to the list of triangles
int offsetFrames; // Offset, in bytes from the start of the file, to the list of frames
int offsetGLcmds; // Offset, in bytes from the start of the file, to the list of gl commands
int offsetEnd; // Offset, in bytes from the start of the file, to the end of the file (filesize)
} md2header_t;
typedef struct
{
unsigned short meshIndex[3]; // indices into the array of vertices in each frames
unsigned short stIndex[3]; // indices into the array of texture coordinates
} md2triangle_t;
typedef struct
{
short s;
short t;
} md2texcoord_t;
typedef struct
{
unsigned char v[3]; // Scaled vertices. You'll need to multiply them with scale[x] to make them normal.
unsigned char lightNormalIndex; // Index to the array of normals
} md2vertex_t;
typedef struct
{
float scale[3]; // Used by the v member in the md2framePoint structure
float translate[3]; // Used by the v member in the md2framePoint structure
char name[16]; // Name of the frame
} md2frame_t;
// Load the model
model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat)
{
FILE *f;
model_t *retModel = NULL;
md2header_t *header;
size_t fileLen;
int i, j;
size_t namelen;
char *texturefilename;
const char *texPos;
char *buffer;
const float WUNITS = 1.0f;
float dataScale = WUNITS;
md2triangle_t *tris;
md2texcoord_t *texcoords;
md2frame_t *frames;
int t;
// MD2 currently does not work with tinyframes, so force useFloat = true
//
// <SSNTails>
// the UV coordinates in MD2 are not compatible with glDrawElements like MD3 is. So they need to be loaded as full float.
//
// MD2 is intended to be draw in triangle strips and fans
// not very compatible with a modern GL implementation, either
// so the idea would be to full float expand it, and put it in a vertex buffer object
// I'm sure there's a way to convert the UVs to 'tinyframes', but maybe that's a job for someone else.
// You'd have to decompress the model, then recompress, reindexing the triangles and weeding out duplicate coordinates
// I already have the decompression work done
useFloat = true;
f = fopen(fileName, "rb");
if (!f)
return NULL;
retModel = (model_t*)Z_Calloc(sizeof(model_t), ztag, 0);
//size_t fileLen;
//int i, j;
//size_t namelen;
//char *texturefilename;
texPos = strchr(fileName, '/');
if (texPos)
{
texPos++;
namelen = strlen(texPos) + 1;
texturefilename = (char*)Z_Malloc(namelen, PU_CACHE, 0);
strcpy(texturefilename, texPos);
}
else
{
namelen = strlen(fileName) + 1;
texturefilename = (char*)Z_Malloc(namelen, PU_CACHE, 0);
strcpy(texturefilename, fileName);
}
texturefilename[namelen - 2] = 'z';
texturefilename[namelen - 3] = 'u';
texturefilename[namelen - 4] = 'b';
// find length of file
fseek(f, 0, SEEK_END);
fileLen = ftell(f);
fseek(f, 0, SEEK_SET);
// read in file
buffer = malloc(fileLen);
if (fread(buffer, fileLen, 1, f)) { } // squash ignored fread error
fclose(f);
// get pointer to file header
header = (md2header_t*)buffer;
retModel->numMeshes = 1; // MD2 only has one mesh
retModel->meshes = (mesh_t*)Z_Calloc(sizeof(mesh_t) * retModel->numMeshes, ztag, 0);
retModel->meshes[0].numFrames = header->numFrames;
// const float WUNITS = 1.0f;
// float dataScale = WUNITS;
// Tris and ST are simple structures that can be straight-copied
tris = (md2triangle_t*)&buffer[header->offsetTris];
texcoords = (md2texcoord_t*)&buffer[header->offsetST];
frames = (md2frame_t*)&buffer[header->offsetFrames];
// Read in textures
retModel->numMaterials = header->numSkins;
if (retModel->numMaterials <= 0) // Always at least one skin, duh
retModel->numMaterials = 1;
retModel->materials = (material_t*)Z_Calloc(sizeof(material_t)*retModel->numMaterials, ztag, 0);
// int t;
for (t = 0; t < retModel->numMaterials; t++)
{
retModel->materials[t].ambient[0] = 0.8f;
retModel->materials[t].ambient[1] = 0.8f;
retModel->materials[t].ambient[2] = 0.8f;
retModel->materials[t].ambient[3] = 1.0f;
retModel->materials[t].diffuse[0] = 0.8f;
retModel->materials[t].diffuse[1] = 0.8f;
retModel->materials[t].diffuse[2] = 0.8f;
retModel->materials[t].diffuse[3] = 1.0f;
retModel->materials[t].emissive[0] = 0.0f;
retModel->materials[t].emissive[1] = 0.0f;
retModel->materials[t].emissive[2] = 0.0f;
retModel->materials[t].emissive[3] = 1.0f;
retModel->materials[t].specular[0] = 0.0f;
retModel->materials[t].specular[1] = 0.0f;
retModel->materials[t].specular[2] = 0.0f;
retModel->materials[t].specular[3] = 1.0f;
retModel->materials[t].shininess = 0.0f;
retModel->materials[t].spheremap = false;
/* retModel->materials[t].texture = Texture::ReadTexture((char*)texturefilename, ZT_TEXTURE);
if (!systemSucks)
{
// Check for a normal map...??
char openfilename[1024];
char normalMapName[1024];
strcpy(normalMapName, texturefilename);
size_t len = strlen(normalMapName);
char *ptr = &normalMapName[len];
ptr--; // z
ptr--; // u
ptr--; // b
ptr--; // .
*ptr++ = '_';
*ptr++ = 'n';
*ptr++ = '.';
*ptr++ = 'b';
*ptr++ = 'u';
*ptr++ = 'z';
*ptr++ = '\0';
sprintf(openfilename, "%s/%s", "textures", normalMapName);
// Convert backslashes to forward slashes
for (int k = 0; k < 1024; k++)
{
if (openfilename[k] == '\0')
break;
if (openfilename[k] == '\\')
openfilename[k] = '/';
}
Resource::resource_t *res = Resource::Open(openfilename);
if (res)
{
Resource::Close(res);
retModel->materials[t].lightmap = Texture::ReadTexture(normalMapName, ZT_TEXTURE);
}
}*/
}
retModel->meshes[0].numTriangles = header->numTris;
if (!useFloat) // Decompress to MD3 'tinyframe' space
{
char *ptr;
md2triangle_t *trisPtr;
unsigned short *indexptr;
float *uvptr;
dataScale = 0.015624f; // 1 / 64.0f
retModel->meshes[0].tinyframes = (tinyframe_t*)Z_Calloc(sizeof(tinyframe_t)*header->numFrames, ztag, 0);
retModel->meshes[0].numVertices = header->numXYZ;
retModel->meshes[0].uvs = (float*)Z_Malloc(sizeof(float) * 2 * retModel->meshes[0].numVertices, ztag, 0);
ptr = (char*)frames;
for (i = 0; i < header->numFrames; i++, ptr += header->framesize)
{
short *vertptr;
char *normptr;
// char *tanptr;
md2vertex_t *vertex;
md2frame_t *framePtr = (md2frame_t*)ptr;
retModel->meshes[0].tinyframes[i].vertices = (short*)Z_Malloc(sizeof(short) * 3 * header->numXYZ, ztag, 0);
retModel->meshes[0].tinyframes[i].normals = (char*)Z_Malloc(sizeof(char) * 3 * header->numXYZ, ztag, 0);
// if (retModel->materials[0].lightmap)
// retModel->meshes[0].tinyframes[i].tangents = (char*)malloc(sizeof(char));//(char*)Z_Malloc(sizeof(char)*3*header->numVerts, ztag);
retModel->meshes[0].indices = (unsigned short*)Z_Malloc(sizeof(unsigned short) * 3 * header->numTris, ztag, 0);
vertptr = retModel->meshes[0].tinyframes[i].vertices;
normptr = retModel->meshes[0].tinyframes[i].normals;
// tanptr = retModel->meshes[0].tinyframes[i].tangents;
retModel->meshes[0].tinyframes[i].material = &retModel->materials[0];
framePtr++; // Advance to vertex list
vertex = (md2vertex_t*)framePtr;
framePtr--;
for (j = 0; j < header->numXYZ; j++, vertex++)
{
*vertptr = (short)(((vertex->v[0] * framePtr->scale[0]) + framePtr->translate[0]) / dataScale);
vertptr++;
*vertptr = (short)(((vertex->v[2] * framePtr->scale[2]) + framePtr->translate[2]) / dataScale);
vertptr++;
*vertptr = -1.0f * (short)(((vertex->v[1] * framePtr->scale[1]) + framePtr->translate[1]) / dataScale);
vertptr++;
// Normal
*normptr++ = (char)(avertexnormals[vertex->lightNormalIndex][0] * 127);
*normptr++ = (char)(avertexnormals[vertex->lightNormalIndex][2] * 127);
*normptr++ = (char)(avertexnormals[vertex->lightNormalIndex][1] * 127);
}
}
// This doesn't need to be done every frame!
trisPtr = tris;
indexptr = retModel->meshes[0].indices;
uvptr = (float*)retModel->meshes[0].uvs;
for (j = 0; j < header->numTris; j++, trisPtr++)
{
*indexptr = trisPtr->meshIndex[0];
indexptr++;
*indexptr = trisPtr->meshIndex[1];
indexptr++;
*indexptr = trisPtr->meshIndex[2];
indexptr++;
uvptr[trisPtr->meshIndex[0] * 2] = texcoords[trisPtr->stIndex[0]].s / (float)header->skinwidth;
uvptr[trisPtr->meshIndex[0] * 2 + 1] = (texcoords[trisPtr->stIndex[0]].t / (float)header->skinheight);
uvptr[trisPtr->meshIndex[1] * 2] = texcoords[trisPtr->stIndex[1]].s / (float)header->skinwidth;
uvptr[trisPtr->meshIndex[1] * 2 + 1] = (texcoords[trisPtr->stIndex[1]].t / (float)header->skinheight);
uvptr[trisPtr->meshIndex[2] * 2] = texcoords[trisPtr->stIndex[2]].s / (float)header->skinwidth;
uvptr[trisPtr->meshIndex[2] * 2 + 1] = (texcoords[trisPtr->stIndex[2]].t / (float)header->skinheight);
}
}
else // Full float loading method
{
md2triangle_t *trisPtr;
float *uvptr;
char *ptr;
retModel->meshes[0].numVertices = header->numTris * 3;
retModel->meshes[0].frames = (mdlframe_t*)Z_Calloc(sizeof(mdlframe_t)*header->numFrames, ztag, 0);
retModel->meshes[0].uvs = (float*)Z_Malloc(sizeof(float) * 2 * retModel->meshes[0].numVertices, ztag, 0);
trisPtr = tris;
uvptr = retModel->meshes[0].uvs;
for (i = 0; i < retModel->meshes[0].numTriangles; i++, trisPtr++)
{
*uvptr++ = texcoords[trisPtr->stIndex[0]].s / (float)header->skinwidth;
*uvptr++ = (texcoords[trisPtr->stIndex[0]].t / (float)header->skinheight);
*uvptr++ = texcoords[trisPtr->stIndex[1]].s / (float)header->skinwidth;
*uvptr++ = (texcoords[trisPtr->stIndex[1]].t / (float)header->skinheight);
*uvptr++ = texcoords[trisPtr->stIndex[2]].s / (float)header->skinwidth;
*uvptr++ = (texcoords[trisPtr->stIndex[2]].t / (float)header->skinheight);
}
ptr = (char*)frames;
for (i = 0; i < header->numFrames; i++, ptr += header->framesize)
{
float *vertptr, *normptr;
md2vertex_t *vertex;
md2frame_t *framePtr = (md2frame_t*)ptr;
retModel->meshes[0].frames[i].normals = (float*)Z_Malloc(sizeof(float) * 3 * header->numTris * 3, ztag, 0);
retModel->meshes[0].frames[i].vertices = (float*)Z_Malloc(sizeof(float) * 3 * header->numTris * 3, ztag, 0);
// if (retModel->materials[0].lightmap)
// retModel->meshes[0].frames[i].tangents = (float*)malloc(sizeof(float));//(float*)Z_Malloc(sizeof(float)*3*header->numTris*3, ztag);
//float *vertptr, *normptr;
normptr = (float*)retModel->meshes[0].frames[i].normals;
vertptr = (float*)retModel->meshes[0].frames[i].vertices;
trisPtr = tris;
retModel->meshes[0].frames[i].material = &retModel->materials[0];
framePtr++; // Advance to vertex list
vertex = (md2vertex_t*)framePtr;
framePtr--;
for (j = 0; j < header->numTris; j++, trisPtr++)
{
*vertptr = ((vertex[trisPtr->meshIndex[0]].v[0] * framePtr->scale[0]) + framePtr->translate[0]) * WUNITS;
vertptr++;
*vertptr = ((vertex[trisPtr->meshIndex[0]].v[2] * framePtr->scale[2]) + framePtr->translate[2]) * WUNITS;
vertptr++;
*vertptr = -1.0f * ((vertex[trisPtr->meshIndex[0]].v[1] * framePtr->scale[1]) + framePtr->translate[1]) * WUNITS;
vertptr++;
*vertptr = ((vertex[trisPtr->meshIndex[1]].v[0] * framePtr->scale[0]) + framePtr->translate[0]) * WUNITS;
vertptr++;
*vertptr = ((vertex[trisPtr->meshIndex[1]].v[2] * framePtr->scale[2]) + framePtr->translate[2]) * WUNITS;
vertptr++;
*vertptr = -1.0f * ((vertex[trisPtr->meshIndex[1]].v[1] * framePtr->scale[1]) + framePtr->translate[1]) * WUNITS;
vertptr++;
*vertptr = ((vertex[trisPtr->meshIndex[2]].v[0] * framePtr->scale[0]) + framePtr->translate[0]) * WUNITS;
vertptr++;
*vertptr = ((vertex[trisPtr->meshIndex[2]].v[2] * framePtr->scale[2]) + framePtr->translate[2]) * WUNITS;
vertptr++;
*vertptr = -1.0f * ((vertex[trisPtr->meshIndex[2]].v[1] * framePtr->scale[1]) + framePtr->translate[1]) * WUNITS;
vertptr++;
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[0]].lightNormalIndex][0];
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[0]].lightNormalIndex][2];
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[0]].lightNormalIndex][1];
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[1]].lightNormalIndex][0];
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[1]].lightNormalIndex][2];
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[1]].lightNormalIndex][1];
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[2]].lightNormalIndex][0];
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[2]].lightNormalIndex][2];
*normptr++ = avertexnormals[vertex[trisPtr->meshIndex[2]].lightNormalIndex][1];
}
}
}
free(buffer);
return retModel;
}

19
src/hardware/hw_md2load.h Normal file
View file

@ -0,0 +1,19 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#ifndef _HW_MD2LOAD_H_
#define _HW_MD2LOAD_H_
#include "hw_model.h"
#include "../doomtype.h"
// Load the Model
model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat);
#endif

510
src/hardware/hw_md3load.c Normal file
View file

@ -0,0 +1,510 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../doomdef.h"
#include "hw_md3load.h"
#include "hw_model.h"
#include "../z_zone.h"
typedef struct
{
int ident; // A "magic number" that's used to identify the .md3 file
int version; // The version of the file, always 15
char name[64];
int flags;
int numFrames; // Number of frames
int numTags;
int numSurfaces;
int numSkins; // Number of skins with the model
int offsetFrames;
int offsetTags;
int offsetSurfaces;
int offsetEnd; // Offset, in bytes from the start of the file, to the end of the file (filesize)
} md3modelHeader;
typedef struct
{
float minBounds[3]; // First corner of the bounding box
float maxBounds[3]; // Second corner of the bounding box
float localOrigin[3]; // Local origin, usually (0, 0, 0)
float radius; // Radius of bounding sphere
char name[16]; // Name of frame
} md3Frame;
typedef struct
{
char name[64]; // Name of tag
float origin[3]; // Coordinates of tag
float axis[9]; // Orientation of tag object
} md3Tag;
typedef struct
{
int ident;
char name[64]; // Name of this surface
int flags;
int numFrames; // # of keyframes
int numShaders; // # of shaders
int numVerts; // # of vertices
int numTriangles; // # of triangles
int offsetTriangles; // Relative offset from start of this struct to where the list of Triangles start
int offsetShaders; // Relative offset from start of this struct to where the list of Shaders start
int offsetST; // Relative offset from start of this struct to where the list of tex coords start
int offsetXYZNormal; // Relative offset from start of this struct to where the list of vertices start
int offsetEnd; // Relative offset from start of this struct to where this surface ends
} md3Surface;
typedef struct
{
char name[64]; // Name of this shader
int shaderIndex; // Shader index number
} md3Shader;
typedef struct
{
int index[3]; // List of offset values into the list of Vertex objects that constitute the corners of the Triangle object.
} md3Triangle;
typedef struct
{
float st[2];
} md3TexCoord;
typedef struct
{
short x, y, z, n;
} md3Vertex;
static float latlnglookup[256][256][3];
static void GetNormalFromLatLong(short latlng, float *out)
{
float *lookup = latlnglookup[(unsigned char)(latlng >> 8)][(unsigned char)(latlng & 255)];
out[0] = *lookup++;
out[1] = *lookup++;
out[2] = *lookup++;
}
#if 0
static void NormalToLatLng(float *n, short *out)
{
// Special cases
if (0.0f == n[0] && 0.0f == n[1])
{
if (n[2] > 0.0f)
*out = 0;
else
*out = 128;
}
else
{
char x, y;
x = (char)(57.2957795f * (atan2(n[1], n[0])) * (255.0f / 360.0f));
y = (char)(57.2957795f * (acos(n[2])) * (255.0f / 360.0f));
*out = (x << 8) + y;
}
}
#endif
static inline void LatLngToNormal(short n, float *out)
{
const float PI = (3.1415926535897932384626433832795f);
float lat = (float)(n >> 8);
float lng = (float)(n & 255);
lat *= PI / 128.0f;
lng *= PI / 128.0f;
out[0] = cosf(lat) * sinf(lng);
out[1] = sinf(lat) * sinf(lng);
out[2] = cosf(lng);
}
static void LatLngInit(void)
{
int i, j;
for (i = 0; i < 256; i++)
{
for (j = 0; j < 256; j++)
LatLngToNormal((short)((i << 8) + j), latlnglookup[i][j]);
}
}
static boolean latlnginit = false;
model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat)
{
const float WUNITS = 1.0f;
model_t *retModel = NULL;
md3modelHeader *mdh;
long fileLen;
long fileReadLen;
char *buffer;
int surfEnd;
int i, t;
int matCount;
FILE *f;
if (!latlnginit)
{
LatLngInit();
latlnginit = true;
}
f = fopen(fileName, "rb");
if (!f)
return NULL;
retModel = (model_t*)Z_Calloc(sizeof(model_t), ztag, 0);
// find length of file
fseek(f, 0, SEEK_END);
fileLen = ftell(f);
fseek(f, 0, SEEK_SET);
// read in file
buffer = malloc(fileLen);
fileReadLen = fread(buffer, fileLen, 1, f);
fclose(f);
(void)fileReadLen; // intentionally ignore return value, per buildbot
// get pointer to file header
mdh = (md3modelHeader*)buffer;
retModel->numMeshes = mdh->numSurfaces;
retModel->numMaterials = 0;
surfEnd = 0;
for (i = 0; i < mdh->numSurfaces; i++)
{
md3Surface *mdS = (md3Surface*)&buffer[mdh->offsetSurfaces];
surfEnd += mdS->offsetEnd;
retModel->numMaterials += mdS->numShaders;
}
// Initialize materials
if (retModel->numMaterials <= 0) // Always at least one skin, duh
retModel->numMaterials = 1;
retModel->materials = (material_t*)Z_Calloc(sizeof(material_t)*retModel->numMaterials, ztag, 0);
for (t = 0; t < retModel->numMaterials; t++)
{
retModel->materials[t].ambient[0] = 0.3686f;
retModel->materials[t].ambient[1] = 0.3684f;
retModel->materials[t].ambient[2] = 0.3684f;
retModel->materials[t].ambient[3] = 1.0f;
retModel->materials[t].diffuse[0] = 0.8863f;
retModel->materials[t].diffuse[1] = 0.8850f;
retModel->materials[t].diffuse[2] = 0.8850f;
retModel->materials[t].diffuse[3] = 1.0f;
retModel->materials[t].emissive[0] = 0.0f;
retModel->materials[t].emissive[1] = 0.0f;
retModel->materials[t].emissive[2] = 0.0f;
retModel->materials[t].emissive[3] = 1.0f;
retModel->materials[t].specular[0] = 0.4902f;
retModel->materials[t].specular[1] = 0.4887f;
retModel->materials[t].specular[2] = 0.4887f;
retModel->materials[t].specular[3] = 1.0f;
retModel->materials[t].shininess = 25.0f;
retModel->materials[t].spheremap = false;
}
retModel->meshes = (mesh_t*)Z_Calloc(sizeof(mesh_t)*retModel->numMeshes, ztag, 0);
matCount = 0;
for (i = 0, surfEnd = 0; i < mdh->numSurfaces; i++)
{
int j;
md3Shader *mdShader;
md3Surface *mdS = (md3Surface*)&buffer[mdh->offsetSurfaces + surfEnd];
surfEnd += mdS->offsetEnd;
mdShader = (md3Shader*)((char*)mdS + mdS->offsetShaders);
for (j = 0; j < mdS->numShaders; j++, matCount++)
{
size_t len = strlen(mdShader[j].name);
mdShader[j].name[len-1] = 'z';
mdShader[j].name[len-2] = 'u';
mdShader[j].name[len-3] = 'b';
// Load material
/* retModel->materials[matCount].texture = Texture::ReadTexture(mdShader[j].name, ZT_TEXTURE);
if (!systemSucks)
{
// Check for a normal map...??
char openfilename[1024];
char normalMapName[1024];
strcpy(normalMapName, mdShader[j].name);
len = strlen(normalMapName);
char *ptr = &normalMapName[len];
ptr--; // z
ptr--; // u
ptr--; // b
ptr--; // .
*ptr++ = '_';
*ptr++ = 'n';
*ptr++ = '.';
*ptr++ = 'b';
*ptr++ = 'u';
*ptr++ = 'z';
*ptr++ = '\0';
sprintf(openfilename, "%s/%s", "textures", normalMapName);
// Convert backslashes to forward slashes
for (int k = 0; k < 1024; k++)
{
if (openfilename[k] == '\0')
break;
if (openfilename[k] == '\\')
openfilename[k] = '/';
}
Resource::resource_t *res = Resource::Open(openfilename);
if (res)
{
Resource::Close(res);
retModel->materials[matCount].lightmap = Texture::ReadTexture(normalMapName, ZT_TEXTURE);
}
}*/
}
retModel->meshes[i].numFrames = mdS->numFrames;
retModel->meshes[i].numTriangles = mdS->numTriangles;
if (!useFloat) // 'tinyframe' mode with indices
{
float tempNormal[3];
float *uvptr;
md3TexCoord *mdST;
unsigned short *indexptr;
md3Triangle *mdT;
retModel->meshes[i].tinyframes = (tinyframe_t*)Z_Calloc(sizeof(tinyframe_t)*mdS->numFrames, ztag, 0);
retModel->meshes[i].numVertices = mdS->numVerts;
retModel->meshes[i].uvs = (float*)Z_Malloc(sizeof(float)*2*mdS->numVerts, ztag, 0);
for (j = 0; j < mdS->numFrames; j++)
{
short *vertptr;
char *normptr;
// char *tanptr;
int k;
md3Vertex *mdV = (md3Vertex*)((char*)mdS + mdS->offsetXYZNormal + (mdS->numVerts*j*sizeof(md3Vertex)));
retModel->meshes[i].tinyframes[j].vertices = (short*)Z_Malloc(sizeof(short)*3*mdS->numVerts, ztag, 0);
retModel->meshes[i].tinyframes[j].normals = (char*)Z_Malloc(sizeof(char)*3*mdS->numVerts, ztag, 0);
// if (retModel->materials[0].lightmap)
// retModel->meshes[i].tinyframes[j].tangents = (char*)malloc(sizeof(char));//(char*)Z_Malloc(sizeof(char)*3*mdS->numVerts, ztag);
retModel->meshes[i].indices = (unsigned short*)Z_Malloc(sizeof(unsigned short) * 3 * mdS->numTriangles, ztag, 0);
vertptr = retModel->meshes[i].tinyframes[j].vertices;
normptr = retModel->meshes[i].tinyframes[j].normals;
// tanptr = retModel->meshes[i].tinyframes[j].tangents;
retModel->meshes[i].tinyframes[j].material = &retModel->materials[i];
for (k = 0; k < mdS->numVerts; k++)
{
// Vertex
*vertptr = mdV[k].x;
vertptr++;
*vertptr = mdV[k].z;
vertptr++;
*vertptr = 1.0f - mdV[k].y;
vertptr++;
// Normal
GetNormalFromLatLong(mdV[k].n, tempNormal);
*normptr = (char)(tempNormal[0] * 127);
normptr++;
*normptr = (char)(tempNormal[2] * 127);
normptr++;
*normptr = (char)(tempNormal[1] * 127);
normptr++;
}
}
uvptr = (float*)retModel->meshes[i].uvs;
mdST = (md3TexCoord*)((char*)mdS + mdS->offsetST);
for (j = 0; j < mdS->numVerts; j++)
{
*uvptr = mdST[j].st[0];
uvptr++;
*uvptr = mdST[j].st[1];
uvptr++;
}
indexptr = retModel->meshes[i].indices;
mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles);
for (j = 0; j < mdS->numTriangles; j++, mdT++)
{
// Indices
*indexptr = (unsigned short)mdT->index[0];
indexptr++;
*indexptr = (unsigned short)mdT->index[1];
indexptr++;
*indexptr = (unsigned short)mdT->index[2];
indexptr++;
}
}
else // Traditional full-float loading method
{
float dataScale = 0.015624f * WUNITS;
float tempNormal[3];
md3TexCoord *mdST;
md3Triangle *mdT;
float *uvptr;
int k;
retModel->meshes[i].numVertices = mdS->numTriangles * 3;//mdS->numVerts;
retModel->meshes[i].frames = (mdlframe_t*)Z_Calloc(sizeof(mdlframe_t)*mdS->numFrames, ztag, 0);
retModel->meshes[i].uvs = (float*)Z_Malloc(sizeof(float)*2*mdS->numTriangles*3, ztag, 0);
for (j = 0; j < mdS->numFrames; j++)
{
float *vertptr;
float *normptr;
md3Vertex *mdV = (md3Vertex*)((char*)mdS + mdS->offsetXYZNormal + (mdS->numVerts*j*sizeof(md3Vertex)));
retModel->meshes[i].frames[j].vertices = (float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag, 0);
retModel->meshes[i].frames[j].normals = (float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag, 0);
// if (retModel->materials[i].lightmap)
// retModel->meshes[i].frames[j].tangents = (float*)malloc(sizeof(float));//(float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag);
vertptr = retModel->meshes[i].frames[j].vertices;
normptr = retModel->meshes[i].frames[j].normals;
retModel->meshes[i].frames[j].material = &retModel->materials[i];
mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles);
for (k = 0; k < mdS->numTriangles; k++)
{
// Vertex 1
*vertptr = mdV[mdT->index[0]].x * dataScale;
vertptr++;
*vertptr = mdV[mdT->index[0]].z * dataScale;
vertptr++;
*vertptr = 1.0f - mdV[mdT->index[0]].y * dataScale;
vertptr++;
GetNormalFromLatLong(mdV[mdT->index[0]].n, tempNormal);
*normptr = tempNormal[0];
normptr++;
*normptr = tempNormal[2];
normptr++;
*normptr = tempNormal[1];
normptr++;
// Vertex 2
*vertptr = mdV[mdT->index[1]].x * dataScale;
vertptr++;
*vertptr = mdV[mdT->index[1]].z * dataScale;
vertptr++;
*vertptr = 1.0f - mdV[mdT->index[1]].y * dataScale;
vertptr++;
GetNormalFromLatLong(mdV[mdT->index[1]].n, tempNormal);
*normptr = tempNormal[0];
normptr++;
*normptr = tempNormal[2];
normptr++;
*normptr = tempNormal[1];
normptr++;
// Vertex 3
*vertptr = mdV[mdT->index[2]].x * dataScale;
vertptr++;
*vertptr = mdV[mdT->index[2]].z * dataScale;
vertptr++;
*vertptr = 1.0f - mdV[mdT->index[2]].y * dataScale;
vertptr++;
GetNormalFromLatLong(mdV[mdT->index[2]].n, tempNormal);
*normptr = tempNormal[0];
normptr++;
*normptr = tempNormal[2];
normptr++;
*normptr = tempNormal[1];
normptr++;
mdT++; // Advance to next triangle
}
}
mdST = (md3TexCoord*)((char*)mdS + mdS->offsetST);
uvptr = (float*)retModel->meshes[i].uvs;
mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles);
for (k = 0; k < mdS->numTriangles; k++)
{
*uvptr = mdST[mdT->index[0]].st[0];
uvptr++;
*uvptr = mdST[mdT->index[0]].st[1];
uvptr++;
*uvptr = mdST[mdT->index[1]].st[0];
uvptr++;
*uvptr = mdST[mdT->index[1]].st[1];
uvptr++;
*uvptr = mdST[mdT->index[2]].st[0];
uvptr++;
*uvptr = mdST[mdT->index[2]].st[1];
uvptr++;
mdT++; // Advance to next triangle
}
}
}
/*
// Tags?
retModel->numTags = mdh->numTags;
retModel->maxNumFrames = mdh->numFrames;
retModel->tags = (tag_t*)Z_Calloc(sizeof(tag_t) * retModel->numTags * mdh->numFrames, ztag);
md3Tag *mdTag = (md3Tag*)&buffer[mdh->offsetTags];
tag_t *curTag = retModel->tags;
for (i = 0; i < mdh->numFrames; i++)
{
int j;
for (j = 0; j < retModel->numTags; j++, mdTag++)
{
strcpys(curTag->name, mdTag->name, sizeof(curTag->name) / sizeof(char));
curTag->transform.m[0][0] = mdTag->axis[0];
curTag->transform.m[0][1] = mdTag->axis[1];
curTag->transform.m[0][2] = mdTag->axis[2];
curTag->transform.m[1][0] = mdTag->axis[3];
curTag->transform.m[1][1] = mdTag->axis[4];
curTag->transform.m[1][2] = mdTag->axis[5];
curTag->transform.m[2][0] = mdTag->axis[6];
curTag->transform.m[2][1] = mdTag->axis[7];
curTag->transform.m[2][2] = mdTag->axis[8];
curTag->transform.m[3][0] = mdTag->origin[0] * WUNITS;
curTag->transform.m[3][1] = mdTag->origin[1] * WUNITS;
curTag->transform.m[3][2] = mdTag->origin[2] * WUNITS;
curTag->transform.m[3][3] = 1.0f;
Matrix::Rotate(&curTag->transform, 90.0f, &Vector::Xaxis);
curTag++;
}
}*/
free(buffer);
return retModel;
}

19
src/hardware/hw_md3load.h Normal file
View file

@ -0,0 +1,19 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#ifndef _HW_MD3LOAD_H_
#define _HW_MD3LOAD_H_
#include "hw_model.h"
#include "../doomtype.h"
// Load the Model
model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat);
#endif

593
src/hardware/hw_model.c Normal file
View file

@ -0,0 +1,593 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#include "../z_zone.h"
#include "../doomdef.h"
#include "hw_model.h"
#include "hw_md2load.h"
#include "hw_md3load.h"
#include "u_list.h"
#include <string.h>
static float PI = (3.1415926535897932384626433832795f);
static float U_Deg2Rad(float deg)
{
return deg * ((float)PI / 180.0f);
}
vector_t vectorXaxis = { 1.0f, 0.0f, 0.0f };
vector_t vectorYaxis = { 0.0f, 1.0f, 0.0f };
vector_t vectorZaxis = { 0.0f, 0.0f, 1.0f };
void VectorRotate(vector_t *rotVec, const vector_t *axisVec, float angle)
{
float ux, uy, uz, vx, vy, vz, wx, wy, wz, sa, ca;
angle = U_Deg2Rad(angle);
// Rotate the point (x,y,z) around the vector (u,v,w)
ux = axisVec->x * rotVec->x;
uy = axisVec->x * rotVec->y;
uz = axisVec->x * rotVec->z;
vx = axisVec->y * rotVec->x;
vy = axisVec->y * rotVec->y;
vz = axisVec->y * rotVec->z;
wx = axisVec->z * rotVec->x;
wy = axisVec->z * rotVec->y;
wz = axisVec->z * rotVec->z;
sa = sinf(angle);
ca = cosf(angle);
rotVec->x = axisVec->x*(ux + vy + wz) + (rotVec->x*(axisVec->y*axisVec->y + axisVec->z*axisVec->z) - axisVec->x*(vy + wz))*ca + (-wy + vz)*sa;
rotVec->y = axisVec->y*(ux + vy + wz) + (rotVec->y*(axisVec->x*axisVec->x + axisVec->z*axisVec->z) - axisVec->y*(ux + wz))*ca + (wx - uz)*sa;
rotVec->z = axisVec->z*(ux + vy + wz) + (rotVec->z*(axisVec->x*axisVec->x + axisVec->y*axisVec->y) - axisVec->z*(ux + vy))*ca + (-vx + uy)*sa;
}
void UnloadModel(model_t *model)
{
// Wouldn't it be great if C just had destructors?
int i;
for (i = 0; i < model->numMeshes; i++)
{
mesh_t *mesh = &model->meshes[i];
if (mesh->frames)
{
int j;
for (j = 0; j < mesh->numFrames; j++)
{
if (mesh->frames[j].normals)
Z_Free(mesh->frames[j].normals);
if (mesh->frames[j].tangents)
Z_Free(mesh->frames[j].tangents);
if (mesh->frames[j].vertices)
Z_Free(mesh->frames[j].vertices);
if (mesh->frames[j].colors)
Z_Free(mesh->frames[j].colors);
}
Z_Free(mesh->frames);
}
else if (mesh->tinyframes)
{
int j;
for (j = 0; j < mesh->numFrames; j++)
{
if (mesh->tinyframes[j].normals)
Z_Free(mesh->tinyframes[j].normals);
if (mesh->tinyframes[j].tangents)
Z_Free(mesh->tinyframes[j].tangents);
if (mesh->tinyframes[j].vertices)
Z_Free(mesh->tinyframes[j].vertices);
}
if (mesh->indices)
Z_Free(mesh->indices);
Z_Free(mesh->tinyframes);
}
if (mesh->uvs)
Z_Free(mesh->uvs);
if (mesh->lightuvs)
Z_Free(mesh->lightuvs);
}
if (model->meshes)
Z_Free(model->meshes);
if (model->tags)
Z_Free(model->tags);
if (model->materials)
Z_Free(model->materials);
DeleteVBOs(model);
Z_Free(model);
}
tag_t *GetTagByName(model_t *model, char *name, int frame)
{
if (frame < model->maxNumFrames)
{
tag_t *iterator = &model->tags[frame * model->numTags];
int i;
for (i = 0; i < model->numTags; i++)
{
if (!stricmp(iterator[i].name, name))
return &iterator[i];
}
}
return NULL;
}
//
// LoadModel
//
// Load a model and
// convert it to the
// internal format.
//
model_t *LoadModel(const char *filename, int ztag)
{
model_t *model;
// What type of file?
const char *extension = NULL;
int i;
for (i = (int)strlen(filename)-1; i >= 0; i--)
{
if (filename[i] != '.')
continue;
extension = &filename[i];
break;
}
if (!extension)
{
CONS_Printf("Model %s is lacking a file extension, unable to determine type!\n", filename);
return NULL;
}
if (!strcmp(extension, ".md3"))
{
if (!(model = MD3_LoadModel(filename, ztag, false)))
return NULL;
}
else if (!strcmp(extension, ".md3s")) // MD3 that will be converted in memory to use full floats
{
if (!(model = MD3_LoadModel(filename, ztag, true)))
return NULL;
}
else if (!strcmp(extension, ".md2"))
{
if (!(model = MD2_LoadModel(filename, ztag, false)))
return NULL;
}
else if (!strcmp(extension, ".md2s"))
{
if (!(model = MD2_LoadModel(filename, ztag, true)))
return NULL;
}
else
{
CONS_Printf("Unknown model format: %s\n", extension);
return NULL;
}
model->mdlFilename = (char*)Z_Malloc(strlen(filename)+1, ztag, 0);
strcpy(model->mdlFilename, filename);
Optimize(model);
GeneratePolygonNormals(model, ztag);
// Default material properties
for (i = 0 ; i < model->numMaterials; i++)
{
material_t *material = &model->materials[i];
material->ambient[0] = 0.7686f;
material->ambient[1] = 0.7686f;
material->ambient[2] = 0.7686f;
material->ambient[3] = 1.0f;
material->diffuse[0] = 0.5863f;
material->diffuse[1] = 0.5863f;
material->diffuse[2] = 0.5863f;
material->diffuse[3] = 1.0f;
material->specular[0] = 0.4902f;
material->specular[1] = 0.4902f;
material->specular[2] = 0.4902f;
material->specular[3] = 1.0f;
material->shininess = 25.0f;
}
return model;
}
//
// GenerateVertexNormals
//
// Creates a new normal for a vertex using the average of all of the polygons it belongs to.
//
void GenerateVertexNormals(model_t *model)
{
int i;
for (i = 0; i < model->numMeshes; i++)
{
int j;
mesh_t *mesh = &model->meshes[i];
if (!mesh->frames)
continue;
for (j = 0; j < mesh->numFrames; j++)
{
mdlframe_t *frame = &mesh->frames[j];
int memTag = PU_STATIC;
float *newNormals = (float*)Z_Malloc(sizeof(float)*3*mesh->numTriangles*3, memTag, 0);
int k;
float *vertPtr = frame->vertices;
float *oldNormals;
M_Memcpy(newNormals, frame->normals, sizeof(float)*3*mesh->numTriangles*3);
/* if (!systemSucks)
{
memTag = Z_GetTag(frame->tangents);
float *newTangents = (float*)Z_Malloc(sizeof(float)*3*mesh->numTriangles*3, memTag);
M_Memcpy(newTangents, frame->tangents, sizeof(float)*3*mesh->numTriangles*3);
}*/
for (k = 0; k < mesh->numVertices; k++)
{
float x, y, z;
int vCount = 0;
vector_t normal;
int l;
float *testPtr = frame->vertices;
x = *vertPtr++;
y = *vertPtr++;
z = *vertPtr++;
normal.x = normal.y = normal.z = 0;
for (l = 0; l < mesh->numVertices; l++)
{
float testX, testY, testZ;
testX = *testPtr++;
testY = *testPtr++;
testZ = *testPtr++;
if (fabsf(x - testX) > FLT_EPSILON
|| fabsf(y - testY) > FLT_EPSILON
|| fabsf(z - testZ) > FLT_EPSILON)
continue;
// Found a vertex match! Add it...
normal.x += frame->normals[3 * l + 0];
normal.y += frame->normals[3 * l + 1];
normal.z += frame->normals[3 * l + 2];
vCount++;
}
if (vCount > 1)
{
// Vector::Normalize(&normal);
newNormals[3 * k + 0] = (float)normal.x;
newNormals[3 * k + 1] = (float)normal.y;
newNormals[3 * k + 2] = (float)normal.z;
/* if (!systemSucks)
{
Vector::vector_t tangent;
Vector::Tangent(&normal, &tangent);
newTangents[3 * k + 0] = tangent.x;
newTangents[3 * k + 1] = tangent.y;
newTangents[3 * k + 2] = tangent.z;
}*/
}
}
oldNormals = frame->normals;
frame->normals = newNormals;
Z_Free(oldNormals);
/* if (!systemSucks)
{
float *oldTangents = frame->tangents;
frame->tangents = newTangents;
Z_Free(oldTangents);
}*/
}
}
}
typedef struct materiallist_s
{
struct materiallist_s *next;
struct materiallist_s *prev;
material_t *material;
} materiallist_t;
static boolean AddMaterialToList(materiallist_t **head, material_t *material)
{
materiallist_t *node, *newMatNode;
for (node = *head; node; node = node->next)
{
if (node->material == material)
return false;
}
// Didn't find it, so add to the list
newMatNode = (materiallist_t*)Z_Malloc(sizeof(materiallist_t), PU_CACHE, 0);
newMatNode->material = material;
ListAdd(newMatNode, (listitem_t**)head);
return true;
}
//
// Optimize
//
// Groups triangles from meshes in the model
// Only works for models with 1 frame
//
void Optimize(model_t *model)
{
int numMeshes = 0;
int i;
materiallist_t *matListHead = NULL;
int memTag;
mesh_t *newMeshes;
materiallist_t *node;
if (model->numMeshes <= 1)
return; // No need
for (i = 0; i < model->numMeshes; i++)
{
mesh_t *curMesh = &model->meshes[i];
if (curMesh->numFrames > 1)
return; // Can't optimize models with > 1 frame
if (!curMesh->frames)
return; // Don't optimize tinyframe models (no need)
// We are condensing to 1 mesh per material, so
// the # of materials we use will be the new
// # of meshes
if (AddMaterialToList(&matListHead, curMesh->frames[0].material))
numMeshes++;
}
memTag = PU_STATIC;
newMeshes = (mesh_t*)Z_Calloc(sizeof(mesh_t) * numMeshes, memTag, 0);
i = 0;
for (node = matListHead; node; node = node->next)
{
material_t *curMat = node->material;
mesh_t *newMesh = &newMeshes[i];
mdlframe_t *curFrame;
int uvCount;
int vertCount;
int colorCount;
// Find all triangles with this material and count them
int numTriangles = 0;
int j;
for (j = 0; j < model->numMeshes; j++)
{
mesh_t *curMesh = &model->meshes[j];
if (curMesh->frames[0].material == curMat)
numTriangles += curMesh->numTriangles;
}
newMesh->numFrames = 1;
newMesh->numTriangles = numTriangles;
newMesh->numVertices = numTriangles * 3;
newMesh->uvs = (float*)Z_Malloc(sizeof(float)*2*numTriangles*3, memTag, 0);
// if (node->material->lightmap)
// newMesh->lightuvs = (float*)Z_Malloc(sizeof(float)*2*numTriangles*3, memTag, 0);
newMesh->frames = (mdlframe_t*)Z_Calloc(sizeof(mdlframe_t), memTag, 0);
curFrame = &newMesh->frames[0];
curFrame->material = curMat;
curFrame->normals = (float*)Z_Malloc(sizeof(float)*3*numTriangles*3, memTag, 0);
// if (!systemSucks)
// curFrame->tangents = (float*)Z_Malloc(sizeof(float)*3*numTriangles*3, memTag, 0);
curFrame->vertices = (float*)Z_Malloc(sizeof(float)*3*numTriangles*3, memTag, 0);
curFrame->colors = (char*)Z_Malloc(sizeof(char)*4*numTriangles*3, memTag, 0);
// Now traverse the meshes of the model, adding in
// vertices/normals/uvs that match the current material
uvCount = 0;
vertCount = 0;
colorCount = 0;
for (j = 0; j < model->numMeshes; j++)
{
mesh_t *curMesh = &model->meshes[j];
if (curMesh->frames[0].material == curMat)
{
float *dest;
float *src;
char *destByte;
char *srcByte;
M_Memcpy(&newMesh->uvs[uvCount],
curMesh->uvs,
sizeof(float)*2*curMesh->numTriangles*3);
/* if (node->material->lightmap)
{
M_Memcpy(&newMesh->lightuvs[uvCount],
curMesh->lightuvs,
sizeof(float)*2*curMesh->numTriangles*3);
}*/
uvCount += 2*curMesh->numTriangles*3;
dest = (float*)newMesh->frames[0].vertices;
src = (float*)curMesh->frames[0].vertices;
M_Memcpy(&dest[vertCount],
src,
sizeof(float)*3*curMesh->numTriangles*3);
dest = (float*)newMesh->frames[0].normals;
src = (float*)curMesh->frames[0].normals;
M_Memcpy(&dest[vertCount],
src,
sizeof(float)*3*curMesh->numTriangles*3);
/* if (!systemSucks)
{
dest = (float*)newMesh->frames[0].tangents;
src = (float*)curMesh->frames[0].tangents;
M_Memcpy(&dest[vertCount],
src,
sizeof(float)*3*curMesh->numTriangles*3);
}*/
vertCount += 3 * curMesh->numTriangles * 3;
destByte = (char*)newMesh->frames[0].colors;
srcByte = (char*)curMesh->frames[0].colors;
if (srcByte)
{
M_Memcpy(&destByte[colorCount],
srcByte,
sizeof(char)*4*curMesh->numTriangles*3);
}
else
{
memset(&destByte[colorCount],
255,
sizeof(char)*4*curMesh->numTriangles*3);
}
colorCount += 4 * curMesh->numTriangles * 3;
}
}
i++;
}
CONS_Printf("Model::Optimize(): Model reduced from %d to %d meshes.\n", model->numMeshes, numMeshes);
model->meshes = newMeshes;
model->numMeshes = numMeshes;
}
void GeneratePolygonNormals(model_t *model, int ztag)
{
int i;
for (i = 0; i < model->numMeshes; i++)
{
int j;
mesh_t *mesh = &model->meshes[i];
if (!mesh->frames)
continue;
for (j = 0; j < mesh->numFrames; j++)
{
int k;
mdlframe_t *frame = &mesh->frames[j];
const float *vertices = frame->vertices;
vector_t *polyNormals;
frame->polyNormals = (vector_t*)Z_Malloc(sizeof(vector_t) * mesh->numTriangles, ztag, 0);
polyNormals = frame->polyNormals;
for (k = 0; k < mesh->numTriangles; k++)
{
// Vector::Normal(vertices, polyNormals);
vertices += 3 * 3;
polyNormals++;
}
}
}
}
//
// Reload
//
// Reload VBOs
//
#if 0
static void Reload(void)
{
/* model_t *node;
for (node = modelHead; node; node = node->next)
{
int i;
for (i = 0; i < node->numMeshes; i++)
{
mesh_t *mesh = &node->meshes[i];
if (mesh->frames)
{
int j;
for (j = 0; j < mesh->numFrames; j++)
CreateVBO(mesh, &mesh->frames[j]);
}
else if (mesh->tinyframes)
{
int j;
for (j = 0; j < mesh->numFrames; j++)
CreateVBO(mesh, &mesh->tinyframes[j]);
}
}
}*/
}
#endif
void DeleteVBOs(model_t *model)
{
(void)model;
/* for (int i = 0; i < model->numMeshes; i++)
{
mesh_t *mesh = &model->meshes[i];
if (mesh->frames)
{
for (int j = 0; j < mesh->numFrames; j++)
{
mdlframe_t *frame = &mesh->frames[j];
if (!frame->vboID)
continue;
bglDeleteBuffers(1, &frame->vboID);
frame->vboID = 0;
}
}
else if (mesh->tinyframes)
{
for (int j = 0; j < mesh->numFrames; j++)
{
tinyframe_t *frame = &mesh->tinyframes[j];
if (!frame->vboID)
continue;
bglDeleteBuffers(1, &frame->vboID);
frame->vboID = 0;
}
}
}*/
}

104
src/hardware/hw_model.h Normal file
View file

@ -0,0 +1,104 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#ifndef _HW_MODEL_H_
#define _HW_MODEL_H_
#include "../doomtype.h"
typedef struct
{
float x, y, z;
} vector_t;
extern vector_t vectorXaxis;
extern vector_t vectorYaxis;
extern vector_t vectorZaxis;
void VectorRotate(vector_t *rotVec, const vector_t *axisVec, float angle);
typedef struct
{
float ambient[4], diffuse[4], specular[4], emissive[4];
float shininess;
boolean spheremap;
// Texture::texture_t *texture;
// Texture::texture_t *lightmap;
} material_t;
typedef struct
{
material_t *material; // Pointer to the allocated 'materials' list in model_t
float *vertices;
float *normals;
float *tangents;
char *colors;
unsigned int vboID;
vector_t *polyNormals;
} mdlframe_t;
typedef struct
{
material_t *material;
short *vertices;
char *normals;
char *tangents;
unsigned int vboID;
} tinyframe_t;
// Equivalent to MD3's many 'surfaces'
typedef struct mesh_s
{
int numVertices;
int numTriangles;
float *uvs;
float *lightuvs;
int numFrames;
mdlframe_t *frames;
tinyframe_t *tinyframes;
unsigned short *indices;
} mesh_t;
typedef struct tag_s
{
char name[64];
// matrix_t transform;
} tag_t;
typedef struct model_s
{
int maxNumFrames;
int numMaterials;
material_t *materials;
int numMeshes;
mesh_t *meshes;
int numTags;
tag_t *tags;
char *mdlFilename;
boolean unloaded;
} model_t;
extern int numModels;
extern model_t *modelHead;
tag_t *GetTagByName(model_t *model, char *name, int frame);
model_t *LoadModel(const char *filename, int ztag);
void UnloadModel(model_t *model);
void Optimize(model_t *model);
void GenerateVertexNormals(model_t *model);
void GeneratePolygonNormals(model_t *model, int ztag);
void CreateVBOTiny(mesh_t *mesh, tinyframe_t *frame);
void CreateVBO(mesh_t *mesh, mdlframe_t *frame);
void DeleteVBOs(model_t *model);
#endif

View file

@ -347,13 +347,6 @@ static INT32 WINAPI SetRes(viddef_t *lvid, vmode_t *pcurrentmode)
if (strstr(renderer, "810")) oglflags |= GLF_NOZBUFREAD; if (strstr(renderer, "810")) oglflags |= GLF_NOZBUFREAD;
DBG_Printf("oglflags : 0x%X\n", oglflags); DBG_Printf("oglflags : 0x%X\n", oglflags);
#ifdef USE_PALETTED_TEXTURE
if (isExtAvailable("GL_EXT_paletted_texture",gl_extensions))
glColorTableEXT = GetGLFunc("glColorTableEXT");
else
glColorTableEXT = NULL;
#endif
#ifdef USE_WGL_SWAP #ifdef USE_WGL_SWAP
if (isExtAvailable("WGL_EXT_swap_control",gl_extensions)) if (isExtAvailable("WGL_EXT_swap_control",gl_extensions))
wglSwapIntervalEXT = GetGLFunc("wglSwapIntervalEXT"); wglSwapIntervalEXT = GetGLFunc("wglSwapIntervalEXT");
@ -582,19 +575,8 @@ EXPORT void HWRAPI(SetPalette) (RGBA_t *pal, RGBA_t *gamma)
myPaletteData[i].s.blue = (UINT8)MIN((pal[i].s.blue*gamma->s.blue)/127, 255); myPaletteData[i].s.blue = (UINT8)MIN((pal[i].s.blue*gamma->s.blue)/127, 255);
myPaletteData[i].s.alpha = pal[i].s.alpha; myPaletteData[i].s.alpha = pal[i].s.alpha;
} }
#ifdef USE_PALETTED_TEXTURE
if (glColorTableEXT) // on a palette change, you have to reload all of the textures
{
for (i = 0; i < 256; i++)
{
palette_tex[3*i+0] = pal[i].s.red;
palette_tex[3*i+1] = pal[i].s.green;
palette_tex[3*i+2] = pal[i].s.blue;
}
glColorTableEXT(GL_TEXTURE_2D, GL_RGB8, 256, GL_RGB, GL_UNSIGNED_BYTE, palette_tex);
}
#endif
// on a chang<6E> de palette, il faut recharger toutes les textures
Flush(); Flush();
} }

File diff suppressed because it is too large Load diff

View file

@ -37,13 +37,11 @@
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glu.h> #include <GL/glu.h>
#ifndef MINI_GL_COMPATIBILITY
#ifdef STATIC_OPENGL // Because of the 1.3 functions, you'll need GLext to compile it if static #ifdef STATIC_OPENGL // Because of the 1.3 functions, you'll need GLext to compile it if static
#define GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES
#include <GL/glext.h> #include <GL/glext.h>
#endif #endif
#endif #endif
#endif
#define _CREATE_DLL_ // necessary for Unix AND Windows #define _CREATE_DLL_ // necessary for Unix AND Windows
#include "../../doomdef.h" #include "../../doomdef.h"
@ -73,7 +71,6 @@ extern FILE *gllogstream;
#endif #endif
#ifndef DRIVER_STRING #ifndef DRIVER_STRING
// #define USE_PALETTED_TEXTURE
#define DRIVER_STRING "HWRAPI Init(): SRB2Kart OpenGL renderer" // Tails #define DRIVER_STRING "HWRAPI Init(): SRB2Kart OpenGL renderer" // Tails
#endif #endif
@ -91,10 +88,6 @@ int SetupPixelFormat(INT32 WantColorBits, INT32 WantStencilBits, INT32 WantDepth
void SetModelView(GLint w, GLint h); void SetModelView(GLint w, GLint h);
void SetStates(void); void SetStates(void);
FUNCMATH float byteasfloat(UINT8 fbyte); FUNCMATH float byteasfloat(UINT8 fbyte);
#ifdef USE_PALETTED_TEXTURE
extern PFNGLCOLORTABLEEXTPROC glColorTableEXT;
extern GLubyte palette_tex[256*3];
#endif
#ifndef GL_EXT_texture_filter_anisotropic #ifndef GL_EXT_texture_filter_anisotropic
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
@ -120,6 +113,10 @@ typedef void (APIENTRY * PFNglGetIntegerv) (GLenum pname, GLint *params);
extern PFNglGetIntegerv pglGetIntegerv; extern PFNglGetIntegerv pglGetIntegerv;
typedef const GLubyte* (APIENTRY * PFNglGetString) (GLenum name); typedef const GLubyte* (APIENTRY * PFNglGetString) (GLenum name);
extern PFNglGetString pglGetString; extern PFNglGetString pglGetString;
#if 0
typedef void (APIENTRY * PFNglEnableClientState) (GLenum cap); // redefined in r_opengl.c
static PFNglEnableClientState pglEnableClientState;
#endif
#endif #endif
// ========================================================================== // ==========================================================================

View file

@ -0,0 +1,52 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#ifndef _R_VBO_H_
#define _R_VBO_H_
typedef struct
{
float x, y, z; // Vertex
float nx, ny, nz; // Normal
float s0, t0; // Texcoord0
} vbo32_t;
typedef struct
{
float x, y, z; // Vertex
float s0, t0; // Texcoord0
unsigned char r, g, b, a; // Color
float pad[2]; // Pad
} vbo2d32_t;
typedef struct
{
float x, y; // Vertex
float s0, t0; // Texcoord0
} vbofont_t;
typedef struct
{
short x, y, z; // Vertex
char nx, ny, nz; // Normal
char tanx, tany, tanz; // Tangent
float s0, t0; // Texcoord0
} vbotiny_t;
typedef struct
{
float x, y, z; // Vertex
float nx, ny, nz; // Normal
float s0, t0; // Texcoord0
float s1, t1; // Texcoord1
float s2, t2; // Texcoord2
float tan0, tan1, tan2; // Tangent
unsigned char r, g, b, a; // Color
} vbo64_t;
#endif

230
src/hardware/u_list.c Normal file
View file

@ -0,0 +1,230 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#include "u_list.h"
#include "../z_zone.h"
// Utility for managing
// structures in a linked
// list.
//
// Struct must have "next" and "prev" pointers
// as its first two variables.
//
//
// ListAdd
//
// Adds an item to the list
//
void ListAdd(void *pItem, listitem_t **itemHead)
{
listitem_t *item = (listitem_t*)pItem;
if (*itemHead == NULL)
{
*itemHead = item;
(*itemHead)->prev = (*itemHead)->next = NULL;
}
else
{
listitem_t *tail;
tail = *itemHead;
while (tail->next != NULL)
tail = tail->next;
tail->next = item;
tail->next->prev = tail;
item->next = NULL;
}
}
//
// ListAddFront
//
// Adds an item to the front of the list
// (This is much faster)
//
void ListAddFront(void *pItem, listitem_t **itemHead)
{
listitem_t *item = (listitem_t*)pItem;
if (*itemHead == NULL)
{
*itemHead = item;
(*itemHead)->prev = (*itemHead)->next = NULL;
}
else
{
(*itemHead)->prev = item;
item->next = (*itemHead);
item->prev = NULL;
*itemHead = item;
}
}
//
// ListAddBefore
//
// Adds an item before the item specified in the list
//
void ListAddBefore(void *pItem, void *pSpot, listitem_t **itemHead)
{
listitem_t *item = (listitem_t*)pItem;
listitem_t *spot = (listitem_t*)pSpot;
listitem_t *prev = spot->prev;
if (!prev)
ListAddFront(pItem, itemHead);
else
{
item->next = spot;
spot->prev = item;
item->prev = prev;
prev->next = item;
}
}
//
// ListAddAfter
//
// Adds an item after the item specified in the list
//
void ListAddAfter(void *pItem, void *pSpot, listitem_t **itemHead)
{
listitem_t *item = (listitem_t*)pItem;
listitem_t *spot = (listitem_t*)pSpot;
listitem_t *next = spot->next;
if (!next)
ListAdd(pItem, itemHead);
else
{
item->prev = spot;
spot->next = item;
item->next = next;
next->prev = item;
}
}
//
// ListRemove
//
// Take an item out of the list and free its memory.
//
void ListRemove(void *pItem, listitem_t **itemHead)
{
listitem_t *item = (listitem_t*)pItem;
if (item == *itemHead) // Start of list
{
*itemHead = item->next;
if (*itemHead)
(*itemHead)->prev = NULL;
}
else if (item->next == NULL) // end of list
{
item->prev->next = NULL;
}
else // Somewhere in between
{
item->prev->next = item->next;
item->next->prev = item->prev;
}
Z_Free (item);
}
//
// ListRemoveAll
//
// Removes all items from the list, freeing their memory.
//
void ListRemoveAll(listitem_t **itemHead)
{
listitem_t *item;
listitem_t *next;
for (item = *itemHead; item; item = next)
{
next = item->next;
ListRemove(item, itemHead);
}
}
//
// ListRemoveNoFree
//
// Take an item out of the list, but don't free its memory.
//
void ListRemoveNoFree(void *pItem, listitem_t **itemHead)
{
listitem_t *item = (listitem_t*)pItem;
if (item == *itemHead) // Start of list
{
*itemHead = item->next;
if (*itemHead)
(*itemHead)->prev = NULL;
}
else if (item->next == NULL) // end of list
{
item->prev->next = NULL;
}
else // Somewhere in between
{
item->prev->next = item->next;
item->next->prev = item->prev;
}
}
//
// ListGetCount
//
// Counts the # of items in a list
// Should not be used in performance-minded code
//
unsigned int ListGetCount(void *itemHead)
{
listitem_t *item = (listitem_t*)itemHead;
unsigned int count = 0;
for (; item; item = item->next)
count++;
return count;
}
//
// ListGetByIndex
//
// Gets an item in the list by its index
// Should not be used in performance-minded code
//
listitem_t *ListGetByIndex(void *itemHead, unsigned int index)
{
listitem_t *head = (listitem_t*)itemHead;
unsigned int count = 0;
listitem_t *node;
for (node = head; node; node = node->next)
{
if (count == index)
return node;
count++;
}
return NULL;
}

29
src/hardware/u_list.h Normal file
View file

@ -0,0 +1,29 @@
/*
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
An experimental work-in-progress.
Donated to Sonic Team Junior and adapted to work with
Sonic Robo Blast 2. The license of this code matches whatever
the licensing is for Sonic Robo Blast 2.
*/
#ifndef _U_LIST_H_
#define _U_LIST_H_
typedef struct listitem_s
{
struct listitem_s *next;
struct listitem_s *prev;
} listitem_t;
void ListAdd(void *pItem, listitem_t **itemHead);
void ListAddFront(void *pItem, listitem_t **itemHead);
void ListAddBefore(void *pItem, void *pSpot, listitem_t **itemHead);
void ListAddAfter(void *pItem, void *pSpot, listitem_t **itemHead);
void ListRemove(void *pItem, listitem_t **itemHead);
void ListRemoveAll(listitem_t **itemHead);
void ListRemoveNoFree(void *pItem, listitem_t **itemHead);
unsigned int ListGetCount(void *itemHead);
listitem_t *ListGetByIndex(void *itemHead, unsigned int index);
#endif

View file

@ -146,6 +146,18 @@ boolean I_SongPaused(void);
boolean I_SetSongSpeed(float speed); boolean I_SetSongSpeed(float speed);
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void);
boolean I_SetSongLoopPoint(UINT32 looppoint);
UINT32 I_GetSongLoopPoint(void);
boolean I_SetSongPosition(UINT32 position);
UINT32 I_GetSongPosition(void);
/// ------------------------ /// ------------------------
// MUSIC PLAYBACK // MUSIC PLAYBACK
/// ------------------------ /// ------------------------
@ -216,6 +228,17 @@ void I_SetMusicVolume(UINT8 volume);
boolean I_SetSongTrack(INT32 track); boolean I_SetSongTrack(INT32 track);
/// ------------------------
/// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume);
void I_StopFadingSong(void);
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
boolean I_FadeOutStopSong(UINT32 ms);
boolean I_FadeInPlaySong(UINT32 ms, boolean looping);
/// ------------------------ /// ------------------------
// CD MUSIC I/O // CD MUSIC I/O
/// ------------------------ /// ------------------------

View file

@ -813,6 +813,8 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
#endif #endif
#endif #endif
mysockaddr_t straddr; mysockaddr_t straddr;
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
if (s == (SOCKET_TYPE)ERRSOCKET) if (s == (SOCKET_TYPE)ERRSOCKET)
return (SOCKET_TYPE)ERRSOCKET; return (SOCKET_TYPE)ERRSOCKET;
@ -906,12 +908,16 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10); CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10);
} }
if (getsockname(s, (struct sockaddr *)&sin, &len) == -1)
CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n"));
else
current_port = (UINT16)ntohs(sin.sin_port);
return s; return s;
} }
static boolean UDP_Socket(void) static boolean UDP_Socket(void)
{ {
const char *sock_port = NULL;
size_t s; size_t s;
struct my_addrinfo *ai, *runp, hints; struct my_addrinfo *ai, *runp, hints;
int gaie; int gaie;
@ -933,20 +939,11 @@ static boolean UDP_Socket(void)
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP; hints.ai_protocol = IPPROTO_UDP;
if (M_CheckParm("-clientport"))
{
if (!M_IsNextParm())
I_Error("syntax: -clientport <portnum>");
sock_port = M_GetNextParm();
}
else
sock_port = port_name;
if (M_CheckParm("-bindaddr")) if (M_CheckParm("-bindaddr"))
{ {
while (M_IsNextParm()) while (M_IsNextParm())
{ {
gaie = I_getaddrinfo(M_GetNextParm(), sock_port, &hints, &ai); gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai);
if (gaie == 0) if (gaie == 0)
{ {
runp = ai; runp = ai;
@ -967,7 +964,7 @@ static boolean UDP_Socket(void)
} }
else else
{ {
gaie = I_getaddrinfo("0.0.0.0", sock_port, &hints, &ai); gaie = I_getaddrinfo("0.0.0.0", port_name, &hints, &ai);
if (gaie == 0) if (gaie == 0)
{ {
runp = ai; runp = ai;
@ -982,8 +979,8 @@ static boolean UDP_Socket(void)
#ifdef HAVE_MINIUPNPC #ifdef HAVE_MINIUPNPC
if (UPNP_support) if (UPNP_support)
{ {
I_UPnP_rem(sock_port, "UDP"); I_UPnP_rem(port_name, "UDP");
I_UPnP_add(NULL, sock_port, "UDP"); I_UPnP_add(NULL, port_name, "UDP");
} }
#endif #endif
} }
@ -1000,7 +997,7 @@ static boolean UDP_Socket(void)
{ {
while (M_IsNextParm()) while (M_IsNextParm())
{ {
gaie = I_getaddrinfo(M_GetNextParm(), sock_port, &hints, &ai); gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai);
if (gaie == 0) if (gaie == 0)
{ {
runp = ai; runp = ai;
@ -1021,7 +1018,7 @@ static boolean UDP_Socket(void)
} }
else else
{ {
gaie = I_getaddrinfo("::", sock_port, &hints, &ai); gaie = I_getaddrinfo("::", port_name, &hints, &ai);
if (gaie == 0) if (gaie == 0)
{ {
runp = ai; runp = ai;
@ -1478,14 +1475,15 @@ boolean I_InitTcpNetwork(void)
if (!I_InitTcpDriver()) if (!I_InitTcpDriver())
return false; return false;
if (M_CheckParm("-udpport")) if (M_CheckParm("-port"))
// Combined -udpport and -clientport into -port
// As it was really redundant having two seperate parms that does the same thing
{ {
if (M_IsNextParm()) if (M_IsNextParm())
strcpy(port_name, M_GetNextParm()); strcpy(port_name, M_GetNextParm());
else else
strcpy(port_name, "0"); strcpy(port_name, "0");
} }
current_port = (UINT16)atoi(port_name);
// parse network game options, // parse network game options,
if (M_CheckParm("-server") || dedicated) if (M_CheckParm("-server") || dedicated)

View file

@ -219,6 +219,7 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] =
SKINCOLOR_SUNSET,10, // SKINCOLOR_MOONSLAM SKINCOLOR_SUNSET,10, // SKINCOLOR_MOONSLAM
SKINCOLOR_MAUVE,10, // SKINCOLOR_ULTRAVIOLET SKINCOLOR_MAUVE,10, // SKINCOLOR_ULTRAVIOLET
SKINCOLOR_DAWN,6, // SKINCOLOR_DUSK SKINCOLOR_DAWN,6, // SKINCOLOR_DUSK
SKINCOLOR_POPCORN,12, // SKINCOLOR_BUBBLEGUM
SKINCOLOR_EMERALD,8, // SKINCOLOR_PURPLE SKINCOLOR_EMERALD,8, // SKINCOLOR_PURPLE
SKINCOLOR_PASTEL,11, // SKINCOLOR_FUCHSIA SKINCOLOR_PASTEL,11, // SKINCOLOR_FUCHSIA
SKINCOLOR_MAROON,8, // SKINCOLOR_TOXIC SKINCOLOR_MAROON,8, // SKINCOLOR_TOXIC

View file

@ -769,7 +769,8 @@ static int lib_pRestoreMusic(lua_State *L)
NOHUD NOHUD
if (!player) if (!player)
return LUA_ErrInvalid(L, "player_t"); return LUA_ErrInvalid(L, "player_t");
P_RestoreMusic(player); if (P_IsLocalPlayer(player))
P_RestoreMusic(player);
return 0; return 0;
} }
@ -1836,7 +1837,7 @@ static int lib_sChangeMusic(lua_State *L)
{ {
#ifdef MUSICSLOT_COMPATIBILITY #ifdef MUSICSLOT_COMPATIBILITY
const char *music_name; const char *music_name;
UINT32 music_num; UINT32 music_num, position, prefadems, fadeinms;
char music_compat_name[7]; char music_compat_name[7];
boolean looping; boolean looping;
@ -1864,7 +1865,6 @@ static int lib_sChangeMusic(lua_State *L)
music_name = luaL_checkstring(L, 1); music_name = luaL_checkstring(L, 1);
} }
looping = (boolean)lua_opttrueboolean(L, 2); looping = (boolean)lua_opttrueboolean(L, 2);
#else #else
@ -1889,8 +1889,12 @@ static int lib_sChangeMusic(lua_State *L)
#endif #endif
music_flags = (UINT16)luaL_optinteger(L, 4, 0); music_flags = (UINT16)luaL_optinteger(L, 4, 0);
position = (UINT32)luaL_optinteger(L, 5, 0);
prefadems = (UINT32)luaL_optinteger(L, 6, 0);
fadeinms = (UINT32)luaL_optinteger(L, 7, 0);
if (!player || P_IsLocalPlayer(player)) if (!player || P_IsLocalPlayer(player))
S_ChangeMusic(music_name, music_flags, looping); S_ChangeMusicEx(music_name, music_flags, looping, position, prefadems, fadeinms);
return 0; return 0;
} }
@ -1907,10 +1911,8 @@ static int lib_sSpeedMusic(lua_State *L)
return LUA_ErrInvalid(L, "player_t"); return LUA_ErrInvalid(L, "player_t");
} }
if (!player || P_IsLocalPlayer(player)) if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_SpeedMusic(speed)); S_SpeedMusic(speed);
else return 0;
lua_pushboolean(L, false);
return 1;
} }
static int lib_sStopMusic(lua_State *L) static int lib_sStopMusic(lua_State *L)
@ -1928,6 +1930,110 @@ static int lib_sStopMusic(lua_State *L)
return 0; return 0;
} }
static int lib_sSetInternalMusicVolume(lua_State *L)
{
UINT32 volume = (UINT32)luaL_checkinteger(L, 1);
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_SetInternalMusicVolume(volume);
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sStopFadingMusic(lua_State *L)
{
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
S_StopFadingMusic();
lua_pushboolean(L, true);
}
else
lua_pushnil(L);
return 1;
}
static int lib_sFadeMusic(lua_State *L)
{
UINT32 target_volume = (UINT32)luaL_checkinteger(L, 1);
UINT32 ms;
INT32 source_volume;
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
ms = (UINT32)luaL_checkinteger(L, 2);
source_volume = -1;
}
else if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
{
player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
source_volume = (INT32)luaL_checkinteger(L, 2);
ms = (UINT32)luaL_checkinteger(L, 3);
}
else if (luaL_optinteger(L, 3, INT32_MAX) == INT32_MAX)
{
ms = (UINT32)luaL_checkinteger(L, 2);
source_volume = -1;
}
else
{
source_volume = (INT32)luaL_checkinteger(L, 2);
ms = (UINT32)luaL_checkinteger(L, 3);
}
NOHUD
if (!player || P_IsLocalPlayer(player))
lua_pushboolean(L, S_FadeMusicFromVolume(target_volume, source_volume, ms));
else
lua_pushnil(L);
return 1;
}
static int lib_sFadeOutStopMusic(lua_State *L)
{
UINT32 ms = (UINT32)luaL_checkinteger(L, 1);
player_t *player = NULL;
NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsLocalPlayer(player))
{
lua_pushboolean(L, S_FadeOutStopMusic(ms));
}
else
lua_pushnil(L);
return 1;
}
static int lib_sOriginPlaying(lua_State *L) static int lib_sOriginPlaying(lua_State *L)
{ {
void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -2727,6 +2833,10 @@ static luaL_Reg lib[] = {
{"S_ChangeMusic",lib_sChangeMusic}, {"S_ChangeMusic",lib_sChangeMusic},
{"S_SpeedMusic",lib_sSpeedMusic}, {"S_SpeedMusic",lib_sSpeedMusic},
{"S_StopMusic",lib_sStopMusic}, {"S_StopMusic",lib_sStopMusic},
{"S_SetInternalMusicVolume", lib_sSetInternalMusicVolume},
{"S_StopFadingMusic",lib_sStopFadingMusic},
{"S_FadeMusic",lib_sFadeMusic},
{"S_FadeOutStopMusic",lib_sFadeOutStopMusic},
{"S_OriginPlaying",lib_sOriginPlaying}, {"S_OriginPlaying",lib_sOriginPlaying},
{"S_IdPlaying",lib_sIdPlaying}, {"S_IdPlaying",lib_sIdPlaying},
{"S_SoundPlaying",lib_sSoundPlaying}, {"S_SoundPlaying",lib_sSoundPlaying},
@ -2752,7 +2862,7 @@ static luaL_Reg lib[] = {
// k_kart // k_kart
{"K_PlayAttackTaunt", lib_kAttackSound}, {"K_PlayAttackTaunt", lib_kAttackSound},
{"K_PlayBoostTaunt", lib_kBoostSound}, {"K_PlayBoostTaunt", lib_kBoostSound},
{"K_PlayPowerGloatSund", lib_kGloatSound}, {"K_PlayPowerGloatSound", lib_kGloatSound},
{"K_PlayOvertakeSound", lib_kOvertakeSound}, {"K_PlayOvertakeSound", lib_kOvertakeSound},
{"K_PlayLossSound", lib_kLossSound}, {"K_PlayLossSound", lib_kLossSound},
{"K_PlayHitEmSound", lib_kHitEmSound}, {"K_PlayHitEmSound", lib_kHitEmSound},

View file

@ -51,6 +51,7 @@ enum hook {
hook_PlayerExplode, //SRB2KART hook_PlayerExplode, //SRB2KART
hook_PlayerSquish, //SRB2KART hook_PlayerSquish, //SRB2KART
hook_PlayerCmd, //SRB2KART hook_PlayerCmd, //SRB2KART
hook_IntermissionThinker, //SRB2KART
hook_MAX // last hook hook_MAX // last hook
}; };
@ -99,4 +100,6 @@ boolean LUAh_PlayerSquish(player_t *player, mobj_t *inflictor, mobj_t *source);
boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them. boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them.
void LUAh_IntermissionThinker(void); // Hook for Y_Ticker
#endif #endif

View file

@ -62,6 +62,7 @@ const char *const hookNames[hook_MAX+1] = {
"PlayerExplode", "PlayerExplode",
"PlayerSquish", "PlayerSquish",
"PlayerCmd", "PlayerCmd",
"IntermissionThinker",
NULL NULL
}; };
@ -420,6 +421,28 @@ void LUAh_ThinkFrame(void)
} }
} }
// Hook for Y_Ticker
void LUAh_IntermissionThinker(void)
{
hook_p hookp;
if (!gL || !(hooksAvailable[hook_IntermissionThinker/8] & (1<<(hook_IntermissionThinker%8))))
return;
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_IntermissionThinker)
{
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
if (lua_pcall(gL, 0, 0, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
}
}
}
// Hook for mobj collisions // Hook for mobj collisions
UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
{ {

View file

@ -1477,6 +1477,12 @@ static int mapheaderinfo_get(lua_State *L)
lua_pushstring(L, header->musname); lua_pushstring(L, header->musname);
else if (fastcmp(field,"mustrack")) else if (fastcmp(field,"mustrack"))
lua_pushinteger(L, header->mustrack); lua_pushinteger(L, header->mustrack);
else if (fastcmp(field,"muspos"))
lua_pushinteger(L, header->muspos);
else if (fastcmp(field,"musinterfadeout"))
lua_pushinteger(L, header->musinterfadeout);
else if (fastcmp(field,"musintername"))
lua_pushstring(L, header->musintername);
else if (fastcmp(field,"forcecharacter")) else if (fastcmp(field,"forcecharacter"))
lua_pushstring(L, header->forcecharacter); lua_pushstring(L, header->forcecharacter);
else if (fastcmp(field,"weather")) else if (fastcmp(field,"weather"))

View file

@ -56,7 +56,7 @@ fixed_t FixedDiv2(fixed_t a, fixed_t b)
if (b == 0) if (b == 0)
I_Error("FixedDiv: divide by zero"); I_Error("FixedDiv: divide by zero");
ret = (((INT64)a * FRACUNIT) ) / b; ret = (((INT64)a * FRACUNIT)) / b;
if ((ret > INT32_MAX) || (ret < INT32_MIN)) if ((ret > INT32_MAX) || (ret < INT32_MIN))
I_Error("FixedDiv: divide by zero"); I_Error("FixedDiv: divide by zero");
@ -117,7 +117,7 @@ fixed_t FixedHypot(fixed_t x, fixed_t y)
yx = FixedDiv(y, x); // (x/y) yx = FixedDiv(y, x); // (x/y)
} }
yx2 = FixedMul(yx, yx); // (x/y)^2 yx2 = FixedMul(yx, yx); // (x/y)^2
yx1 = FixedSqrt(1*FRACUNIT + yx2); // (1 + (x/y)^2)^1/2 yx1 = FixedSqrt(1 * FRACUNIT + yx2); // (1 + (x/y)^2)^1/2
return FixedMul(ax, yx1); // |x|*((1 + (x/y)^2)^1/2) return FixedMul(ax, yx1); // |x|*((1 + (x/y)^2)^1/2)
} }
@ -191,8 +191,8 @@ vector2_t *FV2_Divide(vector2_t *a_i, fixed_t a_c)
// Vector Complex Math // Vector Complex Math
vector2_t *FV2_Midpoint(const vector2_t *a_1, const vector2_t *a_2, vector2_t *a_o) vector2_t *FV2_Midpoint(const vector2_t *a_1, const vector2_t *a_2, vector2_t *a_o)
{ {
a_o->x = FixedDiv(a_2->x - a_1->x, 2*FRACUNIT); a_o->x = FixedDiv(a_2->x - a_1->x, 2 * FRACUNIT);
a_o->y = FixedDiv(a_2->y - a_1->y, 2*FRACUNIT); a_o->y = FixedDiv(a_2->y - a_1->y, 2 * FRACUNIT);
a_o->x = a_1->x + a_o->x; a_o->x = a_1->x + a_o->x;
a_o->y = a_1->y + a_o->y; a_o->y = a_1->y + a_o->y;
return a_o; return a_o;
@ -200,16 +200,16 @@ vector2_t *FV2_Midpoint(const vector2_t *a_1, const vector2_t *a_2, vector2_t *a
fixed_t FV2_Distance(const vector2_t *p1, const vector2_t *p2) fixed_t FV2_Distance(const vector2_t *p1, const vector2_t *p2)
{ {
fixed_t xs = FixedMul(p2->x-p1->x,p2->x-p1->x); fixed_t xs = FixedMul(p2->x - p1->x, p2->x - p1->x);
fixed_t ys = FixedMul(p2->y-p1->y,p2->y-p1->y); fixed_t ys = FixedMul(p2->y - p1->y, p2->y - p1->y);
return FixedSqrt(xs+ys); return FixedSqrt(xs + ys);
} }
fixed_t FV2_Magnitude(const vector2_t *a_normal) fixed_t FV2_Magnitude(const vector2_t *a_normal)
{ {
fixed_t xs = FixedMul(a_normal->x,a_normal->x); fixed_t xs = FixedMul(a_normal->x, a_normal->x);
fixed_t ys = FixedMul(a_normal->y,a_normal->y); fixed_t ys = FixedMul(a_normal->y, a_normal->y);
return FixedSqrt(xs+ys); return FixedSqrt(xs + ys);
} }
// Also returns the magnitude // Also returns the magnitude
@ -240,7 +240,7 @@ vector2_t *FV2_Negate(vector2_t *a_1)
boolean FV2_Equal(const vector2_t *a_1, const vector2_t *a_2) boolean FV2_Equal(const vector2_t *a_1, const vector2_t *a_2)
{ {
fixed_t Epsilon = FRACUNIT/FRACUNIT; fixed_t Epsilon = FRACUNIT / FRACUNIT;
if ((abs(a_2->x - a_1->x) > Epsilon) || if ((abs(a_2->x - a_1->x) > Epsilon) ||
(abs(a_2->y - a_1->y) > Epsilon)) (abs(a_2->y - a_1->y) > Epsilon))
@ -261,7 +261,7 @@ fixed_t FV2_Dot(const vector2_t *a_1, const vector2_t *a_2)
// //
// Given two points, create a vector between them. // Given two points, create a vector between them.
// //
vector2_t *FV2_Point2Vec (const vector2_t *point1, const vector2_t *point2, vector2_t *a_o) vector2_t *FV2_Point2Vec(const vector2_t *point1, const vector2_t *point2, vector2_t *a_o)
{ {
a_o->x = point1->x - point2->x; a_o->x = point1->x - point2->x;
a_o->y = point1->y - point2->y; a_o->y = point1->y - point2->y;
@ -344,9 +344,9 @@ vector3_t *FV3_Divide(vector3_t *a_i, fixed_t a_c)
// Vector Complex Math // Vector Complex Math
vector3_t *FV3_Midpoint(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o) vector3_t *FV3_Midpoint(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o)
{ {
a_o->x = FixedDiv(a_2->x - a_1->x, 2*FRACUNIT); a_o->x = FixedDiv(a_2->x - a_1->x, 2 * FRACUNIT);
a_o->y = FixedDiv(a_2->y - a_1->y, 2*FRACUNIT); a_o->y = FixedDiv(a_2->y - a_1->y, 2 * FRACUNIT);
a_o->z = FixedDiv(a_2->z - a_1->z, 2*FRACUNIT); a_o->z = FixedDiv(a_2->z - a_1->z, 2 * FRACUNIT);
a_o->x = a_1->x + a_o->x; a_o->x = a_1->x + a_o->x;
a_o->y = a_1->y + a_o->y; a_o->y = a_1->y + a_o->y;
a_o->z = a_1->z + a_o->z; a_o->z = a_1->z + a_o->z;
@ -355,18 +355,18 @@ vector3_t *FV3_Midpoint(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a
fixed_t FV3_Distance(const vector3_t *p1, const vector3_t *p2) fixed_t FV3_Distance(const vector3_t *p1, const vector3_t *p2)
{ {
fixed_t xs = FixedMul(p2->x-p1->x,p2->x-p1->x); fixed_t xs = FixedMul(p2->x - p1->x, p2->x - p1->x);
fixed_t ys = FixedMul(p2->y-p1->y,p2->y-p1->y); fixed_t ys = FixedMul(p2->y - p1->y, p2->y - p1->y);
fixed_t zs = FixedMul(p2->z-p1->z,p2->z-p1->z); fixed_t zs = FixedMul(p2->z - p1->z, p2->z - p1->z);
return FixedSqrt(xs+ys+zs); return FixedSqrt(xs + ys + zs);
} }
fixed_t FV3_Magnitude(const vector3_t *a_normal) fixed_t FV3_Magnitude(const vector3_t *a_normal)
{ {
fixed_t xs = FixedMul(a_normal->x,a_normal->x); fixed_t xs = FixedMul(a_normal->x, a_normal->x);
fixed_t ys = FixedMul(a_normal->y,a_normal->y); fixed_t ys = FixedMul(a_normal->y, a_normal->y);
fixed_t zs = FixedMul(a_normal->z,a_normal->z); fixed_t zs = FixedMul(a_normal->z, a_normal->z);
return FixedSqrt(xs+ys+zs); return FixedSqrt(xs + ys + zs);
} }
// Also returns the magnitude // Also returns the magnitude
@ -399,7 +399,7 @@ vector3_t *FV3_Negate(vector3_t *a_1)
boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2) boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2)
{ {
fixed_t Epsilon = FRACUNIT/FRACUNIT; fixed_t Epsilon = FRACUNIT / FRACUNIT;
if ((abs(a_2->x - a_1->x) > Epsilon) || if ((abs(a_2->x - a_1->x) > Epsilon) ||
(abs(a_2->y - a_1->y) > Epsilon) || (abs(a_2->y - a_1->y) > Epsilon) ||
@ -458,6 +458,20 @@ vector3_t *FV3_ClosestPointOnLine(const vector3_t *Line, const vector3_t *p, vec
return FV3_AddEx(&Line[0], &V, out); return FV3_AddEx(&Line[0], &V, out);
} }
//
// ClosestPointOnVector
//
// Similar to ClosestPointOnLine, but uses a vector instead of two points.
//
void FV3_ClosestPointOnVector(const vector3_t *dir, const vector3_t *p, vector3_t *out)
{
fixed_t t = FV3_Dot(dir, p);
// Return the point on the line closest
FV3_MulEx(dir, t, out);
return;
}
// //
// ClosestPointOnTriangle // ClosestPointOnTriangle
// //
@ -465,7 +479,7 @@ vector3_t *FV3_ClosestPointOnLine(const vector3_t *Line, const vector3_t *p, vec
// the closest point on the edge of // the closest point on the edge of
// the triangle is returned. // the triangle is returned.
// //
void FV3_ClosestPointOnTriangle (const vector3_t *tri, const vector3_t *point, vector3_t *result) void FV3_ClosestPointOnTriangle(const vector3_t *tri, const vector3_t *point, vector3_t *result)
{ {
UINT8 i; UINT8 i;
fixed_t dist, closestdist; fixed_t dist, closestdist;
@ -506,7 +520,7 @@ void FV3_ClosestPointOnTriangle (const vector3_t *tri, const vector3_t *point, v
// //
// Given two points, create a vector between them. // Given two points, create a vector between them.
// //
vector3_t *FV3_Point2Vec (const vector3_t *point1, const vector3_t *point2, vector3_t *a_o) vector3_t *FV3_Point2Vec(const vector3_t *point1, const vector3_t *point2, vector3_t *a_o)
{ {
a_o->x = point1->x - point2->x; a_o->x = point1->x - point2->x;
a_o->y = point1->y - point2->y; a_o->y = point1->y - point2->y;
@ -519,7 +533,7 @@ vector3_t *FV3_Point2Vec (const vector3_t *point1, const vector3_t *point2, vect
// //
// Calculates the normal of a polygon. // Calculates the normal of a polygon.
// //
void FV3_Normal (const vector3_t *a_triangle, vector3_t *a_normal) fixed_t FV3_Normal(const vector3_t *a_triangle, vector3_t *a_normal)
{ {
vector3_t a_1; vector3_t a_1;
vector3_t a_2; vector3_t a_2;
@ -529,7 +543,28 @@ void FV3_Normal (const vector3_t *a_triangle, vector3_t *a_normal)
FV3_Cross(&a_1, &a_2, a_normal); FV3_Cross(&a_1, &a_2, a_normal);
FV3_NormalizeEx(a_normal, a_normal); return FV3_NormalizeEx(a_normal, a_normal);
}
//
// Strength
//
// Measures the 'strength' of a vector in a particular direction.
//
fixed_t FV3_Strength(const vector3_t *a_1, const vector3_t *dir)
{
vector3_t normal;
fixed_t dist = FV3_NormalizeEx(a_1, &normal);
fixed_t dot = FV3_Dot(&normal, dir);
FV3_ClosestPointOnVector(dir, a_1, &normal);
dist = FV3_Magnitude(&normal);
if (dot < 0) // Not facing same direction, so negate result.
dist = -dist;
return dist;
} }
// //
@ -550,11 +585,11 @@ boolean FV3_IntersectedPlane(const vector3_t *a_triangle, const vector3_t *a_lin
*originDistance = FV3_PlaneDistance(a_normal, &a_triangle[0]); *originDistance = FV3_PlaneDistance(a_normal, &a_triangle[0]);
distance1 = (FixedMul(a_normal->x, a_line[0].x) + FixedMul(a_normal->y, a_line[0].y) distance1 = (FixedMul(a_normal->x, a_line[0].x) + FixedMul(a_normal->y, a_line[0].y)
+ FixedMul(a_normal->z, a_line[0].z)) + *originDistance; + FixedMul(a_normal->z, a_line[0].z)) + *originDistance;
distance2 = (FixedMul(a_normal->x, a_line[1].x) + FixedMul(a_normal->y, a_line[1].y) distance2 = (FixedMul(a_normal->x, a_line[1].x) + FixedMul(a_normal->y, a_line[1].y)
+ FixedMul(a_normal->z, a_line[1].z)) + *originDistance; + FixedMul(a_normal->z, a_line[1].z)) + *originDistance;
// Positive or zero number means no intersection // Positive or zero number means no intersection
if (FixedMul(distance1, distance2) >= 0) if (FixedMul(distance1, distance2) >= 0)
@ -575,8 +610,8 @@ boolean FV3_IntersectedPlane(const vector3_t *a_triangle, const vector3_t *a_lin
fixed_t FV3_PlaneIntersection(const vector3_t *pOrigin, const vector3_t *pNormal, const vector3_t *rOrigin, const vector3_t *rVector) fixed_t FV3_PlaneIntersection(const vector3_t *pOrigin, const vector3_t *pNormal, const vector3_t *rOrigin, const vector3_t *rVector)
{ {
fixed_t d = -(FV3_Dot(pNormal, pOrigin)); fixed_t d = -(FV3_Dot(pNormal, pOrigin));
fixed_t number = FV3_Dot(pNormal,rOrigin) + d; fixed_t number = FV3_Dot(pNormal, rOrigin) + d;
fixed_t denom = FV3_Dot(pNormal,rVector); fixed_t denom = FV3_Dot(pNormal, rVector);
return -FixedDiv(number, denom); return -FixedDiv(number, denom);
} }
@ -597,11 +632,11 @@ fixed_t FV3_IntersectRaySphere(const vector3_t *rO, const vector3_t *rV, const v
c = FV3_Magnitude(&Q); c = FV3_Magnitude(&Q);
v = FV3_Dot(&Q, rV); v = FV3_Dot(&Q, rV);
d = FixedMul(sR, sR) - (FixedMul(c,c) - FixedMul(v,v)); d = FixedMul(sR, sR) - (FixedMul(c, c) - FixedMul(v, v));
// If there was no intersection, return -1 // If there was no intersection, return -1
if (d < 0*FRACUNIT) if (d < 0 * FRACUNIT)
return (-1*FRACUNIT); return (-1 * FRACUNIT);
// Return the distance to the [first] intersecting point // Return the distance to the [first] intersecting point
return (v - FixedSqrt(d)); return (v - FixedSqrt(d));
@ -629,9 +664,9 @@ vector3_t *FV3_IntersectionPoint(const vector3_t *vNormal, const vector3_t *vLin
// Here I just chose a arbitrary point as the point to find that distance. You notice we negate that // Here I just chose a arbitrary point as the point to find that distance. You notice we negate that
// distance. We negate the distance because we want to eventually go BACKWARDS from our point to the plane. // distance. We negate the distance because we want to eventually go BACKWARDS from our point to the plane.
// By doing this is will basically bring us back to the plane to find our intersection point. // By doing this is will basically bring us back to the plane to find our intersection point.
Numerator = - (FixedMul(vNormal->x, vLine[0].x) + // Use the plane equation with the normal and the line Numerator = -(FixedMul(vNormal->x, vLine[0].x) + // Use the plane equation with the normal and the line
FixedMul(vNormal->y, vLine[0].y) + FixedMul(vNormal->y, vLine[0].y) +
FixedMul(vNormal->z, vLine[0].z) + distance); FixedMul(vNormal->z, vLine[0].z) + distance);
// 3) If we take the dot product between our line vector and the normal of the polygon, // 3) If we take the dot product between our line vector and the normal of the polygon,
// this will give us the cosine of the angle between the 2 (since they are both normalized - length 1). // this will give us the cosine of the angle between the 2 (since they are both normalized - length 1).
@ -643,7 +678,7 @@ vector3_t *FV3_IntersectionPoint(const vector3_t *vNormal, const vector3_t *vLin
// on the plane (the normal is perpendicular to the line - (Normal.Vector = 0)). // on the plane (the normal is perpendicular to the line - (Normal.Vector = 0)).
// In this case, we should just return any point on the line. // In this case, we should just return any point on the line.
if( Denominator == 0*FRACUNIT) // Check so we don't divide by zero if (Denominator == 0 * FRACUNIT) // Check so we don't divide by zero
{ {
ReturnVec->x = vLine[0].x; ReturnVec->x = vLine[0].x;
ReturnVec->y = vLine[0].y; ReturnVec->y = vLine[0].y;
@ -686,8 +721,8 @@ vector3_t *FV3_IntersectionPoint(const vector3_t *vNormal, const vector3_t *vLin
// //
UINT8 FV3_PointOnLineSide(const vector3_t *point, const vector3_t *line) UINT8 FV3_PointOnLineSide(const vector3_t *point, const vector3_t *line)
{ {
fixed_t s1 = FixedMul((point->y - line[0].y),(line[1].x - line[0].x)); fixed_t s1 = FixedMul((point->y - line[0].y), (line[1].x - line[0].x));
fixed_t s2 = FixedMul((point->x - line[0].x),(line[1].y - line[0].y)); fixed_t s2 = FixedMul((point->x - line[0].x), (line[1].y - line[0].y));
return (UINT8)(s1 - s2 < 0); return (UINT8)(s1 - s2 < 0);
} }
@ -752,7 +787,7 @@ void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fi
matrix->m[0] = upcross.x; matrix->m[0] = upcross.x;
matrix->m[1] = upcross.y; matrix->m[1] = upcross.y;
matrix->m[2] = upcross.z; matrix->m[2] = upcross.z;
matrix->m[3] = 0*FRACUNIT; matrix->m[3] = 0 * FRACUNIT;
matrix->m[4] = upx; matrix->m[4] = upx;
matrix->m[5] = upy; matrix->m[5] = upy;
@ -764,9 +799,9 @@ void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fi
matrix->m[10] = anglez; matrix->m[10] = anglez;
matrix->m[11] = 0; matrix->m[11] = 0;
matrix->m[12] = x - FixedMul(upx,radius); matrix->m[12] = x - FixedMul(upx, radius);
matrix->m[13] = y - FixedMul(upy,radius); matrix->m[13] = y - FixedMul(upy, radius);
matrix->m[14] = z - FixedMul(upz,radius); matrix->m[14] = z - FixedMul(upz, radius);
matrix->m[15] = FRACUNIT; matrix->m[15] = FRACUNIT;
} }
@ -778,20 +813,20 @@ void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fi
void FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out) void FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out)
{ {
#define M(row,col) matrix->m[col * 4 + row] #define M(row,col) matrix->m[col * 4 + row]
out->x = FixedMul(vec->x,M(0, 0)) out->x = FixedMul(vec->x, M(0, 0))
+ FixedMul(vec->y,M(0, 1)) + FixedMul(vec->y, M(0, 1))
+ FixedMul(vec->z,M(0, 2)) + FixedMul(vec->z, M(0, 2))
+ M(0, 3); + M(0, 3);
out->y = FixedMul(vec->x,M(1, 0)) out->y = FixedMul(vec->x, M(1, 0))
+ FixedMul(vec->y,M(1, 1)) + FixedMul(vec->y, M(1, 1))
+ FixedMul(vec->z,M(1, 2)) + FixedMul(vec->z, M(1, 2))
+ M(1, 3); + M(1, 3);
out->z = FixedMul(vec->x,M(2, 0)) out->z = FixedMul(vec->x, M(2, 0))
+ FixedMul(vec->y,M(2, 1)) + FixedMul(vec->y, M(2, 1))
+ FixedMul(vec->z,M(2, 2)) + FixedMul(vec->z, M(2, 2))
+ M(2, 3); + M(2, 3);
#undef M #undef M
} }
@ -811,7 +846,7 @@ void FM_MultMatrix(matrix_t *dest, const matrix_t *multme)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
R(i, j) = FixedMul(D(i, 0),M(0, j)) + FixedMul(D(i, 1),M(1, j)) + FixedMul(D(i, 2),M(2, j)) + FixedMul(D(i, 3),M(3, j)); R(i, j) = FixedMul(D(i, 0), M(0, j)) + FixedMul(D(i, 1), M(1, j)) + FixedMul(D(i, 2), M(2, j)) + FixedMul(D(i, 3), M(3, j));
} }
M_Memcpy(dest, &result, sizeof(matrix_t)); M_Memcpy(dest, &result, sizeof(matrix_t));
@ -869,8 +904,8 @@ void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z)
static inline void M_print(INT64 a) static inline void M_print(INT64 a)
{ {
const fixed_t w = (a>>FRACBITS); const fixed_t w = (a >> FRACBITS);
fixed_t f = a%FRACUNIT; fixed_t f = a % FRACUNIT;
fixed_t d = FRACUNIT; fixed_t d = FRACUNIT;
if (f == 0) if (f == 0)
@ -878,7 +913,7 @@ static inline void M_print(INT64 a)
printf("%d", (fixed_t)w); printf("%d", (fixed_t)w);
return; return;
} }
else while (f != 1 && f/2 == f>>1) else while (f != 1 && f / 2 == f >> 1)
{ {
d /= 2; d /= 2;
f /= 2; f /= 2;
@ -892,7 +927,7 @@ static inline void M_print(INT64 a)
FUNCMATH FUNCINLINE static inline fixed_t FixedMulC(fixed_t a, fixed_t b) FUNCMATH FUNCINLINE static inline fixed_t FixedMulC(fixed_t a, fixed_t b)
{ {
return (fixed_t)((((INT64)a * b) ) / FRACUNIT); return (fixed_t)((((INT64)a * b)) / FRACUNIT);
} }
FUNCMATH FUNCINLINE static inline fixed_t FixedDivC2(fixed_t a, fixed_t b) FUNCMATH FUNCINLINE static inline fixed_t FixedDivC2(fixed_t a, fixed_t b)
@ -902,7 +937,7 @@ FUNCMATH FUNCINLINE static inline fixed_t FixedDivC2(fixed_t a, fixed_t b)
if (b == 0) if (b == 0)
I_Error("FixedDiv: divide by zero"); I_Error("FixedDiv: divide by zero");
ret = (((INT64)a * FRACUNIT) ) / b; ret = (((INT64)a * FRACUNIT)) / b;
if ((ret > INT32_MAX) || (ret < INT32_MIN)) if ((ret > INT32_MAX) || (ret < INT32_MIN))
I_Error("FixedDiv: divide by zero"); I_Error("FixedDiv: divide by zero");
@ -911,7 +946,7 @@ FUNCMATH FUNCINLINE static inline fixed_t FixedDivC2(fixed_t a, fixed_t b)
FUNCMATH FUNCINLINE static inline fixed_t FixedDivC(fixed_t a, fixed_t b) FUNCMATH FUNCINLINE static inline fixed_t FixedDivC(fixed_t a, fixed_t b)
{ {
if ((abs(a) >> (FRACBITS-2)) >= abs(b)) if ((abs(a) >> (FRACBITS - 2)) >= abs(b))
return (a^b) < 0 ? INT32_MIN : INT32_MAX; return (a^b) < 0 ? INT32_MIN : INT32_MAX;
return FixedDivC2(a, b); return FixedDivC2(a, b);
@ -938,43 +973,43 @@ int main(int argc, char** argv)
#ifdef MULDIV_TEST #ifdef MULDIV_TEST
for (a = 1; a <= INT32_MAX; a += FRACUNIT) for (a = 1; a <= INT32_MAX; a += FRACUNIT)
for (b = 0; b <= INT32_MAX; b += FRACUNIT) for (b = 0; b <= INT32_MAX; b += FRACUNIT)
{
c = FixedMul(a, b);
d = FixedMulC(a, b);
if (c != d)
{ {
printf("("); c = FixedMul(a, b);
M_print(a); d = FixedMulC(a, b);
printf(") * ("); if (c != d)
M_print(b); {
printf(") = ("); printf("(");
M_print(c); M_print(a);
printf(") != ("); printf(") * (");
M_print(d); M_print(b);
printf(") \n"); printf(") = (");
n--; M_print(c);
printf("%d != %d\n", c, d); printf(") != (");
M_print(d);
printf(") \n");
n--;
printf("%d != %d\n", c, d);
}
c = FixedDiv(a, b);
d = FixedDivC(a, b);
if (c != d)
{
printf("(");
M_print(a);
printf(") / (");
M_print(b);
printf(") = (");
M_print(c);
printf(") != (");
M_print(d);
printf(")\n");
n--;
printf("%d != %d\n", c, d);
}
if (n <= 0)
exit(-1);
} }
c = FixedDiv(a, b);
d = FixedDivC(a, b);
if (c != d)
{
printf("(");
M_print(a);
printf(") / (");
M_print(b);
printf(") = (");
M_print(c);
printf(") != (");
M_print(d);
printf(")\n");
n--;
printf("%d != %d\n", c, d);
}
if (n <= 0)
exit(-1);
}
#endif #endif
#ifdef SQRT_TEST #ifdef SQRT_TEST
@ -982,7 +1017,7 @@ int main(int argc, char** argv)
{ {
c = FixedSqrt(a); c = FixedSqrt(a);
d = FixedSqrtC(a); d = FixedSqrtC(a);
b = abs(c-d); b = abs(c - d);
if (b > 1) if (b > 1)
{ {
printf("sqrt("); printf("sqrt(");

View file

@ -394,9 +394,11 @@ boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2);
fixed_t FV3_Dot(const vector3_t *a_1, const vector3_t *a_2); fixed_t FV3_Dot(const vector3_t *a_1, const vector3_t *a_2);
vector3_t *FV3_Cross(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o); vector3_t *FV3_Cross(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o);
vector3_t *FV3_ClosestPointOnLine(const vector3_t *Line, const vector3_t *p, vector3_t *out); vector3_t *FV3_ClosestPointOnLine(const vector3_t *Line, const vector3_t *p, vector3_t *out);
void FV3_ClosestPointOnVector(const vector3_t *dir, const vector3_t *p, vector3_t *out);
void FV3_ClosestPointOnTriangle(const vector3_t *tri, const vector3_t *point, vector3_t *result); void FV3_ClosestPointOnTriangle(const vector3_t *tri, const vector3_t *point, vector3_t *result);
vector3_t *FV3_Point2Vec(const vector3_t *point1, const vector3_t *point2, vector3_t *a_o); vector3_t *FV3_Point2Vec(const vector3_t *point1, const vector3_t *point2, vector3_t *a_o);
void FV3_Normal(const vector3_t *a_triangle, vector3_t *a_normal); fixed_t FV3_Normal(const vector3_t *a_triangle, vector3_t *a_normal);
fixed_t FV3_Strength(const vector3_t *a_1, const vector3_t *dir);
fixed_t FV3_PlaneDistance(const vector3_t *a_normal, const vector3_t *a_point); fixed_t FV3_PlaneDistance(const vector3_t *a_normal, const vector3_t *a_point);
boolean FV3_IntersectedPlane(const vector3_t *a_triangle, const vector3_t *a_line, vector3_t *a_normal, fixed_t *originDistance); boolean FV3_IntersectedPlane(const vector3_t *a_triangle, const vector3_t *a_line, vector3_t *a_normal, fixed_t *originDistance);
fixed_t FV3_PlaneIntersection(const vector3_t *pOrigin, const vector3_t *pNormal, const vector3_t *rOrigin, const vector3_t *rVector); fixed_t FV3_PlaneIntersection(const vector3_t *pOrigin, const vector3_t *pNormal, const vector3_t *rOrigin, const vector3_t *rVector);

View file

@ -121,41 +121,8 @@ typedef enum
const char *quitmsg[NUM_QUITMESSAGES]; const char *quitmsg[NUM_QUITMESSAGES];
// Stuff for customizing the player select screen Tails 09-22-2003 // Stuff for customizing the player select screen Tails 09-22-2003
description_t description[32] = description_t description[MAXSKINS];
{
{"\x82Sonic\x80\n\x82Speed:\x80 7\n\x82Weight:\x80 3", "", "sonic"},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""},
{"???", "", ""}
};
//static char *char_notes = NULL; //static char *char_notes = NULL;
//static fixed_t char_scroll = 0; //static fixed_t char_scroll = 0;
@ -413,27 +380,9 @@ static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}};
consvar_t cv_chooseskin = {"chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chooseskin = {"chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL};
// This gametype list is integral for many different reasons. // This gametype list is integral for many different reasons.
// When you add gametypes here, don't forget to update them in CV_AddValue! // When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h!
CV_PossibleValue_t gametype_cons_t[] = CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1];
{
{GT_RACE, "Race"}, {GT_MATCH, "Battle"},
/* // SRB2kart
{GT_COOP, "Co-op"},
{GT_COMPETITION, "Competition"},
{GT_RACE, "Race"},
{GT_MATCH, "Match"},
{GT_TEAMMATCH, "Team Match"},
{GT_TAG, "Tag"},
{GT_HIDEANDSEEK, "Hide and Seek"},
{GT_CTF, "CTF"},
*/
{0, NULL}
};
consvar_t cv_newgametype = {"newgametype", "Race", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_newgametype = {"newgametype", "Race", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t serversort_cons_t[] = { static CV_PossibleValue_t serversort_cons_t[] = {
@ -1219,7 +1168,7 @@ static menuitem_t OP_VideoOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 90}, {IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 90},
#ifdef HWRENDER #ifdef HWRENDER
{IT_STRING | IT_CVAR, NULL, "3D models", &cv_grmd2, 105}, {IT_STRING | IT_CVAR, NULL, "3D models", &cv_grmdls, 105},
{IT_SUBMENU|IT_STRING, NULL, "OpenGL Options...", &OP_OpenGLOptionsDef, 115}, {IT_SUBMENU|IT_STRING, NULL, "OpenGL Options...", &OP_OpenGLOptionsDef, 115},
#endif #endif
}; };
@ -2333,10 +2282,8 @@ static void M_ChangeCvar(INT32 choice)
choice *= (TICRATE/7); choice *= (TICRATE/7);
else if (cv == &cv_maxsend) else if (cv == &cv_maxsend)
choice *= 512; choice *= 512;
#ifdef NEWPING
else if (cv == &cv_maxping) else if (cv == &cv_maxping)
choice *= 50; choice *= 50;
#endif
#endif #endif
CV_AddValue(cv,choice); CV_AddValue(cv,choice);
} }
@ -3254,6 +3201,55 @@ void M_Init(void)
CV_RegisterVar(&cv_allcaps); CV_RegisterVar(&cv_allcaps);
} }
void M_InitCharacterTables(void)
{
UINT8 i;
// Setup PlayerMenu table
for (i = 0; i < MAXSKINS; i++)
{
PlayerMenu[i].status = (i < 4 ? IT_CALL : IT_DISABLED);
PlayerMenu[i].patch = PlayerMenu[i].text = NULL;
PlayerMenu[i].itemaction = M_ChoosePlayer;
PlayerMenu[i].alphaKey = 0;
}
// Setup description table
for (i = 0; i < MAXSKINS; i++)
{
if (i == 0)
{
strcpy(description[i].notes, "\x82Sonic\x80 is the fastest of the three, but also the hardest to control. Beginners beware, but experts will find Sonic very powerful.\n\n\x82""Ability:\x80 Speed Thok\nDouble jump to zoom forward with a huge burst of speed.\n\n\x82Tip:\x80 Simply letting go of forward does not slow down in SRB2. To slow down, hold the opposite direction.");
strcpy(description[i].picname, "");
strcpy(description[i].skinname, "sonic");
}
else if (i == 1)
{
strcpy(description[i].notes, "\x82Tails\x80 is the most mobile of the three, but has the slowest speed. Because of his mobility, he's well-\nsuited to beginners.\n\n\x82""Ability:\x80 Fly\nDouble jump to start flying for a limited time. Repetitively hit the jump button to ascend.\n\n\x82Tip:\x80 To quickly descend while flying, hit the spin button.");
strcpy(description[i].picname, "");
strcpy(description[i].skinname, "tails");
}
else if (i == 2)
{
strcpy(description[i].notes, "\x82Knuckles\x80 is well-\nrounded and can destroy breakable walls simply by touching them, but he can't jump as high as the other two.\n\n\x82""Ability:\x80 Glide & Climb\nDouble jump to glide in the air as long as jump is held. Glide into a wall to climb it.\n\n\x82Tip:\x80 Press spin while climbing to jump off the wall; press jump instead to jump off\nand face away from\nthe wall.");
strcpy(description[i].picname, "");
strcpy(description[i].skinname, "knuckles");
}
else if (i == 3)
{
strcpy(description[i].notes, "\x82Sonic & Tails\x80 team up to take on Dr. Eggman!\nControl Sonic while Tails desperately struggles to keep up.\n\nPlayer 2 can control Tails directly by setting the controls in the options menu.\nTails's directional controls are relative to Player 1's camera.\n\nTails can pick up Sonic while flying and carry him around.");
strcpy(description[i].picname, "CHRS&T");
strcpy(description[i].skinname, "sonic&tails");
}
else
{
strcpy(description[i].notes, "???");
strcpy(description[i].picname, "");
strcpy(description[i].skinname, "");
}
}
}
// ========================================================================== // ==========================================================================
// SPECIAL MENU OPTION DRAW ROUTINES GO HERE // SPECIAL MENU OPTION DRAW ROUTINES GO HERE
// ========================================================================== // ==========================================================================
@ -7283,7 +7279,7 @@ static void M_DrawRoomMenu(void)
static void M_DrawConnectMenu(void) static void M_DrawConnectMenu(void)
{ {
UINT16 i, j; UINT16 i;
const char *gt = "Unknown"; const char *gt = "Unknown";
const char *spd = ""; const char *spd = "";
INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE; INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE;
@ -7330,11 +7326,8 @@ static void M_DrawConnectMenu(void)
va("Ping: %u", (UINT32)LONG(serverlist[slindex].info.time))); va("Ping: %u", (UINT32)LONG(serverlist[slindex].info.time)));
gt = "Unknown"; gt = "Unknown";
for (j = 0; gametype_cons_t[j].strvalue; j++) if (serverlist[slindex].info.gametype < NUMGAMETYPES)
{ gt = Gametype_Names[serverlist[slindex].info.gametype];
if (gametype_cons_t[j].value == serverlist[slindex].info.gametype)
gt = gametype_cons_t[j].strvalue;
}
V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags, V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags,
va("Players: %02d/%02d", serverlist[slindex].info.numberofplayer, serverlist[slindex].info.maxplayer)); va("Players: %02d/%02d", serverlist[slindex].info.numberofplayer, serverlist[slindex].info.maxplayer));
@ -7460,7 +7453,10 @@ static void M_ConnectMenu(INT32 choice)
// first page of servers // first page of servers
serverlistpage = 0; serverlistpage = 0;
M_SetupNextMenu(&MP_ConnectDef); if (ms_RoomId < 0)
M_RoomMenu(0); // Select a room instead of staring at an empty list
else
M_SetupNextMenu(&MP_ConnectDef);
itemOn = 0; itemOn = 0;
M_Refresh(0); M_Refresh(0);
} }
@ -7533,7 +7529,15 @@ static void M_ChooseRoom(INT32 choice)
} }
serverlistpage = 0; serverlistpage = 0;
M_SetupNextMenu(currentMenu->prevMenu); /*
We were on the Multiplayer menu? That means that we must have been trying to
view the server browser, but we hadn't selected a room yet. So we need to go
to the browser next, not back there.
*/
if (currentMenu->prevMenu == &MP_MainDef)
M_SetupNextMenu(&MP_ConnectDef);
else
M_SetupNextMenu(currentMenu->prevMenu);
if (currentMenu == &MP_ConnectDef) if (currentMenu == &MP_ConnectDef)
M_Refresh(0); M_Refresh(0);
} }

View file

@ -38,6 +38,9 @@ void M_Drawer(void);
// Called by D_SRB2Main, loads the config file. // Called by D_SRB2Main, loads the config file.
void M_Init(void); void M_Init(void);
// Called by D_SRB2Main also, sets up the playermenu and description tables.
void M_InitCharacterTables(void);
// Called by intro code to force menu up upon a keypress, // Called by intro code to force menu up upon a keypress,
// does nothing if menu is already up. // does nothing if menu is already up.
void M_StartControlPanel(void); void M_StartControlPanel(void);
@ -210,7 +213,7 @@ typedef struct
UINT8 netgame; UINT8 netgame;
} saveinfo_t; } saveinfo_t;
extern description_t description[32]; extern description_t description[MAXSKINS];
extern consvar_t cv_showfocuslost; extern consvar_t cv_showfocuslost;
extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort; extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort;

View file

@ -661,11 +661,19 @@ FUNCMATH static const char *int2str(INT32 n)
#ifndef NONET #ifndef NONET
static INT32 ConnectionFailed(void) static INT32 ConnectionFailed(void)
{ {
time(&MSLastPing);
con_state = MSCS_FAILED; con_state = MSCS_FAILED;
CONS_Alert(CONS_ERROR, M_GetText("Connection to Master Server failed\n")); CONS_Alert(CONS_ERROR, M_GetText("Connection to Master Server failed\n"));
CloseConnection(); CloseConnection();
return MS_CONNECT_ERROR; return MS_CONNECT_ERROR;
} }
static INT32 ConnectionFailedwerrno(int no)
{
CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error: %s\n"),
strerror(no));
return ConnectionFailed();
}
#endif #endif
/** Tries to register the local game server on the master server. /** Tries to register the local game server on the master server.
@ -682,44 +690,43 @@ static INT32 AddToMasterServer(boolean firstadd)
msg_server_t *info = (msg_server_t *)msg.buffer; msg_server_t *info = (msg_server_t *)msg.buffer;
INT32 room = -1; INT32 room = -1;
fd_set tset; fd_set tset;
time_t timestamp = time(NULL);
UINT32 signature, tmp; UINT32 signature, tmp;
const char *insname; const char *insname;
if (socket_fd == (SOCKET_TYPE)ERRSOCKET)/* Woah, our socket was closed! */
{
if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
return ConnectionFailedwerrno(errno);
}
M_Memcpy(&tset, &wset, sizeof (tset)); M_Memcpy(&tset, &wset, sizeof (tset));
res = select(255, NULL, &tset, NULL, &select_timeout); res = select(255, NULL, &tset, NULL, &select_timeout);
if (res != ERRSOCKET && !res) if (res == ERRSOCKET)
return ConnectionFailedwerrno(errno);
if (res == 0)/* nothing selected */
{ {
if (retry++ > 30) // an about 30 second timeout /*
Timeout next call because SendPingToMasterServer
(our calling function) already calls this once
every two minutes.
*/
if (retry++ == 1)
{ {
retry = 0; retry = 0;
CONS_Alert(CONS_ERROR, M_GetText("Master Server timed out\n")); CONS_Alert(CONS_ERROR, M_GetText("Master Server timed out\n"));
MSLastPing = timestamp;
return ConnectionFailed(); return ConnectionFailed();
} }
return MS_CONNECT_ERROR; return MS_CONNECT_ERROR;
} }
retry = 0; retry = 0;
if (res == ERRSOCKET)
{
if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
{
CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error #%u: %s\n"), errno, strerror(errno));
MSLastPing = timestamp;
return ConnectionFailed();
}
}
// so, the socket is writable, but what does that mean, that the connection is // so, the socket is writable, but what does that mean, that the connection is
// ok, or bad... let see that! // ok, or bad... let see that!
j = (socklen_t)sizeof (i); j = (socklen_t)sizeof (i);
getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, (char *)&i, &j); if (getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, (char *)&i, &j) == ERRSOCKET)
return ConnectionFailedwerrno(errno);
if (i) // it was bad if (i) // it was bad
{ return ConnectionFailedwerrno(i);
CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error #%u: %s\n"), errno, strerror(errno));
MSLastPing = timestamp;
return ConnectionFailed();
}
#ifdef PARANOIA #ifdef PARANOIA
if (ms_RoomId <= 0) if (ms_RoomId <= 0)
@ -752,15 +759,12 @@ static INT32 AddToMasterServer(boolean firstadd)
msg.length = (UINT32)sizeof (msg_server_t); msg.length = (UINT32)sizeof (msg_server_t);
msg.room = 0; msg.room = 0;
if (MS_Write(&msg) < 0) if (MS_Write(&msg) < 0)
{
MSLastPing = timestamp;
return ConnectionFailed(); return ConnectionFailed();
}
if(con_state != MSCS_REGISTERED) if(con_state != MSCS_REGISTERED)
CONS_Printf(M_GetText("Master Server update successful.\n")); CONS_Printf(M_GetText("Master Server update successful.\n"));
MSLastPing = timestamp; time(&MSLastPing);
con_state = MSCS_REGISTERED; con_state = MSCS_REGISTERED;
CloseConnection(); CloseConnection();
#endif #endif

View file

@ -1837,6 +1837,9 @@ void P_CheckTimeLimit(void)
} }
} }
if (playercount > MAXPLAYERS)
playercount = MAXPLAYERS;
//Sort 'em. //Sort 'em.
for (i = 1; i < playercount; i++) for (i = 1; i < playercount; i++)
{ {

View file

@ -193,6 +193,12 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
mapheaderinfo[num]->musname[6] = 0; mapheaderinfo[num]->musname[6] = 0;
DEH_WriteUndoline("MUSICTRACK", va("%d", mapheaderinfo[num]->mustrack), UNDO_NONE); DEH_WriteUndoline("MUSICTRACK", va("%d", mapheaderinfo[num]->mustrack), UNDO_NONE);
mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->mustrack = 0;
DEH_WriteUndoline("MUSICPOS", va("%d", mapheaderinfo[num]->muspos), UNDO_NONE);
mapheaderinfo[num]->muspos = 0;
DEH_WriteUndoline("MUSICINTERFADEOUT", va("%d", mapheaderinfo[num]->musinterfadeout), UNDO_NONE);
mapheaderinfo[num]->musinterfadeout = 0;
DEH_WriteUndoline("MUSICINTER", mapheaderinfo[num]->musintername, UNDO_NONE);
mapheaderinfo[num]->musintername[0] = '\0';
DEH_WriteUndoline("FORCECHARACTER", va("%d", mapheaderinfo[num]->forcecharacter), UNDO_NONE); DEH_WriteUndoline("FORCECHARACTER", va("%d", mapheaderinfo[num]->forcecharacter), UNDO_NONE);
mapheaderinfo[num]->forcecharacter[0] = '\0'; mapheaderinfo[num]->forcecharacter[0] = '\0';
DEH_WriteUndoline("WEATHER", va("%d", mapheaderinfo[num]->weather), UNDO_NONE); DEH_WriteUndoline("WEATHER", va("%d", mapheaderinfo[num]->weather), UNDO_NONE);
@ -1544,19 +1550,33 @@ static void P_LoadRawSideDefs2(void *data)
{ {
M_Memcpy(process,msd->bottomtexture,8); M_Memcpy(process,msd->bottomtexture,8);
process[8] = '\0'; process[8] = '\0';
sd->bottomtexture = get_number(process)-1; sd->bottomtexture = get_number(process);
} }
M_Memcpy(process,msd->toptexture,8);
process[8] = '\0';
sd->text = Z_Malloc(7, PU_LEVEL, NULL);
// If they type in O_ or D_ and their music name, just shrug, if (!(msd->midtexture[0] == '-' && msd->midtexture[1] == '\0') || msd->midtexture[1] != '\0')
// then copy the rest instead. {
if ((process[0] == 'O' || process[0] == 'D') && process[7]) M_Memcpy(process,msd->midtexture,8);
M_Memcpy(sd->text, process+2, 6); process[8] = '\0';
else // Assume it's a proper music name. sd->midtexture = get_number(process);
M_Memcpy(sd->text, process, 6); }
sd->text[6] = 0;
// always process if back sidedef, because we need that - symbol
sd->text = Z_Malloc(7, PU_LEVEL, NULL);
if (i == 1 || msd->toptexture[0] != '-' || msd->toptexture[1] != '\0')
{
M_Memcpy(process,msd->toptexture,8);
process[8] = '\0';
// If they type in O_ or D_ and their music name, just shrug,
// then copy the rest instead.
if ((process[0] == 'O' || process[0] == 'D') && process[7])
M_Memcpy(sd->text, process+2, 6);
else // Assume it's a proper music name.
M_Memcpy(sd->text, process, 6);
sd->text[6] = 0;
}
else
sd->text[0] = 0;
break; break;
} }

View file

@ -264,7 +264,7 @@ void P_SpawnSlope_Line(int linenum)
if(!line->frontsector || !line->backsector) if(!line->frontsector || !line->backsector)
{ {
CONS_Printf("P_SpawnSlope_Line used on a line without two sides.\n"); CONS_Debug(DBG_SETUP, "P_SpawnSlope_Line used on a line without two sides. (line number %i)\n", linenum);
return; return;
} }

View file

@ -2440,18 +2440,71 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
// console player only unless NOCLIMB is set // console player only unless NOCLIMB is set
if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player))) if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player)))
{ {
UINT16 tracknum = (UINT16)sides[line->sidenum[0]].bottomtexture; boolean musicsame = (!sides[line->sidenum[0]].text[0] || !strnicmp(sides[line->sidenum[0]].text, S_MusicName(), 7));
UINT16 tracknum = (UINT16)max(sides[line->sidenum[0]].bottomtexture, 0);
INT32 position = (INT32)max(sides[line->sidenum[0]].midtexture, 0);
UINT32 prefadems = (UINT32)max(sides[line->sidenum[0]].textureoffset >> FRACBITS, 0);
UINT32 postfadems = (UINT32)max(sides[line->sidenum[0]].rowoffset >> FRACBITS, 0);
UINT8 fadetarget = (UINT8)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].textureoffset >> FRACBITS : 0, 0);
INT16 fadesource = (INT16)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].rowoffset >> FRACBITS : -1, -1);
strncpy(mapmusname, sides[line->sidenum[0]].text, 7); // Seek offset from current song position
mapmusname[6] = 0; if (line->flags & ML_EFFECT1)
{
// adjust for loop point if subtracting
if (position < 0 && S_GetMusicLength() &&
S_GetMusicPosition() > S_GetMusicLoopPoint() &&
S_GetMusicPosition() + position < S_GetMusicLoopPoint())
position = max(S_GetMusicLength() - (S_GetMusicLoopPoint() - (S_GetMusicPosition() + position)), 0);
else
position = max(S_GetMusicPosition() + position, 0);
}
mapmusflags = tracknum & MUSIC_TRACKMASK; // Fade current music to target volume (if music won't be changed)
if (!(line->flags & ML_BLOCKMONSTERS)) if ((line->flags & ML_EFFECT2) && fadetarget && musicsame)
mapmusflags |= MUSIC_RELOADRESET; {
// 0 fadesource means fade from current volume.
// meaning that we can't specify volume 0 as the source volume -- this starts at 1.
if (!fadesource)
fadesource = -1;
S_ChangeMusic(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4)); if (!postfadems)
if (!(line->flags & ML_EFFECT3)) S_SetInternalMusicVolume(fadetarget);
S_ShowMusicCredit(); else
S_FadeMusicFromVolume(fadetarget, fadesource, postfadems);
if (!(line->flags & ML_EFFECT3))
S_ShowMusicCredit();
if (position)
S_SetMusicPosition(position);
}
// Change the music and apply position/fade operations
else
{
strncpy(mapmusname, sides[line->sidenum[0]].text, 7);
mapmusname[6] = 0;
mapmusflags = tracknum & MUSIC_TRACKMASK;
if (!(line->flags & ML_BLOCKMONSTERS))
mapmusflags |= MUSIC_RELOADRESET;
if (line->flags & ML_BOUNCY)
mapmusflags |= MUSIC_FORCERESET;
mapmusposition = position;
S_ChangeMusicEx(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4), position,
!(line->flags & ML_EFFECT2) ? prefadems : 0,
!(line->flags & ML_EFFECT2) ? postfadems : 0);
if ((line->flags & ML_EFFECT2) && fadetarget)
{
if (!postfadems)
S_SetInternalMusicVolume(fadetarget);
else
S_FadeMusicFromVolume(fadetarget, fadesource, postfadems);
}
}
// Except, you can use the ML_BLOCKMONSTERS flag to change this behavior. // Except, you can use the ML_BLOCKMONSTERS flag to change this behavior.
// if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn. // if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn.

View file

@ -1283,7 +1283,7 @@ void P_RestoreMusic(player_t *player)
if (G_RaceGametype() && player->laps >= (UINT8)(cv_numlaps.value - 1)) if (G_RaceGametype() && player->laps >= (UINT8)(cv_numlaps.value - 1))
S_SpeedMusic(1.2f); S_SpeedMusic(1.2f);
#endif #endif
S_ChangeMusic(mapmusname, mapmusflags, true); S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
} }
} }
} }
@ -8879,8 +8879,11 @@ void P_PlayerThink(player_t *player)
if (player->bot) if (player->bot)
{ {
if (player->playerstate == PST_LIVE && B_CheckRespawn(player)) if (player->playerstate == PST_LIVE || player->playerstate == PST_DEAD)
player->playerstate = PST_REBORN; {
if (B_CheckRespawn(player))
player->playerstate = PST_REBORN;
}
if (player->playerstate == PST_REBORN) if (player->playerstate == PST_REBORN)
return; return;
} }

View file

@ -1561,7 +1561,6 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_grgammared); CV_RegisterVar(&cv_grgammared);
CV_RegisterVar(&cv_grfovchange); CV_RegisterVar(&cv_grfovchange);
CV_RegisterVar(&cv_grfog); CV_RegisterVar(&cv_grfog);
CV_RegisterVar(&cv_voodoocompatibility);
CV_RegisterVar(&cv_grfogcolor); CV_RegisterVar(&cv_grfogcolor);
CV_RegisterVar(&cv_grsoftwarefog); CV_RegisterVar(&cv_grsoftwarefog);
#ifdef ALAM_LIGHTING #ifdef ALAM_LIGHTING
@ -1570,7 +1569,8 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_grcoronas); CV_RegisterVar(&cv_grcoronas);
CV_RegisterVar(&cv_grcoronasize); CV_RegisterVar(&cv_grcoronasize);
#endif #endif
CV_RegisterVar(&cv_grmd2); CV_RegisterVar(&cv_grmdls);
CV_RegisterVar(&cv_grspritebillboarding);
#endif #endif
#ifdef HWRENDER #ifdef HWRENDER

View file

@ -862,8 +862,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc_numlights) if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc_numlights)
{ {
lightlist_t *nextlight = &frontsector->lightlist[i+1]; lightlist_t *nextlight = &frontsector->lightlist[i+1];
if (nextlight->slope ? P_GetZAt(nextlight->slope, ds->leftpos.x, ds->leftpos.y) : nextlight->height > pfloorleft if ((nextlight->slope ? P_GetZAt(nextlight->slope, ds->leftpos.x, ds->leftpos.y) : nextlight->height) > pfloorleft
&& nextlight->slope ? P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y) : nextlight->height > pfloorright) && (nextlight->slope ? P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y) : nextlight->height) > pfloorright)
continue; continue;
} }

View file

@ -40,6 +40,8 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
//int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); //int vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
#endif #endif
CV_PossibleValue_t Forceskin_cons_t[MAXSKINS+2];
static void R_InitSkins(void); static void R_InitSkins(void);
#define MINZ (FRACUNIT*4) #define MINZ (FRACUNIT*4)
@ -1796,7 +1798,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel, UINT8 viewnumber)
} }
} }
// Someone seriously wants infinite draw distance for precipitation? // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS)) if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
{ {
for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
@ -1812,13 +1814,6 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel, UINT8 viewnumber)
R_ProjectPrecipitationSprite(precipthing); R_ProjectPrecipitationSprite(precipthing);
} }
} }
else
{
// Draw everything in sector, no checks
for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
if (!(precipthing->precipflags & PCF_INVISIBLE))
R_ProjectPrecipitationSprite(precipthing);
}
} }
// //
@ -2593,6 +2588,10 @@ void R_InitSkins(void)
skin->spritedef.spriteframes = sprites[SPR_PLAY].spriteframes; skin->spritedef.spriteframes = sprites[SPR_PLAY].spriteframes;
ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, 0); ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, 0);
// Set values for Sonic skin
Forceskin_cons_t[1].value = 0;
Forceskin_cons_t[1].strvalue = skin->name;
//MD2 for sonic doesn't want to load in Linux. //MD2 for sonic doesn't want to load in Linux.
#ifdef HWRENDER #ifdef HWRENDER
if (rendermode == render_opengl) if (rendermode == render_opengl)
@ -3043,6 +3042,10 @@ next_token:
skin_cons_t[numskins].strvalue = skin->name; skin_cons_t[numskins].strvalue = skin->name;
#endif #endif
// Update the forceskin possiblevalues
Forceskin_cons_t[numskins+1].value = numskins;
Forceskin_cons_t[numskins+1].strvalue = skins[numskins].name;
// add face graphics // add face graphics
ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numskins); ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numskins);

View file

@ -97,6 +97,7 @@ typedef struct
sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table
} skin_t; } skin_t;
extern CV_PossibleValue_t Forceskin_cons_t[];
// //
// for followers. // for followers.
// //

View file

@ -38,6 +38,10 @@ extern INT32 msg_id;
#include "p_local.h" // camera info #include "p_local.h" // camera info
#include "m_misc.h" // for tunes command #include "m_misc.h" // for tunes command
#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS)
#include "lua_hook.h" // MusicChange hook
#endif
#ifdef HW3SOUND #ifdef HW3SOUND
// 3D Sound Interface // 3D Sound Interface
#include "hardware/hw3sound.h" #include "hardware/hw3sound.h"
@ -1550,6 +1554,12 @@ static void *music_data;
static UINT16 music_flags; static UINT16 music_flags;
static boolean music_looping; static boolean music_looping;
static char queue_name[7];
static UINT16 queue_flags;
static boolean queue_looping;
static UINT32 queue_position;
static UINT32 queue_fadeinms;
/// ------------------------ /// ------------------------
/// Music Definitions /// Music Definitions
/// ------------------------ /// ------------------------
@ -1788,6 +1798,11 @@ musictype_t S_MusicType(void)
return I_SongType(); return I_SongType();
} }
const char *S_MusicName(void)
{
return music_name;
}
boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping) boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping)
{ {
if (!I_SongPlaying()) if (!I_SongPlaying())
@ -1818,6 +1833,35 @@ boolean S_SpeedMusic(float speed)
return I_SetSongSpeed(speed); return I_SetSongSpeed(speed);
} }
/// ------------------------
/// Music Seeking
/// ------------------------
UINT32 S_GetMusicLength(void)
{
return I_GetSongLength();
}
boolean S_SetMusicLoopPoint(UINT32 looppoint)
{
return I_SetSongLoopPoint(looppoint);
}
UINT32 S_GetMusicLoopPoint(void)
{
return I_GetSongLoopPoint();
}
boolean S_SetMusicPosition(UINT32 position)
{
return I_SetSongPosition(position);
}
UINT32 S_GetMusicPosition(void)
{
return I_GetSongPosition();
}
/// ------------------------ /// ------------------------
/// Music Playback /// Music Playback
/// ------------------------ /// ------------------------
@ -1894,12 +1938,13 @@ static void S_UnloadMusic(void)
music_looping = false; music_looping = false;
} }
static boolean S_PlayMusic(boolean looping) static boolean S_PlayMusic(boolean looping, UINT32 fadeinms)
{ {
if (S_MusicDisabled()) if (S_MusicDisabled())
return false; return false;
if (!I_PlaySong(looping)) if ((!fadeinms && !I_PlaySong(looping)) ||
(fadeinms && !I_FadeInPlaySong(fadeinms, looping)))
{ {
S_UnloadMusic(); S_UnloadMusic();
return false; return false;
@ -1913,8 +1958,30 @@ static boolean S_PlayMusic(boolean looping)
return true; return true;
} }
void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) static void S_QueueMusic(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 fadeinms)
{ {
strncpy(queue_name, mmusic, 7);
queue_flags = mflags;
queue_looping = looping;
queue_position = position;
queue_fadeinms = fadeinms;
}
static void S_ClearQueue(void)
{
queue_name[0] = queue_flags = queue_looping = queue_position = queue_fadeinms = 0;
}
static void S_ChangeMusicToQueue(void)
{
S_ChangeMusicEx(queue_name, queue_flags, queue_looping, queue_position, 0, queue_fadeinms);
S_ClearQueue();
}
void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms)
{
char newmusic[7];
#if defined (DC) || defined (_WIN32_WCE) || defined (PSP) || defined(GP2X) #if defined (DC) || defined (_WIN32_WCE) || defined (PSP) || defined(GP2X)
S_ClearSfx(); S_ClearSfx();
#endif #endif
@ -1923,33 +1990,66 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping)
|| titledemo) // SRB2Kart: Demos don't interrupt title screen music || titledemo) // SRB2Kart: Demos don't interrupt title screen music
return; return;
// No Music (empty string) strncpy(newmusic, mmusic, 7);
if (mmusic[0] == 0) #if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS)
{ if(LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms))
S_StopMusic(); return;
#endif
newmusic[6] = 0;
// No Music (empty string)
if (newmusic[0] == 0)
{
if (prefadems)
I_FadeSong(0, prefadems, &S_StopMusic);
else
S_StopMusic();
return; return;
} }
if (strnicmp(music_name, mmusic, 6)) if (prefadems && S_MusicPlaying()) // queue music change for after fade // allow even if the music is the same
{ {
S_StopMusic(); // shutdown old music CONS_Debug(DBG_DETAILED, "Now fading out song %s\n", music_name);
S_QueueMusic(newmusic, mflags, looping, position, fadeinms);
I_FadeSong(0, prefadems, S_ChangeMusicToQueue);
return;
}
else if (strnicmp(music_name, newmusic, 6) || (mflags & MUSIC_FORCERESET))
{
CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic);
if (!S_LoadMusic(mmusic)) S_StopMusic();
if (!S_LoadMusic(newmusic))
{ {
CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded!\n", mmusic); CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded!\n", newmusic);
return; return;
} }
music_flags = mflags; music_flags = mflags;
music_looping = looping; music_looping = looping;
if (!S_PlayMusic(looping)) if (!S_PlayMusic(looping, fadeinms))
{ {
CONS_Alert(CONS_ERROR, "Music %.6s could not be played!\n", mmusic); CONS_Alert(CONS_ERROR, "Music %.6s could not be played!\n", newmusic);
return; return;
} }
if (position)
I_SetSongPosition(position);
I_SetSongTrack(mflags & MUSIC_TRACKMASK);
}
else if (fadeinms) // let fades happen with same music
{
I_SetSongPosition(position);
I_FadeSong(100, fadeinms, NULL);
}
else // reset volume to 100 with same music
{
I_StopFadingSong();
I_FadeSong(100, 500, NULL);
} }
I_SetSongTrack(mflags & MUSIC_TRACKMASK);
} }
void S_StopMusic(void) void S_StopMusic(void)
@ -2055,6 +2155,32 @@ void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume)
} }
} }
/// ------------------------
/// Music Fading
/// ------------------------
void S_SetInternalMusicVolume(INT32 volume)
{
I_SetInternalMusicVolume(min(max(volume, 0), 100));
}
void S_StopFadingMusic(void)
{
I_StopFadingSong();
}
boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms)
{
if (source_volume < 0)
return I_FadeSong(target_volume, ms, NULL);
else
return I_FadeSongFromVolume(target_volume, source_volume, ms, NULL);
}
boolean S_FadeOutStopMusic(UINT32 ms)
{
return I_FadeSong(0, ms, &S_StopMusic);
}
/// ------------------------ /// ------------------------
/// Init & Others /// Init & Others
@ -2072,26 +2198,28 @@ void S_Start(void)
strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7);
mapmusname[6] = 0; mapmusname[6] = 0;
mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK);
mapmusposition = mapheaderinfo[gamemap-1]->muspos;
} }
//if (cv_resetmusic.value) // Starting ambience should always be restarted //if (cv_resetmusic.value) // Starting ambience should always be restarted
S_StopMusic(); S_StopMusic();
if (leveltime < (starttime + (TICRATE/2))) // SRB2Kart if (leveltime < (starttime + (TICRATE/2))) // SRB2Kart
S_ChangeMusic((encoremode ? "estart" : "kstart"), 0, false); S_ChangeMusicEx((encoremode ? "estart" : "kstart"), 0, false, mapmusposition, 0, 0);
else else
S_ChangeMusic(mapmusname, mapmusflags, true); S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
} }
static void Command_Tunes_f(void) static void Command_Tunes_f(void)
{ {
const char *tunearg; const char *tunearg;
UINT16 tunenum, track = 0; UINT16 tunenum, track = 0;
UINT32 position = 0;
const size_t argc = COM_Argc(); const size_t argc = COM_Argc();
if (argc < 2) //tunes slot ... if (argc < 2) //tunes slot ...
{ {
CONS_Printf("tunes <name/num> [track] [speed] / <-show> / <-default> / <-none>:\n"); CONS_Printf("tunes <name/num> [track] [speed] [position] / <-show> / <-default> / <-none>:\n");
CONS_Printf(M_GetText("Play an arbitrary music lump. If a map number is used, 'MAP##M' is played.\n")); CONS_Printf(M_GetText("Play an arbitrary music lump. If a map number is used, 'MAP##M' is played.\n"));
CONS_Printf(M_GetText("If the format supports multiple songs, you can specify which one to play.\n\n")); CONS_Printf(M_GetText("If the format supports multiple songs, you can specify which one to play.\n\n"));
CONS_Printf(M_GetText("* With \"-show\", shows the currently playing tune and track.\n")); CONS_Printf(M_GetText("* With \"-show\", shows the currently playing tune and track.\n"));
@ -2138,10 +2266,15 @@ static void Command_Tunes_f(void)
snprintf(mapmusname, 7, "%sM", G_BuildMapName(tunenum)); snprintf(mapmusname, 7, "%sM", G_BuildMapName(tunenum));
else else
strncpy(mapmusname, tunearg, 7); strncpy(mapmusname, tunearg, 7);
if (argc > 4)
position = (UINT32)atoi(COM_Argv(4));
mapmusname[6] = 0; mapmusname[6] = 0;
mapmusflags = (track & MUSIC_TRACKMASK); mapmusflags = (track & MUSIC_TRACKMASK);
mapmusposition = position;
S_ChangeMusic(mapmusname, mapmusflags, true); S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
if (argc > 3) if (argc > 3)
{ {
@ -2182,7 +2315,7 @@ static void Command_RestartAudio_f(void)
void GameSounds_OnChange(void) void GameSounds_OnChange(void)
{ {
if (M_CheckParm("-nosound")) if (M_CheckParm("-nosound") || M_CheckParm("-noaudio"))
return; return;
if (sound_disabled) if (sound_disabled)
@ -2196,7 +2329,7 @@ void GameSounds_OnChange(void)
void GameDigiMusic_OnChange(void) void GameDigiMusic_OnChange(void)
{ {
if (M_CheckParm("-nomusic")) if (M_CheckParm("-nomusic") || M_CheckParm("-noaudio"))
return; return;
else if (M_CheckParm("-nodigmusic")) else if (M_CheckParm("-nodigmusic"))
return; return;
@ -2239,7 +2372,7 @@ void GameDigiMusic_OnChange(void)
#ifndef NO_MIDI #ifndef NO_MIDI
void GameMIDIMusic_OnChange(void) void GameMIDIMusic_OnChange(void)
{ {
if (M_CheckParm("-nomusic")) if (M_CheckParm("-nomusic") || M_CheckParm("-noaudio"))
return; return;
else if (M_CheckParm("-nomidimusic")) else if (M_CheckParm("-nomidimusic"))
return; return;

View file

@ -117,14 +117,14 @@ boolean S_MusicDisabled(void);
boolean S_MusicPlaying(void); boolean S_MusicPlaying(void);
boolean S_MusicPaused(void); boolean S_MusicPaused(void);
musictype_t S_MusicType(void); musictype_t S_MusicType(void);
const char *S_MusicName(void);
boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping); boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping);
boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi); boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi);
#define S_DigExists(a) S_MusicExists(a, false, true) #define S_DigExists(a) S_MusicExists(a, false, true)
#define S_MIDIExists(a) S_MusicExists(a, true, false) #define S_MIDIExists(a) S_MusicExists(a, true, false)
// //
// Music Properties // Music Effects
// //
// Set Speed of Music // Set Speed of Music
@ -154,15 +154,35 @@ void S_InitMusicDefs(void);
void S_ShowMusicCredit(void); void S_ShowMusicCredit(void);
// //
// Music Routines // Music Seeking
//
// Get Length of Music
UINT32 S_GetMusicLength(void);
// Set LoopPoint of Music
boolean S_SetMusicLoopPoint(UINT32 looppoint);
// Get LoopPoint of Music
UINT32 S_GetMusicLoopPoint(void);
// Set Position of Music
boolean S_SetMusicPosition(UINT32 position);
// Get Position of Music
UINT32 S_GetMusicPosition(void);
//
// Music Playback
// //
// Start music track, arbitrary, given its name, and set whether looping // Start music track, arbitrary, given its name, and set whether looping
// note: music flags 12 bits for tracknum (gme, other formats with more than one track) // note: music flags 12 bits for tracknum (gme, other formats with more than one track)
// 13-15 aren't used yet // 13-15 aren't used yet
// and the last bit we ignore (internal game flag for resetting music on reload) // and the last bit we ignore (internal game flag for resetting music on reload)
#define S_ChangeMusicInternal(a,b) S_ChangeMusic(a,0,b) void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms);
void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping); #define S_ChangeMusicInternal(a,b) S_ChangeMusicEx(a,0,b,0,0,0)
#define S_ChangeMusic(a,b,c) S_ChangeMusicEx(a,b,c,0,0,0)
// Stops the music. // Stops the music.
void S_StopMusic(void); void S_StopMusic(void);
@ -175,6 +195,17 @@ void S_ResumeAudio(void);
void S_EnableSound(void); void S_EnableSound(void);
void S_DisableSound(void); void S_DisableSound(void);
//
// Music Fading
//
void S_SetInternalMusicVolume(INT32 volume);
void S_StopFadingMusic(void);
boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms);
#define S_FadeMusic(a, b) S_FadeMusicFromVolume(a, -1, b)
#define S_FadeInChangeMusic(a,b,c,d) S_ChangeMusicEx(a,b,c,0,0,d)
boolean S_FadeOutStopMusic(UINT32 ms);
// //
// Updates music & sounds // Updates music & sounds
// //

View file

@ -227,6 +227,10 @@
<ClInclude Include="..\hardware\hw_light.h" /> <ClInclude Include="..\hardware\hw_light.h" />
<ClInclude Include="..\hardware\hw_main.h" /> <ClInclude Include="..\hardware\hw_main.h" />
<ClInclude Include="..\hardware\hw_md2.h" /> <ClInclude Include="..\hardware\hw_md2.h" />
<ClInclude Include="..\hardware\hw_md2load.h" />
<ClInclude Include="..\hardware\hw_md3load.h" />
<ClInclude Include="..\hardware\hw_model.h" />
<ClInclude Include="..\hardware\u_list.h" />
<ClInclude Include="..\hu_stuff.h" /> <ClInclude Include="..\hu_stuff.h" />
<ClInclude Include="..\info.h" /> <ClInclude Include="..\info.h" />
<ClInclude Include="..\i_addrinfo.h" /> <ClInclude Include="..\i_addrinfo.h" />
@ -366,8 +370,12 @@
<ClCompile Include="..\hardware\hw_light.c" /> <ClCompile Include="..\hardware\hw_light.c" />
<ClCompile Include="..\hardware\hw_main.c" /> <ClCompile Include="..\hardware\hw_main.c" />
<ClCompile Include="..\hardware\hw_md2.c" /> <ClCompile Include="..\hardware\hw_md2.c" />
<ClCompile Include="..\hardware\hw_md2load.c" />
<ClCompile Include="..\hardware\hw_md3load.c" />
<ClCompile Include="..\hardware\hw_model.c" />
<ClCompile Include="..\hardware\hw_trick.c" /> <ClCompile Include="..\hardware\hw_trick.c" />
<ClCompile Include="..\hardware\r_opengl\r_opengl.c" /> <ClCompile Include="..\hardware\r_opengl\r_opengl.c" />
<ClCompile Include="..\hardware\u_list.c" />
<ClCompile Include="..\hu_stuff.c" /> <ClCompile Include="..\hu_stuff.c" />
<ClCompile Include="..\info.c" /> <ClCompile Include="..\info.c" />
<ClCompile Include="..\i_addrinfo.c"> <ClCompile Include="..\i_addrinfo.c">

View file

@ -246,6 +246,18 @@
<ClInclude Include="..\hardware\hw_md2.h"> <ClInclude Include="..\hardware\hw_md2.h">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\hardware\hw_md2load.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\hardware\hw_md3load.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\hardware\hw_model.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\hardware\u_list.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\byteptr.h"> <ClInclude Include="..\byteptr.h">
<Filter>I_Interface</Filter> <Filter>I_Interface</Filter>
</ClInclude> </ClInclude>
@ -627,9 +639,21 @@
<ClCompile Include="..\hardware\hw_md2.c"> <ClCompile Include="..\hardware\hw_md2.c">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\hardware\hw_md2load.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\hardware\hw_md3load.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\hardware\hw_model.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\hardware\hw_trick.c"> <ClCompile Include="..\hardware\hw_trick.c">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\hardware\u_list.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\filesrch.c"> <ClCompile Include="..\filesrch.c">
<Filter>I_Interface</Filter> <Filter>I_Interface</Filter>
</ClCompile> </ClCompile>

View file

@ -87,13 +87,11 @@ void *hwSym(const char *funcName,void *handle)
GETFUNC(ClearMipMapCache); GETFUNC(ClearMipMapCache);
GETFUNC(SetSpecialState); GETFUNC(SetSpecialState);
GETFUNC(GetTextureUsed); GETFUNC(GetTextureUsed);
GETFUNC(DrawMD2); GETFUNC(DrawModel);
GETFUNC(DrawMD2i); GETFUNC(CreateModelVBOs);
GETFUNC(SetTransform); GETFUNC(SetTransform);
GETFUNC(GetRenderVersion); GETFUNC(GetRenderVersion);
#ifdef SHUFFLE
GETFUNC(PostImgRedraw); GETFUNC(PostImgRedraw);
#endif //SHUFFLE
GETFUNC(FlushScreenTextures); GETFUNC(FlushScreenTextures);
GETFUNC(StartScreenWipe); GETFUNC(StartScreenWipe);
GETFUNC(EndScreenWipe); GETFUNC(EndScreenWipe);

View file

@ -359,6 +359,14 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
return 0; return 0;
} }
static void SDLdoGrabMouse(void)
{
SDL_ShowCursor(SDL_DISABLE);
SDL_SetWindowGrab(window, SDL_TRUE);
if (SDL_SetRelativeMouseMode(SDL_TRUE) == 0) // already warps mouse if successful
wrapmouseok = SDL_TRUE; // TODO: is wrapmouseok or HalfWarpMouse needed anymore?
}
static void SDLdoUngrabMouse(void) static void SDLdoUngrabMouse(void)
{ {
SDL_ShowCursor(SDL_ENABLE); SDL_ShowCursor(SDL_ENABLE);
@ -629,6 +637,9 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
//else firsttimeonmouse = SDL_FALSE; //else firsttimeonmouse = SDL_FALSE;
capslock = !!( SDL_GetModState() & KMOD_CAPS );// in case CL changes capslock = !!( SDL_GetModState() & KMOD_CAPS );// in case CL changes
if (USE_MOUSEINPUT)
SDLdoGrabMouse();
} }
else if (!mousefocus && !kbfocus) else if (!mousefocus && !kbfocus)
{ {
@ -708,9 +719,7 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt)
// -- Monster Iestyn // -- Monster Iestyn
if (SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window) if (SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window)
{ {
SDL_SetWindowGrab(window, SDL_TRUE); SDLdoGrabMouse();
if (SDL_SetRelativeMouseMode(SDL_TRUE) == 0) // already warps mouse if successful
wrapmouseok = SDL_TRUE; // TODO: is wrapmouseok or HalfWarpMouse needed anymore?
} }
} }
} }
@ -1277,7 +1286,7 @@ void I_StartupMouse(void)
else else
firsttimeonmouse = SDL_FALSE; firsttimeonmouse = SDL_FALSE;
if (cv_usemouse.value) if (cv_usemouse.value)
return; SDLdoGrabMouse();
else else
SDLdoUngrabMouse(); SDLdoUngrabMouse();
} }
@ -1845,13 +1854,11 @@ void I_StartupGraphics(void)
HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL);
HWD.pfnSetPalette = hwSym("SetPalette",NULL); HWD.pfnSetPalette = hwSym("SetPalette",NULL);
HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL);
HWD.pfnDrawMD2 = hwSym("DrawMD2",NULL); HWD.pfnDrawModel = hwSym("DrawModel",NULL);
HWD.pfnDrawMD2i = hwSym("DrawMD2i",NULL); HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL);
HWD.pfnSetTransform = hwSym("SetTransform",NULL); HWD.pfnSetTransform = hwSym("SetTransform",NULL);
HWD.pfnGetRenderVersion = hwSym("GetRenderVersion",NULL); HWD.pfnGetRenderVersion = hwSym("GetRenderVersion",NULL);
#ifdef SHUFFLE
HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL);
#endif
HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL);
HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL);
HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL); HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL);

View file

@ -75,15 +75,41 @@
UINT8 sound_started = false; UINT8 sound_started = false;
static Mix_Music *music; static Mix_Music *music;
static UINT8 music_volume, sfx_volume; static UINT8 music_volume, sfx_volume, internal_volume;
static float loop_point; static float loop_point;
static float song_length; // length in seconds
static boolean songpaused; static boolean songpaused;
static UINT32 music_bytes;
static boolean is_looping;
// fading
static boolean is_fading;
static UINT8 fading_source;
static UINT8 fading_target;
static UINT32 fading_timer;
static UINT32 fading_duration;
static INT32 fading_id;
static void (*fading_callback)(void);
#ifdef HAVE_LIBGME #ifdef HAVE_LIBGME
static Music_Emu *gme; static Music_Emu *gme;
static INT32 current_track; static INT32 current_track;
#endif #endif
static void var_cleanup(void)
{
loop_point = song_length =\
music_bytes = fading_source = fading_target =\
fading_timer = fading_duration = 0;
songpaused = is_looping =\
is_fading = false;
fading_callback = NULL;
internal_volume = 100;
}
/// ------------------------ /// ------------------------
/// Audio System /// Audio System
/// ------------------------ /// ------------------------
@ -111,6 +137,8 @@ void I_StartupSound(void)
return; return;
} }
var_cleanup();
music = NULL; music = NULL;
music_volume = sfx_volume = 0; music_volume = sfx_volume = 0;
@ -336,6 +364,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
len = (info->play_length * 441 / 10) << 2; len = (info->play_length * 441 / 10) << 2;
mem = malloc(len); mem = malloc(len);
gme_play(emu, len >> 1, mem); gme_play(emu, len >> 1, mem);
gme_free_info(info);
gme_delete(emu); gme_delete(emu);
return Mix_QuickLoad_RAW((Uint8 *)mem, len); return Mix_QuickLoad_RAW((Uint8 *)mem, len);
@ -408,6 +437,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
len = (info->play_length * 441 / 10) << 2; len = (info->play_length * 441 / 10) << 2;
mem = malloc(len); mem = malloc(len);
gme_play(emu, len >> 1, mem); gme_play(emu, len >> 1, mem);
gme_free_info(info);
gme_delete(emu); gme_delete(emu);
return Mix_QuickLoad_RAW((Uint8 *)mem, len); return Mix_QuickLoad_RAW((Uint8 *)mem, len);
@ -482,14 +512,102 @@ void I_SetSfxVolume(UINT8 volume)
sfx_volume = volume; sfx_volume = volume;
} }
/// ------------------------
/// Music Utilities
/// ------------------------
static UINT32 get_real_volume(UINT8 volume)
{
#ifdef _WIN32
if (I_SongType() == MU_MID)
// HACK: Until we stop using native MIDI,
// disable volume changes
return ((UINT32)31*128/31); // volume = 31
else
#endif
// convert volume to mixer's 128 scale
// then apply internal_volume as a percentage
return ((UINT32)volume*128/31) * (UINT32)internal_volume / 100;
}
static UINT32 get_adjusted_position(UINT32 position)
{
// all in milliseconds
UINT32 length = I_GetSongLength();
UINT32 looppoint = I_GetSongLoopPoint();
if (length)
return position >= length ? (position % (length-looppoint)) : position;
else
return position;
}
static void do_fading_callback(void)
{
if (fading_callback)
(*fading_callback)();
fading_callback = NULL;
}
/// ------------------------ /// ------------------------
/// Music Hooks /// Music Hooks
/// ------------------------ /// ------------------------
static void count_music_bytes(int chan, void *stream, int len, void *udata)
{
(void)chan;
(void)stream;
(void)udata;
if (!music || I_SongType() == MU_GME || I_SongType() == MU_MOD || I_SongType() == MU_MID)
return;
music_bytes += len;
}
static void music_loop(void) static void music_loop(void)
{ {
Mix_PlayMusic(music, 0); if (is_looping)
Mix_SetMusicPosition(loop_point); {
Mix_PlayMusic(music, 0);
Mix_SetMusicPosition(loop_point);
music_bytes = loop_point*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition)
}
else
I_StopSong();
}
static UINT32 music_fade(UINT32 interval, void *param)
{
(void)param;
if (!is_fading ||
internal_volume == fading_target ||
fading_duration == 0)
{
I_StopFadingSong();
do_fading_callback();
return 0;
}
else if (songpaused) // don't decrement timer
return interval;
else if ((fading_timer -= 10) <= 0)
{
internal_volume = fading_target;
Mix_VolumeMusic(get_real_volume(music_volume));
I_StopFadingSong();
do_fading_callback();
return 0;
}
else
{
UINT8 delta = abs(fading_target - fading_source);
fixed_t factor = FixedDiv(fading_duration - fading_timer, fading_duration);
if (fading_target < fading_source)
internal_volume = max(min(internal_volume, fading_source - FixedMul(delta, factor)), fading_target);
else if (fading_target > fading_source)
internal_volume = min(max(internal_volume, fading_source + FixedMul(delta, factor)), fading_target);
Mix_VolumeMusic(get_real_volume(music_volume));
return interval;
}
} }
#ifdef HAVE_LIBGME #ifdef HAVE_LIBGME
@ -509,7 +627,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
// apply volume to stream // apply volume to stream
for (i = 0, p = (short *)stream; i < len/2; i++, p++) for (i = 0, p = (short *)stream; i < len/2; i++, p++)
*p = ((INT32)*p) * music_volume*2 / 42; *p = ((INT32)*p) * (music_volume*internal_volume/100)*2 / 42;
} }
#endif #endif
@ -586,6 +704,194 @@ boolean I_SetSongSpeed(float speed)
return false; return false;
} }
/// ------------------------
/// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
INT32 length;
#ifdef HAVE_LIBGME
if (gme)
{
gme_info_t *info;
gme_err_t gme_e = gme_track_info(gme, &info, current_track);
if (gme_e != NULL)
{
CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e);
length = 0;
}
else
{
// reconstruct info->play_length, from GME source
// we only want intro + 1 loop, not 2
length = info->length;
if (length <= 0)
{
length = info->intro_length + info->loop_length; // intro + 1 loop
if (length <= 0)
length = 150 * 1000; // 2.5 minutes
}
}
gme_free_info(info);
return max(length, 0);
}
else
#endif
if (!music || I_SongType() == MU_MOD || I_SongType() == MU_MID)
return 0;
else
{
// VERY IMPORTANT to set your LENGTHMS= in your song files, folks!
// SDL mixer can't read music length itself.
length = (UINT32)(song_length*1000);
if (!length)
CONS_Debug(DBG_DETAILED, "Getting music length: music is missing LENGTHMS= tag. Needed for seeking.\n");
return length;
}
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
if (!music || I_SongType() == MU_GME || I_SongType() == MU_MOD || I_SongType() == MU_MID || !is_looping)
return false;
else
{
UINT32 length = I_GetSongLength();
if (length > 0)
looppoint %= length;
loop_point = max((float)(looppoint / 1000.0L), 0);
return true;
}
}
UINT32 I_GetSongLoopPoint(void)
{
#ifdef HAVE_LIBGME
if (gme)
{
INT32 looppoint;
gme_info_t *info;
gme_err_t gme_e = gme_track_info(gme, &info, current_track);
if (gme_e != NULL)
{
CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e);
looppoint = 0;
}
else
looppoint = info->intro_length > 0 ? info->intro_length : 0;
gme_free_info(info);
return max(looppoint, 0);
}
else
#endif
if (!music || I_SongType() == MU_MOD || I_SongType() == MU_MID)
return 0;
else
return (UINT32)(loop_point * 1000);
}
boolean I_SetSongPosition(UINT32 position)
{
UINT32 length;
#ifdef HAVE_LIBGME
if (gme)
{
// this is unstable, so fail silently
return true;
// this isn't required technically, but GME thread-locks for a second
// if you seek too high from the counter
// length = I_GetSongLength();
// if (length)
// position = get_adjusted_position(position);
// SDL_LockAudio();
// gme_err_t gme_e = gme_seek(gme, position);
// SDL_UnlockAudio();
// if (gme_e != NULL)
// {
// CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e);
// return false;
// }
// else
// return true;
}
else
#endif
if (!music || I_SongType() == MU_MID)
return false;
else if (I_SongType() == MU_MOD)
return Mix_SetMusicPosition(position); // Goes by channels
else
{
// Because SDL mixer can't identify song length, if you have
// a position input greater than the real length, then
// music_bytes becomes inaccurate.
length = I_GetSongLength(); // get it in MS
if (length)
position = get_adjusted_position(position);
Mix_RewindMusic(); // needed for mp3
if(Mix_SetMusicPosition((float)(position/1000.0L)) == 0)
music_bytes = position/1000.0L*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition)
else
// NOTE: This block fires on incorrect song format,
// NOT if position input is greater than song length.
music_bytes = 0;
return true;
}
}
UINT32 I_GetSongPosition(void)
{
#ifdef HAVE_LIBGME
if (gme)
{
INT32 position = gme_tell(gme);
gme_info_t *info;
gme_err_t gme_e = gme_track_info(gme, &info, current_track);
if (gme_e != NULL)
{
CONS_Alert(CONS_ERROR, "GME error: %s\n", gme_e);
return position;
}
else
{
// adjust position, since GME's counter keeps going past loop
if (info->length > 0)
position %= info->length;
else if (info->intro_length + info->loop_length > 0)
position = position >= (info->intro_length + info->loop_length) ? (position % info->loop_length) : position;
else
position %= 150 * 1000; // 2.5 minutes
}
gme_free_info(info);
return max(position, 0);
}
else
#endif
if (!music || I_SongType() == MU_MID)
return 0;
else
return music_bytes/44100.0L*1000.0L/4; //assume 44.1khz
// 4 = byte length for 16-bit samples (AUDIO_S16SYS), stereo (2-channel)
// This is hardcoded in I_StartupSound. Other formats for factor:
// 8M: 1 | 8S: 2 | 16M: 2 | 16S: 4
}
/// ------------------------ /// ------------------------
/// Music Playback /// Music Playback
/// ------------------------ /// ------------------------
@ -598,6 +904,7 @@ boolean I_LoadSong(char *data, size_t len)
const size_t key1len = strlen(key1); const size_t key1len = strlen(key1);
const size_t key2len = strlen(key2); const size_t key2len = strlen(key2);
const size_t key3len = strlen(key3); const size_t key3len = strlen(key3);
char *p = data; char *p = data;
SDL_RWops *rw; SDL_RWops *rw;
@ -608,6 +915,9 @@ boolean I_LoadSong(char *data, size_t len)
) )
I_UnloadSong(); I_UnloadSong();
// always do this whether or not a music already exists
var_cleanup();
#ifdef HAVE_LIBGME #ifdef HAVE_LIBGME
if ((UINT8)data[0] == 0x1F if ((UINT8)data[0] == 0x1F
&& (UINT8)data[1] == 0x8B) && (UINT8)data[1] == 0x8B)
@ -717,30 +1027,35 @@ boolean I_LoadSong(char *data, size_t len)
// Find the OGG loop point. // Find the OGG loop point.
loop_point = 0.0f; loop_point = 0.0f;
song_length = 0.0f;
while ((UINT32)(p - data) < len) while ((UINT32)(p - data) < len)
{ {
if (strncmp(p++, key1, key1len)) if (fpclassify(loop_point) == FP_ZERO && !strncmp(p, key1, key1len))
continue;
p += key1len-1; // skip OOP (the L was skipped in strncmp)
if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=?
{ {
p += key2len; // skip POINT= p += key1len; // skip LOOP
loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count. if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=?
// because SDL_Mixer is USELESS and can't even tell us {
// something simple like the frequency of the streaming music, p += key2len; // skip POINT=
// we are unfortunately forced to assume that ALL MUSIC is 44100hz. loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count.
// This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly. // because SDL_Mixer is USELESS and can't even tell us
// something simple like the frequency of the streaming music,
// we are unfortunately forced to assume that ALL MUSIC is 44100hz.
// This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly.
}
else if (!strncmp(p, key3, key3len)) // is it LOOPMS=?
{
p += key3len; // skip MS=
loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds.
// Everything that uses LOOPMS will work perfectly with SDL_Mixer.
}
} }
else if (!strncmp(p, key3, key3len)) // is it LOOPMS=?
{
p += key3len; // skip MS=
loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds.
// Everything that uses LOOPMS will work perfectly with SDL_Mixer.
}
// Neither?! Continue searching.
}
if (fpclassify(loop_point) != FP_ZERO) // Got what we needed
break;
else // continue searching
p++;
}
return true; return true;
} }
@ -764,7 +1079,6 @@ void I_UnloadSong(void)
boolean I_PlaySong(boolean looping) boolean I_PlaySong(boolean looping)
{ {
boolean lpz = fpclassify(loop_point) == FP_ZERO;
#ifdef HAVE_LIBGME #ifdef HAVE_LIBGME
if (gme) if (gme)
{ {
@ -778,21 +1092,37 @@ boolean I_PlaySong(boolean looping)
if (!music) if (!music)
return false; return false;
if (fpclassify(song_length) == FP_ZERO && (I_SongType() == MU_OGG || I_SongType() == MU_MP3 || I_SongType() == MU_FLAC))
CONS_Debug(DBG_DETAILED, "This song is missing a LENGTHMS= tag! Required to make seeking work properly.\n");
if (Mix_PlayMusic(music, looping && lpz ? -1 : 0) == -1) if (I_SongType() != MU_MOD && I_SongType() != MU_MID && Mix_PlayMusic(music, 0) == -1)
{
CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError());
return false;
}
else if ((I_SongType() == MU_MOD || I_SongType() == MU_MID) && Mix_PlayMusic(music, looping ? -1 : 0) == -1) // if MOD, loop forever
{ {
CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError()); CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError());
return false; return false;
} }
Mix_VolumeMusic((UINT32)music_volume*128/31);
if (!lpz) is_looping = looping;
Mix_HookMusicFinished(music_loop);
I_SetMusicVolume(music_volume);
if (I_SongType() != MU_MOD && I_SongType() != MU_MID)
Mix_HookMusicFinished(music_loop); // don't bother counting if MOD
if(I_SongType() != MU_MOD && I_SongType() != MU_MID && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL))
CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError());
return true; return true;
} }
void I_StopSong(void) void I_StopSong(void)
{ {
I_StopFadingSong();
#ifdef HAVE_LIBGME #ifdef HAVE_LIBGME
if (gme) if (gme)
{ {
@ -802,19 +1132,40 @@ void I_StopSong(void)
#endif #endif
if (music) if (music)
{ {
Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes);
Mix_HookMusicFinished(NULL); Mix_HookMusicFinished(NULL);
Mix_HaltMusic(); Mix_HaltMusic();
} }
var_cleanup();
} }
void I_PauseSong(void) void I_PauseSong(void)
{ {
if(I_SongType() == MU_MID) // really, SDL Mixer? why can't you pause MIDI???
return;
if(I_SongType() != MU_GME && I_SongType() != MU_MOD && I_SongType() != MU_MID)
Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes);
Mix_PauseMusic(); Mix_PauseMusic();
songpaused = true; songpaused = true;
} }
void I_ResumeSong(void) void I_ResumeSong(void)
{ {
if (I_SongType() == MU_MID)
return;
if (I_SongType() != MU_GME && I_SongType() != MU_MOD && I_SongType() != MU_MID)
{
while(Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes) != 0) { }
// HACK: fixes issue of multiple effect callbacks being registered
if(music && I_SongType() != MU_MOD && I_SongType() != MU_MID && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL))
CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError());
}
Mix_ResumeMusic(); Mix_ResumeMusic();
songpaused = false; songpaused = false;
} }
@ -833,7 +1184,7 @@ void I_SetMusicVolume(UINT8 volume)
#endif #endif
music_volume = volume; music_volume = volume;
Mix_VolumeMusic((UINT32)music_volume*128/31); Mix_VolumeMusic(get_real_volume(music_volume));
} }
boolean I_SetSongTrack(int track) boolean I_SetSongTrack(int track)
@ -862,9 +1213,100 @@ boolean I_SetSongTrack(int track)
SDL_UnlockAudio(); SDL_UnlockAudio();
return false; return false;
} }
else
#endif #endif
if (I_SongType() == MU_MOD)
return !Mix_SetMusicPosition(track);
(void)track; (void)track;
return false; return false;
} }
/// ------------------------
/// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
internal_volume = volume;
if (!I_SongPlaying())
return;
Mix_VolumeMusic(get_real_volume(music_volume));
}
void I_StopFadingSong(void)
{
if (fading_id)
SDL_RemoveTimer(fading_id);
is_fading = false;
fading_source = fading_target = fading_timer = fading_duration = fading_id = 0;
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void))
{
INT16 volume_delta;
source_volume = min(source_volume, 100);
volume_delta = (INT16)(target_volume - source_volume);
I_StopFadingSong();
if (!ms && volume_delta)
{
I_SetInternalMusicVolume(target_volume);
if (callback)
(*callback)();
return true;
}
else if (!volume_delta)
{
if (callback)
(*callback)();
return true;
}
// Round MS to nearest 10
// If n - lower > higher - n, then round up
ms = (ms - ((ms / 10) * 10) > (((ms / 10) * 10) + 10) - ms) ?
(((ms / 10) * 10) + 10) // higher
: ((ms / 10) * 10); // lower
if (!ms)
I_SetInternalMusicVolume(target_volume);
else if (source_volume != target_volume)
{
fading_id = SDL_AddTimer(10, music_fade, NULL);
if (fading_id)
{
is_fading = true;
fading_timer = fading_duration = ms;
fading_source = source_volume;
fading_target = target_volume;
fading_callback = callback;
if (internal_volume != source_volume)
I_SetInternalMusicVolume(source_volume);
}
}
return is_fading;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void))
{
return I_FadeSongFromVolume(target_volume, internal_volume, ms, callback);
}
boolean I_FadeOutStopSong(UINT32 ms)
{
return I_FadeSongFromVolume(0, internal_volume, ms, &I_StopSong);
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
if (I_PlaySong(looping))
return I_FadeSongFromVolume(100, 0, ms, NULL);
else
return false;
}
#endif #endif

View file

@ -1375,6 +1375,37 @@ boolean I_SetSongSpeed(float speed)
return false; return false;
} }
/// ------------------------
// MUSIC SEEKING
/// ------------------------
UINT32 I_GetSongLength(void)
{
return 0;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
(void)position;
return false;
}
UINT32 I_GetSongPosition(void)
{
return 0;
}
/// ------------------------ /// ------------------------
// MUSIC PLAYBACK // MUSIC PLAYBACK
/// ------------------------ /// ------------------------
@ -1443,6 +1474,47 @@ boolean I_SetSongTrack(int track)
return false; return false;
} }
/// ------------------------
/// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void))
{
(void)target_volume;
(void)source_volume;
(void)ms;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void))
{
(void)target_volume;
(void)ms;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}
/// ------------------------ /// ------------------------
// MUSIC LOADING AND CLEANUP // MUSIC LOADING AND CLEANUP
// \todo Split logic between loading and playing, // \todo Split logic between loading and playing,

View file

@ -755,6 +755,36 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<ClCompile Include="..\hardware\hw_md2load.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\hardware\hw_md3load.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\hardware\hw_model.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\hardware\hw_trick.c"> <ClCompile Include="..\hardware\hw_trick.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -765,6 +795,16 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<ClCompile Include="..\hardware\u_list.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\i_tcp.c"> <ClCompile Include="..\i_tcp.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -1340,7 +1380,11 @@
<ClInclude Include="..\hardware\hw_light.h" /> <ClInclude Include="..\hardware\hw_light.h" />
<ClInclude Include="..\hardware\hw_main.h" /> <ClInclude Include="..\hardware\hw_main.h" />
<ClInclude Include="..\hardware\hw_md2.h" /> <ClInclude Include="..\hardware\hw_md2.h" />
<ClInclude Include="..\hardware\hw_md2load.h" />
<ClInclude Include="..\hardware\hw_md3load.h" />
<ClInclude Include="..\hardware\hw_model.h" />
<ClInclude Include="..\hardware\hws_data.h" /> <ClInclude Include="..\hardware\hws_data.h" />
<ClInclude Include="..\hardware\u_list.h" />
<ClInclude Include="..\byteptr.h" /> <ClInclude Include="..\byteptr.h" />
<ClInclude Include="..\i_joy.h" /> <ClInclude Include="..\i_joy.h" />
<ClInclude Include="..\i_net.h" /> <ClInclude Include="..\i_net.h" />

View file

@ -60,7 +60,6 @@ static void CV_Gammaxxx_ONChange(void);
static CV_PossibleValue_t grgamma_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}}; static CV_PossibleValue_t grgamma_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}};
static CV_PossibleValue_t grsoftwarefog_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "LightPlanes"}, {0, NULL}}; static CV_PossibleValue_t grsoftwarefog_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "LightPlanes"}, {0, NULL}};
consvar_t cv_voodoocompatibility = {"gr_voodoocompatibility", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfog = {"gr_fog", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grfog = {"gr_fog", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grfogcolor = {"gr_fogcolor", "AAAAAA", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grfogcolor = {"gr_fogcolor", "AAAAAA", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -80,7 +79,8 @@ consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE| CV_FLOAT, 0, NULL, 0
//static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NULL}}; //static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NULL}};
// console variables in development // console variables in development
consvar_t cv_grmd2 = {"gr_md2", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grmdls = {"gr_mdls", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif #endif
const UINT8 gammatable[5][256] = const UINT8 gammatable[5][256] =

View file

@ -24,8 +24,10 @@ ifndef NOASM
USEASM=1 USEASM=1
endif endif
ifndef NONET
ifndef MINGW64 #miniupnc is broken with MINGW64 ifndef MINGW64 #miniupnc is broken with MINGW64
HAVE_MINIUPNPC=1 HAVE_MINIUPNPC=1
endif
endif endif
OPTS=-DSTDC_HEADERS OPTS=-DSTDC_HEADERS

View file

@ -230,7 +230,11 @@
<ClCompile Include="..\hardware\hw_light.c" /> <ClCompile Include="..\hardware\hw_light.c" />
<ClCompile Include="..\hardware\hw_main.c" /> <ClCompile Include="..\hardware\hw_main.c" />
<ClCompile Include="..\hardware\hw_md2.c" /> <ClCompile Include="..\hardware\hw_md2.c" />
<ClCompile Include="..\hardware\hw_md2load.c" />
<ClCompile Include="..\hardware\hw_md3load.c" />
<ClCompile Include="..\hardware\hw_model.c" />
<ClCompile Include="..\hardware\hw_trick.c" /> <ClCompile Include="..\hardware\hw_trick.c" />
<ClCompile Include="..\hardware\u_list.c" />
<ClCompile Include="..\hu_stuff.c" /> <ClCompile Include="..\hu_stuff.c" />
<ClCompile Include="..\info.c" /> <ClCompile Include="..\info.c" />
<ClCompile Include="..\i_addrinfo.c"> <ClCompile Include="..\i_addrinfo.c">
@ -394,6 +398,10 @@
<ClInclude Include="..\hardware\hw_light.h" /> <ClInclude Include="..\hardware\hw_light.h" />
<ClInclude Include="..\hardware\hw_main.h" /> <ClInclude Include="..\hardware\hw_main.h" />
<ClInclude Include="..\hardware\hw_md2.h" /> <ClInclude Include="..\hardware\hw_md2.h" />
<ClInclude Include="..\hardware\hw_md2load.h" />
<ClInclude Include="..\hardware\hw_md3load.h" />
<ClInclude Include="..\hardware\hw_model.h" />
<ClInclude Include="..\hardware\u_list.h" />
<ClInclude Include="..\hu_stuff.h" /> <ClInclude Include="..\hu_stuff.h" />
<ClInclude Include="..\info.h" /> <ClInclude Include="..\info.h" />
<ClInclude Include="..\i_addrinfo.h" /> <ClInclude Include="..\i_addrinfo.h" />

View file

@ -453,6 +453,10 @@
<ClCompile Include="..\string.c"> <ClCompile Include="..\string.c">
<Filter>M_Misc</Filter> <Filter>M_Misc</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\hardware\hw_md2load.c" />
<ClCompile Include="..\hardware\hw_md3load.c" />
<ClCompile Include="..\hardware\hw_model.c" />
<ClCompile Include="..\hardware\u_list.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="afxres.h"> <ClInclude Include="afxres.h">
@ -506,6 +510,15 @@
<ClInclude Include="..\hardware\hw_md2.h"> <ClInclude Include="..\hardware\hw_md2.h">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\hardware\hw_md2load.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\hardware\hw_md3load.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\hardware\hw_model.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\hardware\hw3dsdrv.h"> <ClInclude Include="..\hardware\hw3dsdrv.h">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClInclude> </ClInclude>
@ -515,6 +528,9 @@
<ClInclude Include="..\hardware\hws_data.h"> <ClInclude Include="..\hardware\hws_data.h">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\hardware\u_list.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\blua\lapi.h"> <ClInclude Include="..\blua\lapi.h">
<Filter>BLUA</Filter> <Filter>BLUA</Filter>
</ClInclude> </ClInclude>

View file

@ -109,8 +109,7 @@ static loadfunc_t hwdFuncTable[] = {
{"GClipRect@20", &hwdriver.pfnGClipRect}, {"GClipRect@20", &hwdriver.pfnGClipRect},
{"ClearMipMapCache@0", &hwdriver.pfnClearMipMapCache}, {"ClearMipMapCache@0", &hwdriver.pfnClearMipMapCache},
{"SetSpecialState@8", &hwdriver.pfnSetSpecialState}, {"SetSpecialState@8", &hwdriver.pfnSetSpecialState},
{"DrawMD2@16", &hwdriver.pfnDrawMD2}, {"DrawModel@16", &hwdriver.pfnDrawModel},
{"DrawMD2i@36", &hwdriver.pfnDrawMD2i},
{"SetTransform@4", &hwdriver.pfnSetTransform}, {"SetTransform@4", &hwdriver.pfnSetTransform},
{"GetTextureUsed@0", &hwdriver.pfnGetTextureUsed}, {"GetTextureUsed@0", &hwdriver.pfnGetTextureUsed},
{"GetRenderVersion@0", &hwdriver.pfnGetRenderVersion}, {"GetRenderVersion@0", &hwdriver.pfnGetRenderVersion},
@ -140,8 +139,7 @@ static loadfunc_t hwdFuncTable[] = {
{"GClipRect", &hwdriver.pfnGClipRect}, {"GClipRect", &hwdriver.pfnGClipRect},
{"ClearMipMapCache", &hwdriver.pfnClearMipMapCache}, {"ClearMipMapCache", &hwdriver.pfnClearMipMapCache},
{"SetSpecialState", &hwdriver.pfnSetSpecialState}, {"SetSpecialState", &hwdriver.pfnSetSpecialState},
{"DrawMD2", &hwdriver.pfnDrawMD2}, {"DrawModel", &hwdriver.pfnDrawModel},
{"DrawMD2i", &hwdriver.pfnDrawMD2i},
{"SetTransform", &hwdriver.pfnSetTransform}, {"SetTransform", &hwdriver.pfnSetTransform},
{"GetTextureUsed", &hwdriver.pfnGetTextureUsed}, {"GetTextureUsed", &hwdriver.pfnGetTextureUsed},
{"GetRenderVersion", &hwdriver.pfnGetRenderVersion}, {"GetRenderVersion", &hwdriver.pfnGetRenderVersion},

View file

@ -815,6 +815,60 @@ void I_SetMusicVolume(UINT8 volume)
FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0));
} }
UINT32 I_GetSongLength(void)
{
UINT32 length;
if (I_SongType() == MU_MID)
return 0;
FMR_MUSIC(FMOD_Sound_GetLength(music_stream, &length, FMOD_TIMEUNIT_MS));
return length;
}
boolean I_SetSongLoopPoint(UINT32 looppoint)
{
(void)looppoint;
return false;
}
UINT32 I_GetSongLoopPoint(void)
{
return 0;
}
boolean I_SetSongPosition(UINT32 position)
{
FMOD_RESULT e;
if(I_SongType() == MU_MID)
// Dummy out; this works for some MIDI, but not others.
// SDL does not support this for any MIDI.
return false;
e = FMOD_Channel_SetPosition(music_channel, position, FMOD_TIMEUNIT_MS);
if (e == FMOD_OK)
return true;
else if (e == FMOD_ERR_UNSUPPORTED // Only music modules, numbnuts!
|| e == FMOD_ERR_INVALID_POSITION) // Out-of-bounds!
return false;
else // Congrats, you horribly broke it somehow
{
FMR_MUSIC(e);
return false;
}
}
UINT32 I_GetSongPosition(void)
{
FMOD_RESULT e;
unsigned int fmposition = 0;
if(I_SongType() == MU_MID)
// Dummy out because unsupported, even though FMOD does this correctly.
return 0;
e = FMOD_Channel_GetPosition(music_channel, &fmposition, FMOD_TIMEUNIT_MS);
if (e == FMOD_OK)
return (UINT32)fmposition;
else
return 0;
}
boolean I_SetSongTrack(INT32 track) boolean I_SetSongTrack(INT32 track)
{ {
if (track != current_track) // If the track's already playing, then why bother? if (track != current_track) // If the track's already playing, then why bother?
@ -859,3 +913,46 @@ boolean I_SetSongTrack(INT32 track)
} }
return false; return false;
} }
/// ------------------------
/// MUSIC FADING
/// ------------------------
void I_SetInternalMusicVolume(UINT8 volume)
{
(void)volume;
}
void I_StopFadingSong(void)
{
}
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void))
{
(void)target_volume;
(void)source_volume;
(void)ms;
(void)callback;
return false;
}
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void))
{
(void)target_volume;
(void)ms;
(void)callback;
return false;
}
boolean I_FadeOutStopSong(UINT32 ms)
{
(void)ms;
return false;
}
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
(void)ms;
(void)looping;
return false;
}

View file

@ -40,6 +40,7 @@
#include "g_input.h" // PLAYER1INPUTDOWN #include "g_input.h" // PLAYER1INPUTDOWN
#include "k_kart.h" // colortranslations #include "k_kart.h" // colortranslations
#include "console.h" // cons_menuhighlight #include "console.h" // cons_menuhighlight
#include "lua_hook.h" // IntermissionThinker hook
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_main.h" #include "hardware/hw_main.h"
@ -574,6 +575,10 @@ void Y_Ticker(void)
if (paused || P_AutoPause()) if (paused || P_AutoPause())
return; return;
#ifdef HAVE_BLUA
LUAh_IntermissionThinker();
#endif
intertic++; intertic++;
// Team scramble code for team match and CTF. // Team scramble code for team match and CTF.
@ -1505,11 +1510,11 @@ void Y_EndVote(void)
// //
static void Y_UnloadVoteData(void) static void Y_UnloadVoteData(void)
{ {
voteclient.loaded = false;
if (rendermode != render_soft) if (rendermode != render_soft)
return; return;
voteclient.loaded = false;
UNLOAD(widebgpatch); UNLOAD(widebgpatch);
UNLOAD(bgpatch); UNLOAD(bgpatch);
UNLOAD(cursor); UNLOAD(cursor);