mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-25 22:10:59 +00:00
Rebase soft render from https://icculus.org/quake2/
* deleted asm code * added support 2k+ resolutions * SDL2 support
This commit is contained in:
parent
430e21eab0
commit
c43e944a3d
32 changed files with 14911 additions and 42 deletions
138
Makefile
138
Makefile
|
@ -27,6 +27,9 @@
|
|||
# User configurable options
|
||||
# -------------------------
|
||||
|
||||
# Build soft render
|
||||
WITH_REFSOFT:=no
|
||||
|
||||
# Enables CD audio playback. CD audio playback is used
|
||||
# for the background music and doesn't add any further
|
||||
# dependencies. It should work on all platforms where
|
||||
|
@ -326,12 +329,12 @@ endif
|
|||
# ----------
|
||||
|
||||
# Phony targets
|
||||
.PHONY : all client game icon server ref_gl1 ref_gl3
|
||||
.PHONY : all client game icon server ref_gl1 ref_gl3 ref_soft
|
||||
|
||||
# ----------
|
||||
|
||||
# Builds everything
|
||||
all: config client server game ref_gl1 ref_gl3
|
||||
all: config client server game ref_gl1 ref_gl3 ref_soft
|
||||
|
||||
# ----------
|
||||
|
||||
|
@ -346,6 +349,7 @@ config:
|
|||
@echo "WITH_ZIP = $(WITH_ZIP)"
|
||||
@echo "WITH_SYSTEMWIDE = $(WITH_SYSTEMWIDE)"
|
||||
@echo "WITH_SYSTEMDIR = $(WITH_SYSTEMDIR)"
|
||||
@echo "WITH_REFSOFT = $(WITH_REFSOFT)"
|
||||
@echo "============================"
|
||||
@echo ""
|
||||
ifeq ($(WITH_SDL2),yes)
|
||||
|
@ -354,7 +358,7 @@ ifeq ($(CDA_DISABLED),yes)
|
|||
@echo ""
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# ----------
|
||||
|
||||
# Special target to compile
|
||||
|
@ -409,6 +413,10 @@ release/quake2.exe : CFLAGS += -DZIP -DNOUNCRYPT
|
|||
release/quake2.exe : LDFLAGS += -lz
|
||||
endif
|
||||
|
||||
ifeq ($(WITH_REFSOFT),yes)
|
||||
release/quake2.exe : CFLAGS += -DREFSOFT
|
||||
endif
|
||||
|
||||
ifeq ($(WITH_SDL2),yes)
|
||||
release/quake2.exe : CFLAGS += -DSDL2
|
||||
endif
|
||||
|
@ -474,6 +482,10 @@ ifeq ($(WITH_X11GAMMA),yes)
|
|||
release/quake2 : CFLAGS += -DX11GAMMA
|
||||
endif
|
||||
|
||||
ifeq ($(WITH_REFSOFT),yes)
|
||||
release/quake2 : CFLAGS += -DREFSOFT
|
||||
endif
|
||||
|
||||
ifeq ($(WITH_SDL2),yes)
|
||||
release/quake2 : CFLAGS += -DSDL2
|
||||
endif
|
||||
|
@ -651,6 +663,70 @@ build/ref_gl3/%.o: %.c
|
|||
|
||||
# ----------
|
||||
|
||||
# The soft renderer lib
|
||||
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
|
||||
ifeq ($(WITH_REFSOFT),yes)
|
||||
ref_soft:
|
||||
@echo "===> Building ref_soft.dll"
|
||||
$(MAKE) release/ref_soft.dll
|
||||
else
|
||||
ref_soft:
|
||||
@echo "===> No soft render"
|
||||
endif
|
||||
|
||||
ifeq ($(WITH_SDL2),yes)
|
||||
release/ref_soft.dll : CFLAGS += -DSDL2
|
||||
endif
|
||||
|
||||
release/ref_soft.dll : LDFLAGS += -shared
|
||||
|
||||
else ifeq ($(YQ2_OSTYPE), Darwin)
|
||||
|
||||
ifeq ($(WITH_REFSOFT),yes)
|
||||
ref_soft:
|
||||
@echo "===> Building ref_soft.dylib"
|
||||
$(MAKE) release/ref_soft.dylib
|
||||
else
|
||||
ref_soft:
|
||||
@echo "===> No soft render"
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(WITH_SDL2),yes)
|
||||
release/ref_soft.dylib : CFLAGS += -DSDL2
|
||||
endif
|
||||
|
||||
release/ref_soft.dylib : LDFLAGS += -shared
|
||||
|
||||
else # not Windows or Darwin
|
||||
|
||||
ifeq ($(WITH_REFSOFT),yes)
|
||||
ref_soft:
|
||||
@echo "===> Building ref_soft.so"
|
||||
$(MAKE) release/ref_soft.so
|
||||
else
|
||||
ref_soft:
|
||||
@echo "===> No soft render"
|
||||
endif
|
||||
|
||||
release/ref_soft.so : CFLAGS += -fPIC
|
||||
release/ref_soft.so : LDFLAGS += -shared
|
||||
|
||||
ifeq ($(WITH_SDL2),yes)
|
||||
release/ref_soft.so : CFLAGS += -DSDL2
|
||||
endif
|
||||
|
||||
endif # OS specific ref_soft shit
|
||||
|
||||
build/ref_soft/%.o: %.c
|
||||
@echo "===> CC $<"
|
||||
${Q}mkdir -p $(@D)
|
||||
${Q}$(CC) -c $(CFLAGS) $(SDLCFLAGS) $(INCLUDE) $(GLAD_INCLUDE) -o $@ $<
|
||||
|
||||
# ----------
|
||||
|
||||
# The baseq2 game
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
game:
|
||||
|
@ -809,7 +885,7 @@ CLIENT_OBJS_ := \
|
|||
src/server/sv_save.o \
|
||||
src/server/sv_send.o \
|
||||
src/server/sv_user.o \
|
||||
src/server/sv_world.o
|
||||
src/server/sv_world.o
|
||||
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
CLIENT_OBJS_ += \
|
||||
|
@ -848,7 +924,7 @@ REFGL1_OBJS_ := \
|
|||
src/client/refresh/files/wal.o \
|
||||
src/common/shared/shared.o \
|
||||
src/common/md4.o
|
||||
|
||||
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
REFGL1_OBJS_ += \
|
||||
src/backends/windows/shared/mem.o
|
||||
|
@ -891,6 +967,40 @@ endif
|
|||
|
||||
# ----------
|
||||
|
||||
REFSOFT_OBJS_ := \
|
||||
src/client/refresh/soft/r_aclip.o \
|
||||
src/client/refresh/soft/r_alias.o \
|
||||
src/client/refresh/soft/r_bsp.o \
|
||||
src/client/refresh/soft/r_draw.o \
|
||||
src/client/refresh/soft/r_edge.o \
|
||||
src/client/refresh/soft/r_image.o \
|
||||
src/client/refresh/soft/r_light.o \
|
||||
src/client/refresh/soft/r_main.o \
|
||||
src/client/refresh/soft/r_misc.o \
|
||||
src/client/refresh/soft/r_model.o \
|
||||
src/client/refresh/soft/r_part.o \
|
||||
src/client/refresh/soft/r_poly.o \
|
||||
src/client/refresh/soft/r_polyse.o \
|
||||
src/client/refresh/soft/r_rast.o \
|
||||
src/client/refresh/soft/r_scan.o \
|
||||
src/client/refresh/soft/r_sprite.o \
|
||||
src/client/refresh/soft/r_surf.o \
|
||||
src/client/refresh/files/pcx.o \
|
||||
src/client/refresh/files/stb.o \
|
||||
src/client/refresh/files/wal.o \
|
||||
src/common/shared/shared.o \
|
||||
src/common/md4.o
|
||||
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
REFSOFT_OBJS_ += \
|
||||
src/backends/windows/shared/mem.o
|
||||
else # not Windows
|
||||
REFSOFT_OBJS_ += \
|
||||
src/backends/unix/shared/hunk.o
|
||||
endif
|
||||
|
||||
# ----------
|
||||
|
||||
# Used by the server
|
||||
SERVER_OBJS_ := \
|
||||
src/common/argproc.o \
|
||||
|
@ -944,6 +1054,7 @@ endif
|
|||
CLIENT_OBJS = $(patsubst %,build/client/%,$(CLIENT_OBJS_))
|
||||
REFGL1_OBJS = $(patsubst %,build/ref_gl1/%,$(REFGL1_OBJS_))
|
||||
REFGL3_OBJS = $(patsubst %,build/ref_gl3/%,$(REFGL3_OBJS_))
|
||||
REFSOFT_OBJS = $(patsubst %,build/ref_soft/%,$(REFSOFT_OBJS_))
|
||||
SERVER_OBJS = $(patsubst %,build/server/%,$(SERVER_OBJS_))
|
||||
GAME_OBJS = $(patsubst %,build/baseq2/%,$(GAME_OBJS_))
|
||||
|
||||
|
@ -953,6 +1064,7 @@ GAME_OBJS = $(patsubst %,build/baseq2/%,$(GAME_OBJS_))
|
|||
CLIENT_DEPS= $(CLIENT_OBJS:.o=.d)
|
||||
REFGL1_DEPS= $(REFGL1_OBJS:.o=.d)
|
||||
REFGL3_DEPS= $(REFGL3_OBJS:.o=.d)
|
||||
REFSOFT_DEPS= $(REFSOFT_OBJS:.o=.d)
|
||||
SERVER_DEPS= $(SERVER_OBJS:.o=.d)
|
||||
GAME_DEPS= $(GAME_OBJS:.o=.d)
|
||||
|
||||
|
@ -1023,6 +1135,22 @@ release/ref_gl3.so : $(REFGL3_OBJS)
|
|||
${Q}$(CC) $(REFGL3_OBJS) $(LDFLAGS) $(SDLLDFLAGS) -o $@
|
||||
endif
|
||||
|
||||
# release/ref_soft.so
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
release/ref_soft.dll : $(REFSOFT_OBJS)
|
||||
@echo "===> LD $@"
|
||||
${Q}$(CC) $(REFSOFT_OBJS) $(LDFLAGS) $(DLL_SDLLDFLAGS) -o $@
|
||||
$(Q)strip $@
|
||||
else ifeq ($(YQ2_OSTYPE), Darwin)
|
||||
release/ref_soft.dylib : $(REFSOFT_OBJS)
|
||||
@echo "===> LD $@"
|
||||
${Q}$(CC) $(REFSOFT_OBJS) $(LDFLAGS) $(SDLLDFLAGS) -o $@
|
||||
else
|
||||
release/ref_soft.so : $(REFSOFT_OBJS)
|
||||
@echo "===> LD $@"
|
||||
${Q}$(CC) $(REFSOFT_OBJS) $(LDFLAGS) $(SDLLDFLAGS) -o $@
|
||||
endif
|
||||
|
||||
# release/baseq2/game.so
|
||||
ifeq ($(YQ2_OSTYPE), Windows)
|
||||
release/baseq2/game.dll : $(GAME_OBJS)
|
||||
|
|
|
@ -811,7 +811,7 @@ SDL_ClearBuffer(void)
|
|||
int i;
|
||||
unsigned char *ptr = sound.buffer;
|
||||
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1460,7 +1460,7 @@ SDL_BackendInit(void)
|
|||
|
||||
soundtime = 0;
|
||||
snd_inited = 1;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,10 +160,10 @@ Hunk_End(void)
|
|||
void
|
||||
Hunk_Free(void *base)
|
||||
{
|
||||
byte *m;
|
||||
|
||||
if (base)
|
||||
{
|
||||
byte *m;
|
||||
|
||||
m = ((byte *)base) - sizeof(int);
|
||||
|
||||
if (munmap(m, *((int *)m)))
|
||||
|
|
|
@ -117,7 +117,7 @@ Sys_Microseconds(void)
|
|||
long long sec = now.tv_sec;
|
||||
// set back first by 1ms so neither this function nor Sys_Milliseconds()
|
||||
// (which calls this) will ever return 0
|
||||
nsec -= 1000000;
|
||||
nsec -= 1000000;
|
||||
if(nsec < 0)
|
||||
{
|
||||
nsec += 1000000000ll; // 1s in ns => definitely positive now
|
||||
|
@ -411,7 +411,6 @@ Sys_GetGameAPI(void *parms)
|
|||
{
|
||||
void *(*GetGameAPI)(void *);
|
||||
|
||||
FILE *fp;
|
||||
char name[MAX_OSPATH];
|
||||
char *path;
|
||||
char *str_p;
|
||||
|
@ -436,6 +435,8 @@ Sys_GetGameAPI(void *parms)
|
|||
|
||||
while (1)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
path = FS_NextPath(path);
|
||||
|
||||
if (!path)
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
extern void M_ForceMenuOff(void);
|
||||
|
||||
static cvar_t *gl_mode;
|
||||
#ifdef REFSOFT
|
||||
static cvar_t *sw_mode;
|
||||
#endif
|
||||
static cvar_t *gl_hudscale;
|
||||
static cvar_t *gl_consolescale;
|
||||
static cvar_t *gl_menuscale;
|
||||
|
@ -73,10 +76,21 @@ GetRenderer(void)
|
|||
{
|
||||
return 1;
|
||||
}
|
||||
#ifdef REFSOFT
|
||||
else if (Q_stricmp(vid_renderer->string, "soft") == 0)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
#else
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -157,8 +171,31 @@ ApplyChanges(void *unused)
|
|||
Cvar_Set("vid_renderer", "gl3");
|
||||
restart = true;
|
||||
}
|
||||
#ifdef REFSOFT
|
||||
else if (s_renderer_list.curvalue == 2)
|
||||
{
|
||||
Cvar_Set("vid_renderer", "soft");
|
||||
restart = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef REFSOFT
|
||||
if (s_renderer_list.curvalue == 2) {
|
||||
/* custom mode */
|
||||
if (s_mode_list.curvalue != GetCustomValue(&s_mode_list))
|
||||
{
|
||||
/* Restarts automatically */
|
||||
Cvar_SetValue("sw_mode", s_mode_list.curvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Restarts automatically */
|
||||
Cvar_SetValue("sw_mode", -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* custom mode */
|
||||
if (s_mode_list.curvalue != GetCustomValue(&s_mode_list))
|
||||
{
|
||||
|
@ -224,6 +261,20 @@ ApplyChanges(void *unused)
|
|||
M_ForceMenuOff();
|
||||
}
|
||||
|
||||
#ifdef REFSOFT
|
||||
static void DriverCallback( void *unused )
|
||||
{
|
||||
if (s_renderer_list.curvalue == 2)
|
||||
{
|
||||
s_mode_list.curvalue = sw_mode->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_mode_list.curvalue = gl_mode->value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
VID_MenuInit(void)
|
||||
{
|
||||
|
@ -232,6 +283,9 @@ VID_MenuInit(void)
|
|||
static const char *renderers[] = {
|
||||
"[OpenGL 1.4]",
|
||||
"[OpenGL 3.2]",
|
||||
#ifdef REFSOFT
|
||||
"[SDL Soft ]",
|
||||
#endif
|
||||
"[Custom ]",
|
||||
0
|
||||
};
|
||||
|
@ -261,14 +315,14 @@ VID_MenuInit(void)
|
|||
"[1920 1080 ]",
|
||||
"[1920 1200 ]",
|
||||
"[2048 1536 ]",
|
||||
"[2560x1080 ]",
|
||||
"[2560x1440 ]",
|
||||
"[2560x1600 ]",
|
||||
"[3440x1440 ]",
|
||||
"[3840x1600 ]",
|
||||
"[3840x2160 ]",
|
||||
"[4096x2160 ]",
|
||||
"[5120x2880 ]",
|
||||
"[2560 1080 ]",
|
||||
"[2560 1440 ]",
|
||||
"[2560 1600 ]",
|
||||
"[3440 1440 ]",
|
||||
"[3840 1600 ]",
|
||||
"[3840 2160 ]",
|
||||
"[4096 2160 ]",
|
||||
"[5120 2880 ]",
|
||||
"[custom ]",
|
||||
0
|
||||
};
|
||||
|
@ -312,6 +366,13 @@ VID_MenuInit(void)
|
|||
gl_mode = Cvar_Get("gl_mode", "4", 0);
|
||||
}
|
||||
|
||||
#ifdef REFSOFT
|
||||
if (!sw_mode)
|
||||
{
|
||||
sw_mode = Cvar_Get("sw_mode", "4", 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!gl_hudscale)
|
||||
{
|
||||
gl_hudscale = Cvar_Get("gl_hudscale", "-1", CVAR_ARCHIVE);
|
||||
|
@ -371,12 +432,23 @@ VID_MenuInit(void)
|
|||
s_renderer_list.generic.y = (y = 0);
|
||||
s_renderer_list.itemnames = renderers;
|
||||
s_renderer_list.curvalue = GetRenderer();
|
||||
#ifdef REFSOFT
|
||||
s_renderer_list.generic.callback = DriverCallback;
|
||||
#endif
|
||||
|
||||
s_mode_list.generic.type = MTYPE_SPINCONTROL;
|
||||
s_mode_list.generic.name = "video mode";
|
||||
s_mode_list.generic.x = 0;
|
||||
s_mode_list.generic.y = (y += 10);
|
||||
s_mode_list.itemnames = resolutions;
|
||||
|
||||
#ifdef REFSOFT
|
||||
if (s_renderer_list.curvalue == 2 && sw_mode->value >= 0)
|
||||
{
|
||||
s_mode_list.curvalue = sw_mode->value;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (gl_mode->value >= 0)
|
||||
{
|
||||
s_mode_list.curvalue = gl_mode->value;
|
||||
|
|
|
@ -175,11 +175,18 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
|
|||
(pcx_width >= 4096) || (pcx_height >= 4096))
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Bad pcx file %s\n", filename);
|
||||
ri.FS_FreeFile(pcx);
|
||||
return;
|
||||
}
|
||||
|
||||
full_size = (pcx_height + 1) * (pcx_width + 1);
|
||||
out = malloc(full_size);
|
||||
if (!out)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Can't allocate\n");
|
||||
ri.FS_FreeFile(pcx);
|
||||
return;
|
||||
}
|
||||
|
||||
*pic = out;
|
||||
|
||||
|
@ -188,6 +195,13 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
|
|||
if (palette)
|
||||
{
|
||||
*palette = malloc(768);
|
||||
if (!(*palette))
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Can't allocate\n");
|
||||
free(out);
|
||||
ri.FS_FreeFile(pcx);
|
||||
return;
|
||||
}
|
||||
if (len > 768)
|
||||
{
|
||||
memcpy(*palette, (byte *)pcx + len - 768, 768);
|
||||
|
|
|
@ -299,17 +299,19 @@ R_RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end)
|
|||
|
||||
if (lightmap)
|
||||
{
|
||||
vec3_t scale;
|
||||
vec3_t scale;
|
||||
|
||||
lightmap += 3 * (dt * ((surf->extents[0] >> 4) + 1) + ds);
|
||||
|
||||
for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255;
|
||||
maps++)
|
||||
{
|
||||
for (i = 0; i < 3; i++)
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
scale[i] = gl_modulate->value *
|
||||
r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
|
||||
scale[j] = gl_modulate->value *
|
||||
r_newrefdef.lightstyles[surf->styles[maps]].rgb[j];
|
||||
}
|
||||
|
||||
pointcolor[0] += lightmap[0] * scale[0] * (1.0 / 255);
|
||||
|
|
1077
src/client/refresh/soft/adivtab.h
Normal file
1077
src/client/refresh/soft/adivtab.h
Normal file
File diff suppressed because it is too large
Load diff
317
src/client/refresh/soft/r_aclip.c
Normal file
317
src/client/refresh/soft/r_aclip.c
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_aclip.c: clip routines for drawing Alias models directly to the screen
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
static finalvert_t fv[2][8];
|
||||
|
||||
void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
|
||||
void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||
finalvert_t *out);
|
||||
void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||
finalvert_t *out);
|
||||
void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||
finalvert_t *out);
|
||||
void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||
finalvert_t *out);
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_Alias_clip_z
|
||||
|
||||
pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
|
||||
================
|
||||
*/
|
||||
void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
|
||||
{
|
||||
float scale;
|
||||
|
||||
scale = (ALIAS_Z_CLIP_PLANE - pfv0->xyz[2]) /
|
||||
(pfv1->xyz[2] - pfv0->xyz[2]);
|
||||
|
||||
out->xyz[0] = pfv0->xyz[0] + (pfv1->xyz[0] - pfv0->xyz[0]) * scale;
|
||||
out->xyz[1] = pfv0->xyz[1] + (pfv1->xyz[1] - pfv0->xyz[1]) * scale;
|
||||
out->xyz[2] = ALIAS_Z_CLIP_PLANE;
|
||||
|
||||
out->s = pfv0->s + (pfv1->s - pfv0->s) * scale;
|
||||
out->t = pfv0->t + (pfv1->t - pfv0->t) * scale;
|
||||
out->l = pfv0->l + (pfv1->l - pfv0->l) * scale;
|
||||
|
||||
R_AliasProjectAndClipTestFinalVert (out);
|
||||
}
|
||||
|
||||
void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
|
||||
{
|
||||
float scale;
|
||||
|
||||
if (pfv0->v >= pfv1->v )
|
||||
{
|
||||
scale = (float)(r_refdef.aliasvrect.x - pfv0->u) /
|
||||
(pfv1->u - pfv0->u);
|
||||
out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
|
||||
out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
|
||||
out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
|
||||
out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
|
||||
out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
|
||||
out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = (float)(r_refdef.aliasvrect.x - pfv1->u) /
|
||||
(pfv0->u - pfv1->u);
|
||||
out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
|
||||
out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
|
||||
out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
|
||||
out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
|
||||
out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
|
||||
out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
|
||||
{
|
||||
float scale;
|
||||
|
||||
if ( pfv0->v >= pfv1->v )
|
||||
{
|
||||
scale = (float)(r_refdef.aliasvrectright - pfv0->u ) /
|
||||
(pfv1->u - pfv0->u );
|
||||
out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
|
||||
out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
|
||||
out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
|
||||
out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
|
||||
out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
|
||||
out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = (float)(r_refdef.aliasvrectright - pfv1->u ) /
|
||||
(pfv0->u - pfv1->u );
|
||||
out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
|
||||
out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
|
||||
out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
|
||||
out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
|
||||
out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
|
||||
out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
|
||||
{
|
||||
float scale;
|
||||
|
||||
if (pfv0->v >= pfv1->v)
|
||||
{
|
||||
scale = (float)(r_refdef.aliasvrect.y - pfv0->v) /
|
||||
(pfv1->v - pfv0->v);
|
||||
out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
|
||||
out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
|
||||
out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
|
||||
out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
|
||||
out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
|
||||
out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = (float)(r_refdef.aliasvrect.y - pfv1->v) /
|
||||
(pfv0->v - pfv1->v);
|
||||
out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
|
||||
out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
|
||||
out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
|
||||
out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
|
||||
out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
|
||||
out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
|
||||
finalvert_t *out)
|
||||
{
|
||||
float scale;
|
||||
|
||||
if (pfv0->v >= pfv1->v)
|
||||
{
|
||||
scale = (float)(r_refdef.aliasvrectbottom - pfv0->v) /
|
||||
(pfv1->v - pfv0->v);
|
||||
|
||||
out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
|
||||
out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
|
||||
out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
|
||||
out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
|
||||
out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
|
||||
out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = (float)(r_refdef.aliasvrectbottom - pfv1->v) /
|
||||
(pfv0->v - pfv1->v);
|
||||
|
||||
out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
|
||||
out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
|
||||
out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
|
||||
out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
|
||||
out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
|
||||
out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
|
||||
void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
|
||||
{
|
||||
int i,j,k;
|
||||
|
||||
j = count-1;
|
||||
k = 0;
|
||||
for (i=0 ; i<count ; j = i, i++)
|
||||
{
|
||||
int flags, oldflags;
|
||||
|
||||
oldflags = in[j].flags & flag;
|
||||
flags = in[i].flags & flag;
|
||||
|
||||
if (flags && oldflags)
|
||||
continue;
|
||||
if (oldflags ^ flags)
|
||||
{
|
||||
clip (&in[j], &in[i], &out[k]);
|
||||
out[k].flags = 0;
|
||||
if (out[k].u < r_refdef.aliasvrect.x)
|
||||
out[k].flags |= ALIAS_LEFT_CLIP;
|
||||
if (out[k].v < r_refdef.aliasvrect.y)
|
||||
out[k].flags |= ALIAS_TOP_CLIP;
|
||||
if (out[k].u > r_refdef.aliasvrectright)
|
||||
out[k].flags |= ALIAS_RIGHT_CLIP;
|
||||
if (out[k].v > r_refdef.aliasvrectbottom)
|
||||
out[k].flags |= ALIAS_BOTTOM_CLIP;
|
||||
k++;
|
||||
}
|
||||
if (!flags)
|
||||
{
|
||||
out[k] = in[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasClipTriangle
|
||||
================
|
||||
*/
|
||||
void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2)
|
||||
{
|
||||
int i, k, pingpong;
|
||||
unsigned clipflags;
|
||||
|
||||
// copy vertexes and fix seam texture coordinates
|
||||
fv[0][0] = *index0;
|
||||
fv[0][1] = *index1;
|
||||
fv[0][2] = *index2;
|
||||
|
||||
// clip
|
||||
clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
|
||||
|
||||
if (clipflags & ALIAS_Z_CLIP)
|
||||
{
|
||||
k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
|
||||
if (k == 0)
|
||||
return;
|
||||
|
||||
pingpong = 1;
|
||||
clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
pingpong = 0;
|
||||
k = 3;
|
||||
}
|
||||
|
||||
if (clipflags & ALIAS_LEFT_CLIP)
|
||||
{
|
||||
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
|
||||
ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
|
||||
if (k == 0)
|
||||
return;
|
||||
|
||||
pingpong ^= 1;
|
||||
}
|
||||
|
||||
if (clipflags & ALIAS_RIGHT_CLIP)
|
||||
{
|
||||
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
|
||||
ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
|
||||
if (k == 0)
|
||||
return;
|
||||
|
||||
pingpong ^= 1;
|
||||
}
|
||||
|
||||
if (clipflags & ALIAS_BOTTOM_CLIP)
|
||||
{
|
||||
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
|
||||
ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
|
||||
if (k == 0)
|
||||
return;
|
||||
|
||||
pingpong ^= 1;
|
||||
}
|
||||
|
||||
if (clipflags & ALIAS_TOP_CLIP)
|
||||
{
|
||||
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
|
||||
ALIAS_TOP_CLIP, k, R_Alias_clip_top);
|
||||
if (k == 0)
|
||||
return;
|
||||
|
||||
pingpong ^= 1;
|
||||
}
|
||||
|
||||
for (i=0 ; i<k ; i++)
|
||||
{
|
||||
if (fv[pingpong][i].u < r_refdef.aliasvrect.x)
|
||||
fv[pingpong][i].u = r_refdef.aliasvrect.x;
|
||||
else if (fv[pingpong][i].u > r_refdef.aliasvrectright)
|
||||
fv[pingpong][i].u = r_refdef.aliasvrectright;
|
||||
|
||||
if (fv[pingpong][i].v < r_refdef.aliasvrect.y)
|
||||
fv[pingpong][i].v = r_refdef.aliasvrect.y;
|
||||
else if (fv[pingpong][i].v > r_refdef.aliasvrectbottom)
|
||||
fv[pingpong][i].v = r_refdef.aliasvrectbottom;
|
||||
|
||||
fv[pingpong][i].flags = 0;
|
||||
}
|
||||
|
||||
// draw triangles
|
||||
for (i=1 ; i<k-1 ; i++)
|
||||
{
|
||||
aliastriangleparms.a = &fv[pingpong][0];
|
||||
aliastriangleparms.b = &fv[pingpong][i];
|
||||
aliastriangleparms.c = &fv[pingpong][i+1];
|
||||
R_DrawTriangle();
|
||||
}
|
||||
}
|
864
src/client/refresh/soft/r_alias.c
Normal file
864
src/client/refresh/soft/r_alias.c
Normal file
|
@ -0,0 +1,864 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_alias.c: routines for setting up to draw alias models
|
||||
|
||||
/*
|
||||
** use a real variable to control lerping
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "r_local.h"
|
||||
|
||||
#define LIGHT_MIN 5 // lowest light value we'll allow, to avoid the
|
||||
// need for inner-loop light clamping
|
||||
|
||||
//PGM
|
||||
extern byte iractive;
|
||||
//PGM
|
||||
|
||||
int r_amodels_drawn;
|
||||
|
||||
affinetridesc_t r_affinetridesc;
|
||||
|
||||
vec3_t r_plightvec;
|
||||
vec3_t r_lerped[1024];
|
||||
vec3_t r_lerp_frontv, r_lerp_backv, r_lerp_move;
|
||||
|
||||
int r_ambientlight;
|
||||
int r_aliasblendcolor;
|
||||
float r_shadelight;
|
||||
|
||||
|
||||
daliasframe_t *r_thisframe, *r_lastframe;
|
||||
dmdl_t *s_pmdl;
|
||||
|
||||
float aliastransform[3][4];
|
||||
float aliasworldtransform[3][4];
|
||||
float aliasoldworldtransform[3][4];
|
||||
|
||||
static float s_ziscale;
|
||||
static vec3_t s_alias_forward, s_alias_right, s_alias_up;
|
||||
|
||||
|
||||
#define NUMVERTEXNORMALS 162
|
||||
|
||||
float r_avertexnormals[NUMVERTEXNORMALS][3] = {
|
||||
#include "../constants/anorms.h"
|
||||
};
|
||||
|
||||
|
||||
void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp );
|
||||
void R_AliasSetUpTransform (void);
|
||||
void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] );
|
||||
void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
|
||||
|
||||
void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv );
|
||||
|
||||
void R_AliasLerpFrames( dmdl_t *paliashdr, float backlerp );
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasCheckBBox
|
||||
================
|
||||
*/
|
||||
|
||||
#define BBOX_TRIVIAL_ACCEPT 0
|
||||
#define BBOX_MUST_CLIP_XY 1
|
||||
#define BBOX_MUST_CLIP_Z 2
|
||||
#define BBOX_TRIVIAL_REJECT 8
|
||||
|
||||
/*
|
||||
** R_AliasCheckFrameBBox
|
||||
**
|
||||
** Checks a specific alias frame bounding box
|
||||
*/
|
||||
unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] )
|
||||
{
|
||||
unsigned long aggregate_and_clipcode = ~0U,
|
||||
aggregate_or_clipcode = 0;
|
||||
int i;
|
||||
vec3_t mins, maxs;
|
||||
vec3_t transformed_min, transformed_max;
|
||||
qboolean zclipped = false, zfullyclipped = true;
|
||||
|
||||
/*
|
||||
** get the exact frame bounding box
|
||||
*/
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
mins[i] = frame->translate[i];
|
||||
maxs[i] = mins[i] + frame->scale[i]*255;
|
||||
}
|
||||
|
||||
/*
|
||||
** transform the min and max values into view space
|
||||
*/
|
||||
R_AliasTransformVector( mins, transformed_min, aliastransform );
|
||||
R_AliasTransformVector( maxs, transformed_max, aliastransform );
|
||||
|
||||
if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE )
|
||||
zfullyclipped = false;
|
||||
if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE )
|
||||
zfullyclipped = false;
|
||||
|
||||
if ( zfullyclipped )
|
||||
{
|
||||
return BBOX_TRIVIAL_REJECT;
|
||||
}
|
||||
if ( zclipped )
|
||||
{
|
||||
return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z );
|
||||
}
|
||||
|
||||
/*
|
||||
** build a transformed bounding box from the given min and max
|
||||
*/
|
||||
for ( i = 0; i < 8; i++ )
|
||||
{
|
||||
int j;
|
||||
vec3_t tmp, transformed;
|
||||
unsigned long clipcode = 0;
|
||||
|
||||
if ( i & 1 )
|
||||
tmp[0] = mins[0];
|
||||
else
|
||||
tmp[0] = maxs[0];
|
||||
|
||||
if ( i & 2 )
|
||||
tmp[1] = mins[1];
|
||||
else
|
||||
tmp[1] = maxs[1];
|
||||
|
||||
if ( i & 4 )
|
||||
tmp[2] = mins[2];
|
||||
else
|
||||
tmp[2] = maxs[2];
|
||||
|
||||
R_AliasTransformVector( tmp, transformed, worldxf );
|
||||
|
||||
for ( j = 0; j < 4; j++ )
|
||||
{
|
||||
float dp = DotProduct( transformed, view_clipplanes[j].normal );
|
||||
|
||||
if ( ( dp - view_clipplanes[j].dist ) < 0.0F )
|
||||
clipcode |= 1 << j;
|
||||
}
|
||||
|
||||
aggregate_and_clipcode &= clipcode;
|
||||
aggregate_or_clipcode |= clipcode;
|
||||
}
|
||||
|
||||
if ( aggregate_and_clipcode )
|
||||
{
|
||||
return BBOX_TRIVIAL_REJECT;
|
||||
}
|
||||
if ( !aggregate_or_clipcode )
|
||||
{
|
||||
return BBOX_TRIVIAL_ACCEPT;
|
||||
}
|
||||
|
||||
return BBOX_MUST_CLIP_XY;
|
||||
}
|
||||
|
||||
qboolean R_AliasCheckBBox (void)
|
||||
{
|
||||
unsigned long ccodes[2] = { 0, 0 };
|
||||
|
||||
ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform );
|
||||
|
||||
/*
|
||||
** non-lerping model
|
||||
*/
|
||||
if ( currententity->backlerp == 0 )
|
||||
{
|
||||
if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT )
|
||||
return BBOX_TRIVIAL_ACCEPT;
|
||||
else if ( ccodes[0] & BBOX_TRIVIAL_REJECT )
|
||||
return BBOX_TRIVIAL_REJECT;
|
||||
else
|
||||
return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT );
|
||||
}
|
||||
|
||||
ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform );
|
||||
|
||||
if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT )
|
||||
return BBOX_TRIVIAL_ACCEPT;
|
||||
else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT )
|
||||
return BBOX_TRIVIAL_REJECT;
|
||||
else
|
||||
return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasTransformVector
|
||||
================
|
||||
*/
|
||||
void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] )
|
||||
{
|
||||
out[0] = DotProduct(in, xf[0]) + xf[0][3];
|
||||
out[1] = DotProduct(in, xf[1]) + xf[1][3];
|
||||
out[2] = DotProduct(in, xf[2]) + xf[2][3];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasPreparePoints
|
||||
|
||||
General clipped case
|
||||
================
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int num_points;
|
||||
dtrivertx_t *last_verts; // verts from the last frame
|
||||
dtrivertx_t *this_verts; // verts from this frame
|
||||
finalvert_t *dest_verts; // destination for transformed verts
|
||||
} aliasbatchedtransformdata_t;
|
||||
|
||||
aliasbatchedtransformdata_t aliasbatchedtransformdata;
|
||||
finalvert_t *finalverts;
|
||||
|
||||
void R_AliasPreparePoints (void)
|
||||
{
|
||||
int i;
|
||||
dstvert_t *pstverts;
|
||||
dtriangle_t *ptri;
|
||||
finalvert_t *pfv[3];
|
||||
finalvert_t *pfinalverts;
|
||||
|
||||
// PGM
|
||||
iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE);
|
||||
// iractive = 0;
|
||||
// if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
|
||||
// iractive = 1;
|
||||
// PGM
|
||||
|
||||
// put work vertexes on stack, cache aligned
|
||||
pfinalverts = finalverts;
|
||||
|
||||
aliasbatchedtransformdata.num_points = s_pmdl->num_xyz;
|
||||
aliasbatchedtransformdata.last_verts = r_lastframe->verts;
|
||||
aliasbatchedtransformdata.this_verts = r_thisframe->verts;
|
||||
aliasbatchedtransformdata.dest_verts = pfinalverts;
|
||||
|
||||
R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points,
|
||||
aliasbatchedtransformdata.dest_verts,
|
||||
aliasbatchedtransformdata.last_verts,
|
||||
aliasbatchedtransformdata.this_verts );
|
||||
|
||||
// clip and draw all triangles
|
||||
//
|
||||
pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st);
|
||||
ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris);
|
||||
|
||||
if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
|
||||
{
|
||||
for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
|
||||
{
|
||||
pfv[0] = &pfinalverts[ptri->index_xyz[0]];
|
||||
pfv[1] = &pfinalverts[ptri->index_xyz[1]];
|
||||
pfv[2] = &pfinalverts[ptri->index_xyz[2]];
|
||||
|
||||
if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
|
||||
continue; // completely clipped
|
||||
|
||||
// insert s/t coordinates
|
||||
pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
|
||||
pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
|
||||
|
||||
pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
|
||||
pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
|
||||
|
||||
pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
|
||||
pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
|
||||
|
||||
if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
|
||||
{ // totally unclipped
|
||||
aliastriangleparms.a = pfv[2];
|
||||
aliastriangleparms.b = pfv[1];
|
||||
aliastriangleparms.c = pfv[0];
|
||||
|
||||
R_DrawTriangle();
|
||||
}
|
||||
else
|
||||
{
|
||||
R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
|
||||
{
|
||||
pfv[0] = &pfinalverts[ptri->index_xyz[0]];
|
||||
pfv[1] = &pfinalverts[ptri->index_xyz[1]];
|
||||
pfv[2] = &pfinalverts[ptri->index_xyz[2]];
|
||||
|
||||
if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
|
||||
continue; // completely clipped
|
||||
|
||||
// insert s/t coordinates
|
||||
pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
|
||||
pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
|
||||
|
||||
pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
|
||||
pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
|
||||
|
||||
pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
|
||||
pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
|
||||
|
||||
if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
|
||||
{ // totally unclipped
|
||||
aliastriangleparms.a = pfv[0];
|
||||
aliastriangleparms.b = pfv[1];
|
||||
aliastriangleparms.c = pfv[2];
|
||||
|
||||
R_DrawTriangle();
|
||||
}
|
||||
else
|
||||
{ // partially clipped
|
||||
R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasSetUpTransform
|
||||
================
|
||||
*/
|
||||
void R_AliasSetUpTransform (void)
|
||||
{
|
||||
int i;
|
||||
static float viewmatrix[3][4];
|
||||
vec3_t angles;
|
||||
|
||||
// TODO: should really be stored with the entity instead of being reconstructed
|
||||
// TODO: should use a look-up table
|
||||
// TODO: could cache lazily, stored in the entity
|
||||
//
|
||||
angles[ROLL] = currententity->angles[ROLL];
|
||||
angles[PITCH] = currententity->angles[PITCH];
|
||||
angles[YAW] = currententity->angles[YAW];
|
||||
AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
|
||||
|
||||
// TODO: can do this with simple matrix rearrangement
|
||||
memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
|
||||
memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
aliasoldworldtransform[i][0] = aliasworldtransform[i][0] = s_alias_forward[i];
|
||||
aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
|
||||
aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i];
|
||||
}
|
||||
|
||||
aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0];
|
||||
aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1];
|
||||
aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2];
|
||||
|
||||
aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0];
|
||||
aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1];
|
||||
aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2];
|
||||
|
||||
// FIXME: can do more efficiently than full concatenation
|
||||
// memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
|
||||
|
||||
// R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
|
||||
|
||||
// TODO: should be global, set when vright, etc., set
|
||||
VectorCopy (vright, viewmatrix[0]);
|
||||
VectorCopy (vup, viewmatrix[1]);
|
||||
VectorInverse (viewmatrix[1]);
|
||||
VectorCopy (vpn, viewmatrix[2]);
|
||||
|
||||
viewmatrix[0][3] = 0;
|
||||
viewmatrix[1][3] = 0;
|
||||
viewmatrix[2][3] = 0;
|
||||
|
||||
// memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
|
||||
|
||||
R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
|
||||
|
||||
aliasworldtransform[0][3] = currententity->origin[0];
|
||||
aliasworldtransform[1][3] = currententity->origin[1];
|
||||
aliasworldtransform[2][3] = currententity->origin[2];
|
||||
|
||||
aliasoldworldtransform[0][3] = currententity->oldorigin[0];
|
||||
aliasoldworldtransform[1][3] = currententity->oldorigin[1];
|
||||
aliasoldworldtransform[2][3] = currententity->oldorigin[2];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasTransformFinalVerts
|
||||
================
|
||||
*/
|
||||
void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ )
|
||||
{
|
||||
int temp;
|
||||
float lightcos, *plightnormal;
|
||||
vec3_t lerped_vert;
|
||||
|
||||
lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
|
||||
lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
|
||||
lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
|
||||
|
||||
plightnormal = r_avertexnormals[newv->lightnormalindex];
|
||||
|
||||
// PMM - added double damage shell
|
||||
if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
|
||||
{
|
||||
lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE;
|
||||
lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE;
|
||||
lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE;
|
||||
}
|
||||
|
||||
fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
|
||||
fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
|
||||
fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
|
||||
|
||||
fv->flags = 0;
|
||||
|
||||
// lighting
|
||||
lightcos = DotProduct (plightnormal, r_plightvec);
|
||||
temp = r_ambientlight;
|
||||
|
||||
if (lightcos < 0)
|
||||
{
|
||||
temp += (int)(r_shadelight * lightcos);
|
||||
|
||||
// clamp; because we limited the minimum ambient and shading light, we
|
||||
// don't have to clamp low light, just bright
|
||||
if (temp < 0)
|
||||
temp = 0;
|
||||
}
|
||||
|
||||
fv->l = temp;
|
||||
|
||||
if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE )
|
||||
{
|
||||
fv->flags |= ALIAS_Z_CLIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
R_AliasProjectAndClipTestFinalVert( fv );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasProjectAndClipTestFinalVert
|
||||
================
|
||||
*/
|
||||
void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv )
|
||||
{
|
||||
float zi;
|
||||
float x, y, z;
|
||||
|
||||
// project points
|
||||
x = fv->xyz[0];
|
||||
y = fv->xyz[1];
|
||||
z = fv->xyz[2];
|
||||
zi = 1.0 / z;
|
||||
|
||||
fv->zi = zi * s_ziscale;
|
||||
|
||||
fv->u = (x * aliasxscale * zi) + aliasxcenter;
|
||||
fv->v = (y * aliasyscale * zi) + aliasycenter;
|
||||
|
||||
if (fv->u < r_refdef.aliasvrect.x)
|
||||
fv->flags |= ALIAS_LEFT_CLIP;
|
||||
if (fv->v < r_refdef.aliasvrect.y)
|
||||
fv->flags |= ALIAS_TOP_CLIP;
|
||||
if (fv->u > r_refdef.aliasvrectright)
|
||||
fv->flags |= ALIAS_RIGHT_CLIP;
|
||||
if (fv->v > r_refdef.aliasvrectbottom)
|
||||
fv->flags |= ALIAS_BOTTOM_CLIP;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_AliasSetupSkin
|
||||
===============
|
||||
*/
|
||||
static qboolean R_AliasSetupSkin (void)
|
||||
{
|
||||
image_t *pskindesc;
|
||||
|
||||
if (currententity->skin)
|
||||
pskindesc = currententity->skin;
|
||||
else
|
||||
{
|
||||
int skinnum;
|
||||
|
||||
skinnum = currententity->skinnum;
|
||||
if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0))
|
||||
{
|
||||
R_Printf(PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n",
|
||||
currentmodel->name, skinnum);
|
||||
skinnum = 0;
|
||||
}
|
||||
|
||||
pskindesc = currentmodel->skins[skinnum];
|
||||
}
|
||||
|
||||
if ( !pskindesc )
|
||||
return false;
|
||||
|
||||
r_affinetridesc.pskin = pskindesc->pixels[0];
|
||||
r_affinetridesc.skinwidth = pskindesc->width;
|
||||
r_affinetridesc.skinheight = pskindesc->height;
|
||||
|
||||
R_PolysetUpdateTables (); // FIXME: precalc edge lookups
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasSetupLighting
|
||||
|
||||
FIXME: put lighting into tables
|
||||
================
|
||||
*/
|
||||
void R_AliasSetupLighting (void)
|
||||
{
|
||||
alight_t lighting;
|
||||
float lightvec[3] = {-1, 0, 0};
|
||||
vec3_t light;
|
||||
int i, j;
|
||||
|
||||
// all components of light should be identical in software
|
||||
if ( currententity->flags & RF_FULLBRIGHT )
|
||||
{
|
||||
for (i=0 ; i<3 ; i++)
|
||||
light[i] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
R_LightPoint (currententity->origin, light);
|
||||
}
|
||||
|
||||
// save off light value for server to look at (BIG HACK!)
|
||||
if ( currententity->flags & RF_WEAPONMODEL )
|
||||
r_lightlevel->value = 150.0 * light[0];
|
||||
|
||||
|
||||
if ( currententity->flags & RF_MINLIGHT )
|
||||
{
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (light[i] < 0.1)
|
||||
light[i] = 0.1;
|
||||
}
|
||||
|
||||
if ( currententity->flags & RF_GLOW )
|
||||
{ // bonus items will pulse with time
|
||||
float scale;
|
||||
|
||||
scale = 0.1 * sin(r_newrefdef.time*7);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
float min;
|
||||
|
||||
min = light[i] * 0.8;
|
||||
light[i] += scale;
|
||||
if (light[i] < min)
|
||||
light[i] = min;
|
||||
}
|
||||
}
|
||||
|
||||
j = (light[0] + light[1] + light[2])*0.3333*255;
|
||||
|
||||
lighting.ambientlight = j;
|
||||
lighting.shadelight = j;
|
||||
|
||||
lighting.plightvec = lightvec;
|
||||
|
||||
// clamp lighting so it doesn't overbright as much
|
||||
if (lighting.ambientlight > 128)
|
||||
lighting.ambientlight = 128;
|
||||
if (lighting.ambientlight + lighting.shadelight > 192)
|
||||
lighting.shadelight = 192 - lighting.ambientlight;
|
||||
|
||||
// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
|
||||
// to clamp off the bottom
|
||||
r_ambientlight = lighting.ambientlight;
|
||||
|
||||
if (r_ambientlight < LIGHT_MIN)
|
||||
r_ambientlight = LIGHT_MIN;
|
||||
|
||||
r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
|
||||
|
||||
if (r_ambientlight < LIGHT_MIN)
|
||||
r_ambientlight = LIGHT_MIN;
|
||||
|
||||
r_shadelight = lighting.shadelight;
|
||||
|
||||
if (r_shadelight < 0)
|
||||
r_shadelight = 0;
|
||||
|
||||
r_shadelight *= VID_GRADES;
|
||||
|
||||
// rotate the lighting vector into the model's frame of reference
|
||||
r_plightvec[0] = DotProduct( lighting.plightvec, s_alias_forward );
|
||||
r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right );
|
||||
r_plightvec[2] = DotProduct( lighting.plightvec, s_alias_up );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AliasSetupFrames
|
||||
|
||||
=================
|
||||
*/
|
||||
void R_AliasSetupFrames( dmdl_t *pmdl )
|
||||
{
|
||||
int thisframe = currententity->frame;
|
||||
int lastframe = currententity->oldframe;
|
||||
|
||||
if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) )
|
||||
{
|
||||
R_Printf(PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n",
|
||||
currentmodel->name, thisframe);
|
||||
thisframe = 0;
|
||||
}
|
||||
if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) )
|
||||
{
|
||||
R_Printf(PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n",
|
||||
currentmodel->name, lastframe);
|
||||
lastframe = 0;
|
||||
}
|
||||
|
||||
r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames
|
||||
+ thisframe * pmdl->framesize);
|
||||
|
||||
r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames
|
||||
+ lastframe * pmdl->framesize);
|
||||
}
|
||||
|
||||
/*
|
||||
** R_AliasSetUpLerpData
|
||||
**
|
||||
** Precomputes lerp coefficients used for the whole frame.
|
||||
*/
|
||||
void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp )
|
||||
{
|
||||
float frontlerp;
|
||||
vec3_t translation, vectors[3];
|
||||
int i;
|
||||
|
||||
frontlerp = 1.0F - backlerp;
|
||||
|
||||
/*
|
||||
** convert entity's angles into discrete vectors for R, U, and F
|
||||
*/
|
||||
AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
|
||||
|
||||
/*
|
||||
** translation is the vector from last position to this position
|
||||
*/
|
||||
VectorSubtract (currententity->oldorigin, currententity->origin, translation);
|
||||
|
||||
/*
|
||||
** move should be the delta back to the previous frame * backlerp
|
||||
*/
|
||||
r_lerp_move[0] = DotProduct(translation, vectors[0]); // forward
|
||||
r_lerp_move[1] = -DotProduct(translation, vectors[1]); // left
|
||||
r_lerp_move[2] = DotProduct(translation, vectors[2]); // up
|
||||
|
||||
VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move );
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i];
|
||||
}
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i];
|
||||
r_lerp_backv[i] = backlerp * r_lastframe->scale[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasDrawModel
|
||||
================
|
||||
*/
|
||||
void R_AliasDrawModel (void)
|
||||
{
|
||||
extern void (*d_pdrawspans)(void *);
|
||||
extern void R_PolysetDrawSpans8_Opaque( void * );
|
||||
extern void R_PolysetDrawSpans8_33( void * );
|
||||
extern void R_PolysetDrawSpans8_66( void * );
|
||||
extern void R_PolysetDrawSpansConstant8_33( void * );
|
||||
extern void R_PolysetDrawSpansConstant8_66( void * );
|
||||
|
||||
s_pmdl = (dmdl_t *)currentmodel->extradata;
|
||||
|
||||
if ( r_lerpmodels->value == 0 )
|
||||
currententity->backlerp = 0;
|
||||
|
||||
if ( currententity->flags & RF_WEAPONMODEL )
|
||||
{
|
||||
if ( r_lefthand->value == 1.0F )
|
||||
aliasxscale = -aliasxscale;
|
||||
else if ( r_lefthand->value == 2.0F )
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** we have to set our frame pointers and transformations before
|
||||
** doing any real work
|
||||
*/
|
||||
R_AliasSetupFrames( s_pmdl );
|
||||
R_AliasSetUpTransform();
|
||||
|
||||
// see if the bounding box lets us trivially reject, also sets
|
||||
// trivial accept status
|
||||
if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT )
|
||||
{
|
||||
if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
|
||||
{
|
||||
aliasxscale = -aliasxscale;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// set up the skin and verify it exists
|
||||
if ( !R_AliasSetupSkin () )
|
||||
{
|
||||
R_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n",
|
||||
currentmodel->name);
|
||||
return;
|
||||
}
|
||||
|
||||
r_amodels_drawn++;
|
||||
R_AliasSetupLighting ();
|
||||
|
||||
/*
|
||||
** select the proper span routine based on translucency
|
||||
*/
|
||||
// PMM - added double damage shell
|
||||
// PMM - reordered to handle blending
|
||||
if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
|
||||
{
|
||||
int color;
|
||||
|
||||
// PMM - added double
|
||||
color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM);
|
||||
// PMM - reordered, new shells after old shells (so they get overriden)
|
||||
|
||||
if ( color == RF_SHELL_RED )
|
||||
r_aliasblendcolor = SHELL_RED_COLOR;
|
||||
else if ( color == RF_SHELL_GREEN )
|
||||
r_aliasblendcolor = SHELL_GREEN_COLOR;
|
||||
else if ( color == RF_SHELL_BLUE )
|
||||
r_aliasblendcolor = SHELL_BLUE_COLOR;
|
||||
else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) )
|
||||
r_aliasblendcolor = SHELL_RG_COLOR;
|
||||
else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) )
|
||||
r_aliasblendcolor = SHELL_RB_COLOR;
|
||||
else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) )
|
||||
r_aliasblendcolor = SHELL_BG_COLOR;
|
||||
// PMM - added this .. it's yellowish
|
||||
else if ( color == (RF_SHELL_DOUBLE) )
|
||||
r_aliasblendcolor = SHELL_DOUBLE_COLOR;
|
||||
else if ( color == (RF_SHELL_HALF_DAM) )
|
||||
r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
|
||||
// pmm
|
||||
else
|
||||
r_aliasblendcolor = SHELL_WHITE_COLOR;
|
||||
/*
|
||||
if ( color & RF_SHELL_RED )
|
||||
{
|
||||
if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) )
|
||||
r_aliasblendcolor = SHELL_WHITE_COLOR;
|
||||
else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE))
|
||||
r_aliasblendcolor = SHELL_RB_COLOR;
|
||||
else
|
||||
r_aliasblendcolor = SHELL_RED_COLOR;
|
||||
}
|
||||
else if ( color & RF_SHELL_BLUE)
|
||||
{
|
||||
if ( color & RF_SHELL_DOUBLE )
|
||||
r_aliasblendcolor = SHELL_CYAN_COLOR;
|
||||
else
|
||||
r_aliasblendcolor = SHELL_BLUE_COLOR;
|
||||
}
|
||||
else if ( color & (RF_SHELL_DOUBLE) )
|
||||
r_aliasblendcolor = SHELL_DOUBLE_COLOR;
|
||||
else if ( color & (RF_SHELL_HALF_DAM) )
|
||||
r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
|
||||
else if ( color & RF_SHELL_GREEN )
|
||||
r_aliasblendcolor = SHELL_GREEN_COLOR;
|
||||
else
|
||||
r_aliasblendcolor = SHELL_WHITE_COLOR;
|
||||
*/
|
||||
|
||||
if ( currententity->alpha > 0.33 )
|
||||
d_pdrawspans = R_PolysetDrawSpansConstant8_66;
|
||||
else
|
||||
d_pdrawspans = R_PolysetDrawSpansConstant8_33;
|
||||
}
|
||||
else if ( currententity->flags & RF_TRANSLUCENT )
|
||||
{
|
||||
if ( currententity->alpha > 0.66 )
|
||||
d_pdrawspans = R_PolysetDrawSpans8_Opaque;
|
||||
else if ( currententity->alpha > 0.33 )
|
||||
d_pdrawspans = R_PolysetDrawSpans8_66;
|
||||
else
|
||||
d_pdrawspans = R_PolysetDrawSpans8_33;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_pdrawspans = R_PolysetDrawSpans8_Opaque;
|
||||
}
|
||||
|
||||
/*
|
||||
** compute this_frame and old_frame addresses
|
||||
*/
|
||||
R_AliasSetUpLerpData( s_pmdl, currententity->backlerp );
|
||||
|
||||
if (currententity->flags & RF_DEPTHHACK)
|
||||
s_ziscale = (float)0x8000 * (float)0x10000 * 3.0;
|
||||
else
|
||||
s_ziscale = (float)0x8000 * (float)0x10000;
|
||||
|
||||
R_AliasPreparePoints ();
|
||||
|
||||
if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
|
||||
{
|
||||
aliasxscale = -aliasxscale;
|
||||
}
|
||||
}
|
642
src/client/refresh/soft/r_bsp.c
Normal file
642
src/client/refresh/soft/r_bsp.c
Normal file
|
@ -0,0 +1,642 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_bsp.c
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
//
|
||||
// current entity info
|
||||
//
|
||||
qboolean insubmodel;
|
||||
entity_t *currententity;
|
||||
vec3_t modelorg; // modelorg is the viewpoint reletive to
|
||||
// the currently rendering entity
|
||||
vec3_t r_entorigin; // the currently rendering entity in world
|
||||
// coordinates
|
||||
|
||||
float entity_rotation[3][3];
|
||||
|
||||
int r_currentbkey;
|
||||
|
||||
typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
|
||||
|
||||
#define MAX_BMODEL_VERTS 500 // 6K
|
||||
#define MAX_BMODEL_EDGES 1000 // 12K
|
||||
|
||||
static mvertex_t *pbverts;
|
||||
static bedge_t *pbedges;
|
||||
static int numbverts, numbedges;
|
||||
static mvertex_t bverts[MAX_BMODEL_VERTS];
|
||||
static bedge_t bedges[MAX_BMODEL_EDGES];
|
||||
|
||||
static mvertex_t *pfrontenter, *pfrontexit;
|
||||
|
||||
static qboolean makeclippededge;
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
R_EntityRotate
|
||||
================
|
||||
*/
|
||||
void R_EntityRotate (vec3_t vec)
|
||||
{
|
||||
vec3_t tvec;
|
||||
|
||||
VectorCopy (vec, tvec);
|
||||
vec[0] = DotProduct (entity_rotation[0], tvec);
|
||||
vec[1] = DotProduct (entity_rotation[1], tvec);
|
||||
vec[2] = DotProduct (entity_rotation[2], tvec);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RotateBmodel
|
||||
================
|
||||
*/
|
||||
void R_RotateBmodel (void)
|
||||
{
|
||||
float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
|
||||
|
||||
// TODO: should use a look-up table
|
||||
// TODO: should really be stored with the entity instead of being reconstructed
|
||||
// TODO: could cache lazily, stored in the entity
|
||||
// TODO: share work with R_SetUpAliasTransform
|
||||
|
||||
// yaw
|
||||
angle = currententity->angles[YAW];
|
||||
angle = angle * M_PI*2 / 360;
|
||||
s = sin(angle);
|
||||
c = cos(angle);
|
||||
|
||||
temp1[0][0] = c;
|
||||
temp1[0][1] = s;
|
||||
temp1[0][2] = 0;
|
||||
temp1[1][0] = -s;
|
||||
temp1[1][1] = c;
|
||||
temp1[1][2] = 0;
|
||||
temp1[2][0] = 0;
|
||||
temp1[2][1] = 0;
|
||||
temp1[2][2] = 1;
|
||||
|
||||
|
||||
// pitch
|
||||
angle = currententity->angles[PITCH];
|
||||
angle = angle * M_PI*2 / 360;
|
||||
s = sin(angle);
|
||||
c = cos(angle);
|
||||
|
||||
temp2[0][0] = c;
|
||||
temp2[0][1] = 0;
|
||||
temp2[0][2] = -s;
|
||||
temp2[1][0] = 0;
|
||||
temp2[1][1] = 1;
|
||||
temp2[1][2] = 0;
|
||||
temp2[2][0] = s;
|
||||
temp2[2][1] = 0;
|
||||
temp2[2][2] = c;
|
||||
|
||||
R_ConcatRotations (temp2, temp1, temp3);
|
||||
|
||||
// roll
|
||||
angle = currententity->angles[ROLL];
|
||||
angle = angle * M_PI*2 / 360;
|
||||
s = sin(angle);
|
||||
c = cos(angle);
|
||||
|
||||
temp1[0][0] = 1;
|
||||
temp1[0][1] = 0;
|
||||
temp1[0][2] = 0;
|
||||
temp1[1][0] = 0;
|
||||
temp1[1][1] = c;
|
||||
temp1[1][2] = s;
|
||||
temp1[2][0] = 0;
|
||||
temp1[2][1] = -s;
|
||||
temp1[2][2] = c;
|
||||
|
||||
R_ConcatRotations (temp1, temp3, entity_rotation);
|
||||
|
||||
//
|
||||
// rotate modelorg and the transformation matrix
|
||||
//
|
||||
R_EntityRotate (modelorg);
|
||||
R_EntityRotate (vpn);
|
||||
R_EntityRotate (vright);
|
||||
R_EntityRotate (vup);
|
||||
|
||||
R_TransformFrustum ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RecursiveClipBPoly
|
||||
|
||||
Clip a bmodel poly down the world bsp tree
|
||||
================
|
||||
*/
|
||||
void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
|
||||
{
|
||||
bedge_t *psideedges[2], *pnextedge, *ptedge;
|
||||
int i, side, lastside;
|
||||
float frac;
|
||||
mplane_t *splitplane, tplane;
|
||||
mvertex_t *pvert, *plastvert, *ptvert;
|
||||
mnode_t *pn;
|
||||
int area;
|
||||
|
||||
psideedges[0] = psideedges[1] = NULL;
|
||||
|
||||
makeclippededge = false;
|
||||
|
||||
// transform the BSP plane into model space
|
||||
// FIXME: cache these?
|
||||
splitplane = pnode->plane;
|
||||
tplane.dist = splitplane->dist -
|
||||
DotProduct(r_entorigin, splitplane->normal);
|
||||
tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
|
||||
tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
|
||||
tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
|
||||
|
||||
// clip edges to BSP plane
|
||||
for (; pedges; pedges = pnextedge)
|
||||
{
|
||||
float dist, lastdist;
|
||||
|
||||
pnextedge = pedges->pnext;
|
||||
|
||||
// set the status for the last point as the previous point
|
||||
// FIXME: cache this stuff somehow?
|
||||
plastvert = pedges->v[0];
|
||||
lastdist = DotProduct (plastvert->position, tplane.normal) -
|
||||
tplane.dist;
|
||||
|
||||
if (lastdist > 0)
|
||||
lastside = 0;
|
||||
else
|
||||
lastside = 1;
|
||||
|
||||
pvert = pedges->v[1];
|
||||
|
||||
dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
|
||||
|
||||
if (dist > 0)
|
||||
side = 0;
|
||||
else
|
||||
side = 1;
|
||||
|
||||
if (side != lastside)
|
||||
{
|
||||
// clipped
|
||||
if (numbverts >= MAX_BMODEL_VERTS)
|
||||
return;
|
||||
|
||||
// generate the clipped vertex
|
||||
frac = lastdist / (lastdist - dist);
|
||||
ptvert = &pbverts[numbverts++];
|
||||
ptvert->position[0] = plastvert->position[0] +
|
||||
frac * (pvert->position[0] -
|
||||
plastvert->position[0]);
|
||||
ptvert->position[1] = plastvert->position[1] +
|
||||
frac * (pvert->position[1] -
|
||||
plastvert->position[1]);
|
||||
ptvert->position[2] = plastvert->position[2] +
|
||||
frac * (pvert->position[2] -
|
||||
plastvert->position[2]);
|
||||
|
||||
// split into two edges, one on each side, and remember entering
|
||||
// and exiting points
|
||||
// FIXME: share the clip edge by having a winding direction flag?
|
||||
if (numbedges >= (MAX_BMODEL_EDGES - 1))
|
||||
{
|
||||
R_Printf(PRINT_ALL,"Out of edges for bmodel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptedge = &pbedges[numbedges];
|
||||
ptedge->pnext = psideedges[lastside];
|
||||
psideedges[lastside] = ptedge;
|
||||
ptedge->v[0] = plastvert;
|
||||
ptedge->v[1] = ptvert;
|
||||
|
||||
ptedge = &pbedges[numbedges + 1];
|
||||
ptedge->pnext = psideedges[side];
|
||||
psideedges[side] = ptedge;
|
||||
ptedge->v[0] = ptvert;
|
||||
ptedge->v[1] = pvert;
|
||||
|
||||
numbedges += 2;
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
// entering for front, exiting for back
|
||||
pfrontenter = ptvert;
|
||||
makeclippededge = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pfrontexit = ptvert;
|
||||
makeclippededge = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add the edge to the appropriate side
|
||||
pedges->pnext = psideedges[side];
|
||||
psideedges[side] = pedges;
|
||||
}
|
||||
}
|
||||
|
||||
// if anything was clipped, reconstitute and add the edges along the clip
|
||||
// plane to both sides (but in opposite directions)
|
||||
if (makeclippededge)
|
||||
{
|
||||
if (numbedges >= (MAX_BMODEL_EDGES - 2))
|
||||
{
|
||||
R_Printf(PRINT_ALL,"Out of edges for bmodel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptedge = &pbedges[numbedges];
|
||||
ptedge->pnext = psideedges[0];
|
||||
psideedges[0] = ptedge;
|
||||
ptedge->v[0] = pfrontexit;
|
||||
ptedge->v[1] = pfrontenter;
|
||||
|
||||
ptedge = &pbedges[numbedges + 1];
|
||||
ptedge->pnext = psideedges[1];
|
||||
psideedges[1] = ptedge;
|
||||
ptedge->v[0] = pfrontenter;
|
||||
ptedge->v[1] = pfrontexit;
|
||||
|
||||
numbedges += 2;
|
||||
}
|
||||
|
||||
// draw or recurse further
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
if (psideedges[i])
|
||||
{
|
||||
// draw if we've reached a non-solid leaf, done if all that's left is a
|
||||
// solid leaf, and continue down the tree if it's not a leaf
|
||||
pn = pnode->children[i];
|
||||
|
||||
// we're done with this branch if the node or leaf isn't in the PVS
|
||||
if (pn->visframe == r_visframecount)
|
||||
{
|
||||
if (pn->contents != CONTENTS_NODE)
|
||||
{
|
||||
if (pn->contents != CONTENTS_SOLID)
|
||||
{
|
||||
if (r_newrefdef.areabits)
|
||||
{
|
||||
area = ((mleaf_t *)pn)->area;
|
||||
if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) )
|
||||
continue; // not visible
|
||||
}
|
||||
|
||||
r_currentbkey = ((mleaf_t *)pn)->key;
|
||||
R_RenderBmodelFace (psideedges[i], psurf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
|
||||
psurf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSolidClippedSubmodelPolygons
|
||||
|
||||
Bmodel crosses multiple leafs
|
||||
================
|
||||
*/
|
||||
void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
|
||||
{
|
||||
int i, j, lindex;
|
||||
vec_t dot;
|
||||
msurface_t *psurf;
|
||||
int numsurfaces;
|
||||
bedge_t *pbedge;
|
||||
medge_t *pedge, *pedges;
|
||||
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||
numsurfaces = pmodel->nummodelsurfaces;
|
||||
pedges = pmodel->edges;
|
||||
|
||||
for (i=0 ; i<numsurfaces ; i++, psurf++)
|
||||
{
|
||||
mplane_t *pplane;
|
||||
|
||||
// find which side of the node we are on
|
||||
pplane = psurf->plane;
|
||||
|
||||
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
|
||||
|
||||
// draw the polygon
|
||||
if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
||||
((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
||||
continue;
|
||||
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
|
||||
// copy the edges to bedges, flipping if necessary so always
|
||||
// clockwise winding
|
||||
// FIXME: if edges and vertices get caches, these assignments must move
|
||||
// outside the loop, and overflow checking must be done here
|
||||
pbverts = bverts;
|
||||
pbedges = bedges;
|
||||
numbverts = numbedges = 0;
|
||||
pbedge = &bedges[numbedges];
|
||||
numbedges += psurf->numedges;
|
||||
|
||||
for (j=0 ; j<psurf->numedges ; j++)
|
||||
{
|
||||
lindex = pmodel->surfedges[psurf->firstedge+j];
|
||||
|
||||
if (lindex > 0)
|
||||
{
|
||||
pedge = &pedges[lindex];
|
||||
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
|
||||
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
|
||||
}
|
||||
else
|
||||
{
|
||||
lindex = -lindex;
|
||||
pedge = &pedges[lindex];
|
||||
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
|
||||
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
|
||||
}
|
||||
|
||||
pbedge[j].pnext = &pbedge[j+1];
|
||||
}
|
||||
|
||||
pbedge[j-1].pnext = NULL; // mark end of edges
|
||||
|
||||
if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
|
||||
R_RecursiveClipBPoly (pbedge, topnode, psurf);
|
||||
else
|
||||
R_RenderBmodelFace( pbedge, psurf );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSubmodelPolygons
|
||||
|
||||
All in one leaf
|
||||
================
|
||||
*/
|
||||
void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
|
||||
{
|
||||
int i;
|
||||
vec_t dot;
|
||||
msurface_t *psurf;
|
||||
int numsurfaces;
|
||||
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||
numsurfaces = pmodel->nummodelsurfaces;
|
||||
|
||||
for (i=0 ; i<numsurfaces ; i++, psurf++)
|
||||
{
|
||||
mplane_t *pplane;
|
||||
// find which side of the node we are on
|
||||
pplane = psurf->plane;
|
||||
|
||||
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
|
||||
|
||||
// draw the polygon
|
||||
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
||||
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
||||
{
|
||||
r_currentkey = ((mleaf_t *)topnode)->key;
|
||||
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
R_RenderFace (psurf, clipflags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int c_drawnode;
|
||||
|
||||
/*
|
||||
================
|
||||
R_RecursiveWorldNode
|
||||
================
|
||||
*/
|
||||
void R_RecursiveWorldNode (mnode_t *node, int clipflags)
|
||||
{
|
||||
int c;
|
||||
vec3_t acceptpt, rejectpt;
|
||||
mleaf_t *pleaf;
|
||||
|
||||
if (node->contents == CONTENTS_SOLID)
|
||||
return; // solid
|
||||
|
||||
if (node->visframe != r_visframecount)
|
||||
return;
|
||||
|
||||
// cull the clipping planes if not trivial accept
|
||||
// FIXME: the compiler is doing a lousy job of optimizing here; it could be
|
||||
// twice as fast in ASM
|
||||
if (clipflags)
|
||||
{
|
||||
int i;
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
int *pindex;
|
||||
float d;
|
||||
if (! (clipflags & (1<<i)) )
|
||||
continue; // don't need to clip against it
|
||||
|
||||
// generate accept and reject points
|
||||
// FIXME: do with fast look-ups or integer tests based on the sign bit
|
||||
// of the floating point values
|
||||
|
||||
pindex = pfrustum_indexes[i];
|
||||
|
||||
rejectpt[0] = (float)node->minmaxs[pindex[0]];
|
||||
rejectpt[1] = (float)node->minmaxs[pindex[1]];
|
||||
rejectpt[2] = (float)node->minmaxs[pindex[2]];
|
||||
|
||||
d = DotProduct (rejectpt, view_clipplanes[i].normal);
|
||||
d -= view_clipplanes[i].dist;
|
||||
if (d <= 0)
|
||||
return;
|
||||
acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
|
||||
acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
|
||||
acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
|
||||
|
||||
d = DotProduct (acceptpt, view_clipplanes[i].normal);
|
||||
d -= view_clipplanes[i].dist;
|
||||
|
||||
if (d >= 0)
|
||||
clipflags &= ~(1<<i); // node is entirely on screen
|
||||
}
|
||||
}
|
||||
|
||||
c_drawnode++;
|
||||
|
||||
// if a leaf node, draw stuff
|
||||
if (node->contents != -1)
|
||||
{
|
||||
msurface_t **mark;
|
||||
pleaf = (mleaf_t *)node;
|
||||
|
||||
// check for door connected areas
|
||||
if (r_newrefdef.areabits)
|
||||
{
|
||||
if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
|
||||
return; // not visible
|
||||
}
|
||||
|
||||
mark = pleaf->firstmarksurface;
|
||||
c = pleaf->nummarksurfaces;
|
||||
|
||||
if (c)
|
||||
{
|
||||
do
|
||||
{
|
||||
(*mark)->visframe = r_framecount;
|
||||
mark++;
|
||||
} while (--c);
|
||||
}
|
||||
|
||||
pleaf->key = r_currentkey;
|
||||
r_currentkey++; // all bmodels in a leaf share the same key
|
||||
}
|
||||
else
|
||||
{
|
||||
float dot;
|
||||
int side;
|
||||
mplane_t *plane;
|
||||
|
||||
// node is just a decision point, so go down the apropriate sides
|
||||
// find which side of the node we are on
|
||||
plane = node->plane;
|
||||
|
||||
switch (plane->type)
|
||||
{
|
||||
case PLANE_X:
|
||||
dot = modelorg[0] - plane->dist;
|
||||
break;
|
||||
case PLANE_Y:
|
||||
dot = modelorg[1] - plane->dist;
|
||||
break;
|
||||
case PLANE_Z:
|
||||
dot = modelorg[2] - plane->dist;
|
||||
break;
|
||||
default:
|
||||
dot = DotProduct (modelorg, plane->normal) - plane->dist;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dot >= 0)
|
||||
side = 0;
|
||||
else
|
||||
side = 1;
|
||||
|
||||
// recurse down the children, front side first
|
||||
R_RecursiveWorldNode (node->children[side], clipflags);
|
||||
|
||||
// draw stuff
|
||||
c = node->numsurfaces;
|
||||
|
||||
if (c)
|
||||
{
|
||||
msurface_t *surf;
|
||||
|
||||
surf = r_worldmodel->surfaces + node->firstsurface;
|
||||
|
||||
if (dot < -BACKFACE_EPSILON)
|
||||
{
|
||||
do
|
||||
{
|
||||
if ((surf->flags & SURF_PLANEBACK) &&
|
||||
(surf->visframe == r_framecount))
|
||||
{
|
||||
R_RenderFace (surf, clipflags);
|
||||
}
|
||||
|
||||
surf++;
|
||||
} while (--c);
|
||||
}
|
||||
else if (dot > BACKFACE_EPSILON)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!(surf->flags & SURF_PLANEBACK) &&
|
||||
(surf->visframe == r_framecount))
|
||||
{
|
||||
R_RenderFace (surf, clipflags);
|
||||
}
|
||||
|
||||
surf++;
|
||||
} while (--c);
|
||||
}
|
||||
|
||||
// all surfaces on the same node share the same sequence number
|
||||
r_currentkey++;
|
||||
}
|
||||
|
||||
// recurse down the back side
|
||||
R_RecursiveWorldNode (node->children[!side], clipflags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RenderWorld
|
||||
================
|
||||
*/
|
||||
void R_RenderWorld (void)
|
||||
{
|
||||
|
||||
if (!r_drawworld->value)
|
||||
return;
|
||||
if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
|
||||
return;
|
||||
|
||||
c_drawnode=0;
|
||||
|
||||
// auto cycle the world frame for texture animation
|
||||
r_worldentity.frame = (int)(r_newrefdef.time*2);
|
||||
currententity = &r_worldentity;
|
||||
|
||||
VectorCopy (r_origin, modelorg);
|
||||
currentmodel = r_worldmodel;
|
||||
r_pcurrentvertbase = currentmodel->vertexes;
|
||||
|
||||
R_RecursiveWorldNode (currentmodel->nodes, 15);
|
||||
}
|
424
src/client/refresh/soft/r_draw.c
Normal file
424
src/client/refresh/soft/r_draw.c
Normal file
|
@ -0,0 +1,424 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// draw.c
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
|
||||
image_t *draw_chars; // 8*8 graphic characters
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_FindPic
|
||||
================
|
||||
*/
|
||||
image_t *Draw_FindPic (char *name)
|
||||
{
|
||||
image_t *image;
|
||||
|
||||
if (name[0] != '/' && name[0] != '\\')
|
||||
{
|
||||
char fullname[MAX_QPATH];
|
||||
|
||||
Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
|
||||
image = R_FindImage (fullname, it_pic);
|
||||
}
|
||||
else
|
||||
image = R_FindImage (name+1, it_pic);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Draw_InitLocal
|
||||
===============
|
||||
*/
|
||||
void Draw_InitLocal (void)
|
||||
{
|
||||
draw_chars = Draw_FindPic ("conchars");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_Char
|
||||
|
||||
Draws one 8*8 graphics character
|
||||
It can be clipped to the top of the screen to allow the console to be
|
||||
smoothly scrolled off.
|
||||
================
|
||||
*/
|
||||
void Draw_CharScaled(int x, int y, int num, float scale)
|
||||
{
|
||||
pixel_t *dest;
|
||||
byte *source;
|
||||
int drawline;
|
||||
int row, col, u, xpos, ypos, iscale;
|
||||
|
||||
iscale = (int) scale;
|
||||
|
||||
num &= 255;
|
||||
|
||||
if (num == 32 || num == 32+128)
|
||||
return;
|
||||
|
||||
if (y <= -8)
|
||||
return; // totally off screen
|
||||
|
||||
// if ( ( y + 8 ) >= vid.height )
|
||||
if ( ( y + 8 ) > vid.height ) // PGM - status text was missing in sw...
|
||||
return;
|
||||
|
||||
row = num>>4;
|
||||
col = num&15;
|
||||
source = draw_chars->pixels[0] + (row<<10) + (col<<3);
|
||||
|
||||
if (y < 0)
|
||||
{ // clipped
|
||||
drawline = 8 + y;
|
||||
source -= 128*y;
|
||||
y = 0;
|
||||
}
|
||||
else
|
||||
drawline = 8;
|
||||
|
||||
dest = vid_buffer + y * vid.width + x;
|
||||
|
||||
while (drawline--)
|
||||
{
|
||||
for (ypos=0; ypos < iscale; ypos ++)
|
||||
{
|
||||
for(u=0; u < 8; u++)
|
||||
{
|
||||
if (source[u] != TRANSPARENT_COLOR)
|
||||
for (xpos=0; xpos < iscale; xpos ++)
|
||||
{
|
||||
dest[u * iscale + xpos] = source[u];
|
||||
}
|
||||
}
|
||||
dest += vid.width;
|
||||
}
|
||||
source += 128;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_GetPicSize
|
||||
=============
|
||||
*/
|
||||
void Draw_GetPicSize (int *w, int *h, char *pic)
|
||||
{
|
||||
image_t *gl;
|
||||
|
||||
gl = Draw_FindPic (pic);
|
||||
if (!gl)
|
||||
{
|
||||
*w = *h = -1;
|
||||
return;
|
||||
}
|
||||
*w = gl->width;
|
||||
*h = gl->height;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_StretchPicImplementation
|
||||
=============
|
||||
*/
|
||||
void Draw_StretchPicImplementation (int x, int y, int w, int h, image_t *pic)
|
||||
{
|
||||
pixel_t *dest;
|
||||
byte *source;
|
||||
int v, u;
|
||||
int height;
|
||||
int f, fstep;
|
||||
int skip;
|
||||
|
||||
if ((x < 0) ||
|
||||
(x + w > vid.width) ||
|
||||
(y + h > vid.height))
|
||||
{
|
||||
ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
|
||||
}
|
||||
|
||||
height = h;
|
||||
if (y < 0)
|
||||
{
|
||||
skip = -y;
|
||||
height += y;
|
||||
y = 0;
|
||||
}
|
||||
else
|
||||
skip = 0;
|
||||
|
||||
dest = vid_buffer + y * vid.width + x;
|
||||
|
||||
for (v=0 ; v<height ; v++, dest += vid.width)
|
||||
{
|
||||
int sv = (skip + v)*pic->height/h;
|
||||
source = pic->pixels[0] + sv*pic->width;
|
||||
if (w == pic->width)
|
||||
memcpy (dest, source, w);
|
||||
else
|
||||
{
|
||||
f = 0;
|
||||
fstep = pic->width*0x10000/w;
|
||||
for (u=0 ; u<w ; u++)
|
||||
{
|
||||
dest[u] = source[f>>16];
|
||||
f += fstep;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_StretchPic
|
||||
=============
|
||||
*/
|
||||
void Draw_StretchPic (int x, int y, int w, int h, char *name)
|
||||
{
|
||||
image_t *pic;
|
||||
|
||||
pic = Draw_FindPic (name);
|
||||
if (!pic)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Can't find pic: %s\n", name);
|
||||
return;
|
||||
}
|
||||
Draw_StretchPicImplementation (x, y, w, h, pic);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_StretchRaw
|
||||
=============
|
||||
*/
|
||||
void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
|
||||
{
|
||||
image_t pic;
|
||||
|
||||
pic.pixels[0] = data;
|
||||
pic.width = cols;
|
||||
pic.height = rows;
|
||||
Draw_StretchPicImplementation (x, y, w, h, &pic);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_Pic
|
||||
=============
|
||||
*/
|
||||
void Draw_PicScaled(int x, int y, char *name, float scale)
|
||||
{
|
||||
image_t *pic;
|
||||
pixel_t *dest;
|
||||
byte *source;
|
||||
int v, u, xpos, ypos, iscale;
|
||||
int height;
|
||||
|
||||
iscale = (int)scale;
|
||||
pic = Draw_FindPic (name);
|
||||
if (!pic)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Can't find pic: %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((x < 0) ||
|
||||
(x + pic->width > vid.width) ||
|
||||
(y + pic->height > vid.height))
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Draw_Pic: bad coordinates\n");
|
||||
return;
|
||||
}
|
||||
|
||||
height = pic->height;
|
||||
source = pic->pixels[0];
|
||||
if (y < 0)
|
||||
{
|
||||
height += y;
|
||||
source += pic->width*-y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
dest = vid_buffer + y * vid.width + x;
|
||||
|
||||
if (!pic->transparent)
|
||||
{
|
||||
for (v=0; v<height; v++)
|
||||
{
|
||||
for(ypos=0; ypos < iscale; ypos++)
|
||||
{
|
||||
for (u=0; u<pic->width; u++)
|
||||
{
|
||||
for(xpos=0; xpos < iscale; xpos++)
|
||||
{
|
||||
dest[u * iscale + xpos] = source[u];
|
||||
}
|
||||
}
|
||||
dest += vid.width;
|
||||
}
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (v=0; v<height; v++)
|
||||
{
|
||||
for(ypos=0; ypos < iscale; ypos++)
|
||||
{
|
||||
for (u=0; u<pic->width; u++)
|
||||
{
|
||||
if (source[u] != TRANSPARENT_COLOR)
|
||||
for(xpos=0; xpos < iscale; xpos++)
|
||||
{
|
||||
dest[u * iscale + xpos] = source[u];
|
||||
}
|
||||
}
|
||||
dest += vid.width;
|
||||
}
|
||||
source += pic->width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_TileClear
|
||||
|
||||
This repeats a 64*64 tile graphic to fill the screen around a sized down
|
||||
refresh window.
|
||||
=============
|
||||
*/
|
||||
void Draw_TileClear (int x, int y, int w, int h, char *name)
|
||||
{
|
||||
int i, j;
|
||||
byte *psrc;
|
||||
pixel_t *pdest;
|
||||
image_t *pic;
|
||||
int x2;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
w += x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
h += y;
|
||||
y = 0;
|
||||
}
|
||||
if (x + w > vid.width)
|
||||
w = vid.width - x;
|
||||
if (y + h > vid.height)
|
||||
h = vid.height - y;
|
||||
if (w <= 0 || h <= 0)
|
||||
return;
|
||||
|
||||
pic = Draw_FindPic (name);
|
||||
if (!pic)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "Can't find pic: %s\n", name);
|
||||
return;
|
||||
}
|
||||
x2 = x + w;
|
||||
pdest = vid_buffer + y * vid.width;
|
||||
for (i=0 ; i<h ; i++, pdest += vid.width)
|
||||
{
|
||||
psrc = pic->pixels[0] + pic->width * ((i+y)&63);
|
||||
for (j=x ; j<x2 ; j++)
|
||||
pdest[j] = psrc[j&63];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
Draw_Fill
|
||||
|
||||
Fills a box of pixels with a single color
|
||||
=============
|
||||
*/
|
||||
void Draw_Fill (int x, int y, int w, int h, int c)
|
||||
{
|
||||
pixel_t *dest;
|
||||
int u, v;
|
||||
|
||||
if (x+w > vid.width)
|
||||
w = vid.width - x;
|
||||
if (y+h > vid.height)
|
||||
h = vid.height - y;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
w += x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
h += y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (w < 0 || h < 0)
|
||||
return;
|
||||
|
||||
dest = vid_buffer + y * vid.width + x;
|
||||
for (v=0 ; v<h ; v++, dest += vid.width)
|
||||
for (u=0 ; u<w ; u++)
|
||||
dest[u] = c;
|
||||
}
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_FadeScreen
|
||||
|
||||
================
|
||||
*/
|
||||
void Draw_FadeScreen (void)
|
||||
{
|
||||
int x,y;
|
||||
|
||||
for (y=0 ; y<vid.height ; y++)
|
||||
{
|
||||
int t;
|
||||
pixel_t *pbuf;
|
||||
|
||||
pbuf = vid_buffer + vid.width * y;
|
||||
t = (y & 1) << 1;
|
||||
|
||||
for (x=0 ; x<vid.width ; x++)
|
||||
{
|
||||
if ((x & 3) != t)
|
||||
pbuf[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
1048
src/client/refresh/soft/r_edge.c
Normal file
1048
src/client/refresh/soft/r_edge.c
Normal file
File diff suppressed because it is too large
Load diff
315
src/client/refresh/soft/r_image.c
Normal file
315
src/client/refresh/soft/r_image.c
Normal file
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
|
||||
#define MAX_RIMAGES 1024
|
||||
image_t r_images[MAX_RIMAGES];
|
||||
int numr_images;
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ImageList_f
|
||||
===============
|
||||
*/
|
||||
void R_ImageList_f (void)
|
||||
{
|
||||
int i;
|
||||
image_t *image;
|
||||
int texels;
|
||||
|
||||
R_Printf(PRINT_ALL, "------------------\n");
|
||||
texels = 0;
|
||||
|
||||
for (i=0, image=r_images ; i<numr_images ; i++, image++)
|
||||
{
|
||||
if (image->registration_sequence <= 0)
|
||||
continue;
|
||||
texels += image->width*image->height;
|
||||
switch (image->type)
|
||||
{
|
||||
case it_skin:
|
||||
R_Printf(PRINT_ALL, "M");
|
||||
break;
|
||||
case it_sprite:
|
||||
R_Printf(PRINT_ALL, "S");
|
||||
break;
|
||||
case it_wall:
|
||||
R_Printf(PRINT_ALL, "W");
|
||||
break;
|
||||
case it_pic:
|
||||
R_Printf(PRINT_ALL, "P");
|
||||
break;
|
||||
default:
|
||||
R_Printf(PRINT_ALL, " ");
|
||||
break;
|
||||
}
|
||||
|
||||
R_Printf(PRINT_ALL, " %3i %3i : %s\n",
|
||||
image->width, image->height, image->name);
|
||||
}
|
||||
R_Printf(PRINT_ALL, "Total texel count: %i\n", texels);
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
|
||||
image_t *R_FindFreeImage (void)
|
||||
{
|
||||
image_t *image;
|
||||
int i;
|
||||
|
||||
// find a free image_t
|
||||
for (i=0, image=r_images ; i<numr_images ; i++,image++)
|
||||
{
|
||||
if (!image->registration_sequence)
|
||||
break;
|
||||
}
|
||||
if (i == numr_images)
|
||||
{
|
||||
if (numr_images == MAX_RIMAGES)
|
||||
ri.Sys_Error (ERR_DROP, "MAX_RIMAGES");
|
||||
numr_images++;
|
||||
}
|
||||
image = &r_images[i];
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_LoadPic
|
||||
|
||||
================
|
||||
*/
|
||||
image_t *R_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
|
||||
{
|
||||
image_t *image;
|
||||
int i, c;
|
||||
|
||||
image = R_FindFreeImage ();
|
||||
if (strlen(name) >= sizeof(image->name))
|
||||
ri.Sys_Error(ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name);
|
||||
strcpy (image->name, name);
|
||||
image->registration_sequence = registration_sequence;
|
||||
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->type = type;
|
||||
|
||||
c = width*height;
|
||||
image->pixels[0] = malloc (c);
|
||||
image->transparent = false;
|
||||
for (i=0 ; i<c ; i++)
|
||||
{
|
||||
int b;
|
||||
|
||||
b = pic[i];
|
||||
if (b == 255)
|
||||
image->transparent = true;
|
||||
image->pixels[0][i] = b;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_LoadWal
|
||||
================
|
||||
*/
|
||||
image_t *R_LoadWal (char *name)
|
||||
{
|
||||
miptex_t *mt;
|
||||
int ofs;
|
||||
image_t *image;
|
||||
int size;
|
||||
|
||||
ri.FS_LoadFile (name, (void **)&mt);
|
||||
if (!mt)
|
||||
{
|
||||
R_Printf(PRINT_ALL, "R_LoadWal: can't load %s\n", name);
|
||||
return r_notexture_mip;
|
||||
}
|
||||
|
||||
image = R_FindFreeImage ();
|
||||
strcpy (image->name, name);
|
||||
image->width = LittleLong (mt->width);
|
||||
image->height = LittleLong (mt->height);
|
||||
image->type = it_wall;
|
||||
image->registration_sequence = registration_sequence;
|
||||
|
||||
size = image->width*image->height * (256+64+16+4)/256;
|
||||
image->pixels[0] = malloc (size);
|
||||
image->pixels[1] = image->pixels[0] + image->width*image->height;
|
||||
image->pixels[2] = image->pixels[1] + image->width*image->height/4;
|
||||
image->pixels[3] = image->pixels[2] + image->width*image->height/16;
|
||||
|
||||
ofs = LittleLong (mt->offsets[0]);
|
||||
memcpy ( image->pixels[0], (byte *)mt + ofs, size);
|
||||
|
||||
ri.FS_FreeFile ((void *)mt);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_FindImage
|
||||
|
||||
Finds or loads the given image
|
||||
===============
|
||||
*/
|
||||
image_t *R_FindImage (char *name, imagetype_t type)
|
||||
{
|
||||
image_t *image;
|
||||
int i, len;
|
||||
byte *pic, *palette;
|
||||
int width, height;
|
||||
char *ptr;
|
||||
|
||||
if (!name)
|
||||
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name");
|
||||
len = strlen(name);
|
||||
if (len<5)
|
||||
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name);
|
||||
|
||||
#ifndef _WIN32
|
||||
// fix backslashes
|
||||
while ((ptr=strchr(name,'\\'))) {
|
||||
*ptr = '/';
|
||||
}
|
||||
#endif
|
||||
|
||||
// look for it
|
||||
for (i=0, image=r_images ; i<numr_images ; i++,image++)
|
||||
{
|
||||
if (!strcmp(name, image->name))
|
||||
{
|
||||
image->registration_sequence = registration_sequence;
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// load the pic from disk
|
||||
//
|
||||
pic = NULL;
|
||||
palette = NULL;
|
||||
if (!strcmp(name+len-4, ".pcx"))
|
||||
{
|
||||
LoadPCX (name, &pic, &palette, &width, &height);
|
||||
if (!pic)
|
||||
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s", name);
|
||||
image = R_LoadPic (name, pic, width, height, type);
|
||||
}
|
||||
else if (!strcmp(name+len-4, ".wal"))
|
||||
{
|
||||
image = R_LoadWal (name);
|
||||
}
|
||||
else if (!strcmp(name+len-4, ".tga"))
|
||||
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s in software renderer", name);
|
||||
else
|
||||
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad extension on: %s", name);
|
||||
|
||||
if (pic)
|
||||
free(pic);
|
||||
if (palette)
|
||||
free(palette);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_RegisterSkin
|
||||
===============
|
||||
*/
|
||||
struct image_s *R_RegisterSkin (char *name)
|
||||
{
|
||||
return R_FindImage (name, it_skin);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_FreeUnusedImages
|
||||
|
||||
Any image that was not touched on this registration sequence
|
||||
will be freed.
|
||||
================
|
||||
*/
|
||||
void R_FreeUnusedImages (void)
|
||||
{
|
||||
int i;
|
||||
image_t *image;
|
||||
|
||||
for (i=0, image=r_images ; i<numr_images ; i++, image++)
|
||||
{
|
||||
if (image->registration_sequence == registration_sequence)
|
||||
{
|
||||
Com_PageInMemory ((byte *)image->pixels[0], image->width*image->height);
|
||||
continue; // used this sequence
|
||||
}
|
||||
if (!image->registration_sequence)
|
||||
continue; // free texture
|
||||
if (image->type == it_pic)
|
||||
continue; // don't free pics
|
||||
// free it
|
||||
free (image->pixels[0]); // the other mip levels just follow
|
||||
memset (image, 0, sizeof(*image));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_InitImages
|
||||
===============
|
||||
*/
|
||||
void R_InitImages (void)
|
||||
{
|
||||
registration_sequence = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ShutdownImages
|
||||
===============
|
||||
*/
|
||||
void R_ShutdownImages (void)
|
||||
{
|
||||
int i;
|
||||
image_t *image;
|
||||
|
||||
for (i=0, image=r_images ; i<numr_images ; i++, image++)
|
||||
{
|
||||
if (!image->registration_sequence)
|
||||
continue; // free texture
|
||||
// free it
|
||||
free (image->pixels[0]); // the other mip levels just follow
|
||||
memset (image, 0, sizeof(*image));
|
||||
}
|
||||
}
|
446
src/client/refresh/soft/r_light.c
Normal file
446
src/client/refresh/soft/r_light.c
Normal file
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_light.c
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
int r_dlightframecount;
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
DYNAMIC LIGHTS
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=============
|
||||
R_MarkLights
|
||||
=============
|
||||
*/
|
||||
void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
|
||||
{
|
||||
mplane_t *splitplane;
|
||||
float dist;
|
||||
msurface_t *surf;
|
||||
int i;
|
||||
|
||||
if (node->contents != -1)
|
||||
return;
|
||||
|
||||
splitplane = node->plane;
|
||||
dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
|
||||
|
||||
//=====
|
||||
//PGM
|
||||
i=light->intensity;
|
||||
if(i<0)
|
||||
i=-i;
|
||||
//PGM
|
||||
//=====
|
||||
|
||||
if (dist > i) // PGM (dist > light->intensity)
|
||||
{
|
||||
R_MarkLights (light, bit, node->children[0]);
|
||||
return;
|
||||
}
|
||||
if (dist < -i) // PGM (dist < -light->intensity)
|
||||
{
|
||||
R_MarkLights (light, bit, node->children[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// mark the polygons
|
||||
surf = r_worldmodel->surfaces + node->firstsurface;
|
||||
for (i=0 ; i<node->numsurfaces ; i++, surf++)
|
||||
{
|
||||
if (surf->dlightframe != r_dlightframecount)
|
||||
{
|
||||
surf->dlightbits = 0;
|
||||
surf->dlightframe = r_dlightframecount;
|
||||
}
|
||||
surf->dlightbits |= bit;
|
||||
}
|
||||
|
||||
R_MarkLights (light, bit, node->children[0]);
|
||||
R_MarkLights (light, bit, node->children[1]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PushDlights
|
||||
=============
|
||||
*/
|
||||
void R_PushDlights (model_t *model)
|
||||
{
|
||||
int i;
|
||||
dlight_t *l;
|
||||
|
||||
r_dlightframecount = r_framecount;
|
||||
for (i=0, l = r_newrefdef.dlights ; i<r_newrefdef.num_dlights ; i++, l++)
|
||||
{
|
||||
R_MarkLights ( l, 1<<i,
|
||||
model->nodes + model->firstnode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
LIGHT SAMPLING
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
vec3_t pointcolor;
|
||||
mplane_t *lightplane; // used as shadow plane
|
||||
vec3_t lightspot;
|
||||
|
||||
int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
|
||||
{
|
||||
float front, back, frac;
|
||||
qboolean side;
|
||||
mplane_t *plane;
|
||||
vec3_t mid;
|
||||
msurface_t *surf;
|
||||
int s, t, ds, dt;
|
||||
int i;
|
||||
mtexinfo_t *tex;
|
||||
byte *lightmap;
|
||||
float *scales;
|
||||
int maps;
|
||||
float samp;
|
||||
int r;
|
||||
|
||||
if (node->contents != -1)
|
||||
return -1; // didn't hit anything
|
||||
|
||||
// calculate mid point
|
||||
|
||||
// FIXME: optimize for axial
|
||||
plane = node->plane;
|
||||
front = DotProduct (start, plane->normal) - plane->dist;
|
||||
back = DotProduct (end, plane->normal) - plane->dist;
|
||||
side = front < 0;
|
||||
|
||||
if ( (back < 0) == side)
|
||||
return RecursiveLightPoint (node->children[side], start, end);
|
||||
|
||||
frac = front / (front-back);
|
||||
mid[0] = start[0] + (end[0] - start[0])*frac;
|
||||
mid[1] = start[1] + (end[1] - start[1])*frac;
|
||||
mid[2] = start[2] + (end[2] - start[2])*frac;
|
||||
if (plane->type < 3) // axial planes
|
||||
mid[plane->type] = plane->dist;
|
||||
|
||||
// go down front side
|
||||
r = RecursiveLightPoint (node->children[side], start, mid);
|
||||
if (r >= 0)
|
||||
return r; // hit something
|
||||
|
||||
if ((back < 0) == side)
|
||||
return -1; // didn't hit anything
|
||||
|
||||
// check for impact on this node
|
||||
VectorCopy (mid, lightspot);
|
||||
lightplane = plane;
|
||||
|
||||
surf = r_worldmodel->surfaces + node->firstsurface;
|
||||
for (i=0 ; i<node->numsurfaces ; i++, surf++)
|
||||
{
|
||||
if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY))
|
||||
continue; // no lightmaps
|
||||
|
||||
tex = surf->texinfo;
|
||||
|
||||
s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
|
||||
t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];
|
||||
if (s < surf->texturemins[0] ||
|
||||
t < surf->texturemins[1])
|
||||
continue;
|
||||
|
||||
ds = s - surf->texturemins[0];
|
||||
dt = t - surf->texturemins[1];
|
||||
|
||||
if ( ds > surf->extents[0] || dt > surf->extents[1] )
|
||||
continue;
|
||||
|
||||
if (!surf->samples)
|
||||
return 0;
|
||||
|
||||
ds >>= 4;
|
||||
dt >>= 4;
|
||||
|
||||
lightmap = surf->samples;
|
||||
VectorCopy (vec3_origin, pointcolor);
|
||||
if (lightmap)
|
||||
{
|
||||
lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
|
||||
|
||||
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
|
||||
maps++)
|
||||
{
|
||||
samp = *lightmap * /* 0.5 * */ (1.0/255); // adjust for gl scale
|
||||
scales = r_newrefdef.lightstyles[surf->styles[maps]].rgb;
|
||||
VectorMA (pointcolor, samp, scales, pointcolor);
|
||||
lightmap += ((surf->extents[0]>>4)+1) *
|
||||
((surf->extents[1]>>4)+1);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// go down back side
|
||||
return RecursiveLightPoint (node->children[!side], mid, end);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_LightPoint
|
||||
===============
|
||||
*/
|
||||
void R_LightPoint (vec3_t p, vec3_t color)
|
||||
{
|
||||
vec3_t end;
|
||||
float r;
|
||||
int lnum;
|
||||
dlight_t *dl;
|
||||
vec3_t dist;
|
||||
|
||||
if (!r_worldmodel->lightdata)
|
||||
{
|
||||
color[0] = color[1] = color[2] = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
end[0] = p[0];
|
||||
end[1] = p[1];
|
||||
end[2] = p[2] - 2048;
|
||||
|
||||
r = RecursiveLightPoint (r_worldmodel->nodes, p, end);
|
||||
|
||||
if (r == -1)
|
||||
{
|
||||
VectorCopy (vec3_origin, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy (pointcolor, color);
|
||||
}
|
||||
|
||||
//
|
||||
// add dynamic lights
|
||||
//
|
||||
for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
|
||||
{
|
||||
float add;
|
||||
|
||||
dl = &r_newrefdef.dlights[lnum];
|
||||
VectorSubtract (currententity->origin,
|
||||
dl->origin,
|
||||
dist);
|
||||
add = dl->intensity - VectorLength(dist);
|
||||
add *= (1.0/256);
|
||||
if (add > 0)
|
||||
{
|
||||
VectorMA (color, add, dl->color, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
||||
|
||||
unsigned blocklights[1024]; // allow some very large lightmaps
|
||||
|
||||
/*
|
||||
===============
|
||||
R_AddDynamicLights
|
||||
===============
|
||||
*/
|
||||
void R_AddDynamicLights (void)
|
||||
{
|
||||
msurface_t *surf;
|
||||
int lnum;
|
||||
int sd, td;
|
||||
float dist, rad, minlight;
|
||||
vec3_t impact, local;
|
||||
int s, t;
|
||||
int i;
|
||||
int smax, tmax;
|
||||
mtexinfo_t *tex;
|
||||
dlight_t *dl;
|
||||
int negativeLight; //PGM
|
||||
|
||||
surf = r_drawsurf.surf;
|
||||
smax = (surf->extents[0]>>4)+1;
|
||||
tmax = (surf->extents[1]>>4)+1;
|
||||
tex = surf->texinfo;
|
||||
|
||||
for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
|
||||
{
|
||||
if (!(surf->dlightbits & (1<<lnum)))
|
||||
continue; // not lit by this light
|
||||
|
||||
dl = &r_newrefdef.dlights[lnum];
|
||||
rad = dl->intensity;
|
||||
|
||||
//=====
|
||||
//PGM
|
||||
negativeLight = 0;
|
||||
if(rad < 0)
|
||||
{
|
||||
negativeLight = 1;
|
||||
rad = -rad;
|
||||
}
|
||||
//PGM
|
||||
//=====
|
||||
|
||||
dist = DotProduct (dl->origin, surf->plane->normal) -
|
||||
surf->plane->dist;
|
||||
rad -= fabs(dist);
|
||||
minlight = 32; // dl->minlight;
|
||||
if (rad < minlight)
|
||||
continue;
|
||||
minlight = rad - minlight;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
impact[i] = dl->origin[i] -
|
||||
surf->plane->normal[i]*dist;
|
||||
}
|
||||
|
||||
local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
|
||||
local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
|
||||
|
||||
local[0] -= surf->texturemins[0];
|
||||
local[1] -= surf->texturemins[1];
|
||||
|
||||
for (t = 0 ; t<tmax ; t++)
|
||||
{
|
||||
td = local[1] - t*16;
|
||||
if (td < 0)
|
||||
td = -td;
|
||||
for (s=0 ; s<smax ; s++)
|
||||
{
|
||||
sd = local[0] - s*16;
|
||||
if (sd < 0)
|
||||
sd = -sd;
|
||||
if (sd > td)
|
||||
dist = sd + (td>>1);
|
||||
else
|
||||
dist = td + (sd>>1);
|
||||
|
||||
//====
|
||||
//PGM
|
||||
if(!negativeLight)
|
||||
{
|
||||
if (dist < minlight)
|
||||
blocklights[t*smax + s] += (rad - dist)*256;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dist < minlight)
|
||||
blocklights[t*smax + s] -= (rad - dist)*256;
|
||||
if(blocklights[t*smax + s] < minlight)
|
||||
blocklights[t*smax + s] = minlight;
|
||||
}
|
||||
//PGM
|
||||
//====
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_BuildLightMap
|
||||
|
||||
Combine and scale multiple lightmaps into the 8.8 format in blocklights
|
||||
===============
|
||||
*/
|
||||
void R_BuildLightMap (void)
|
||||
{
|
||||
int smax, tmax;
|
||||
int i, size;
|
||||
byte *lightmap;
|
||||
msurface_t *surf;
|
||||
|
||||
surf = r_drawsurf.surf;
|
||||
|
||||
smax = (surf->extents[0]>>4)+1;
|
||||
tmax = (surf->extents[1]>>4)+1;
|
||||
size = smax*tmax;
|
||||
|
||||
if (r_fullbright->value || !r_worldmodel->lightdata)
|
||||
{
|
||||
for (i=0 ; i<size ; i++)
|
||||
blocklights[i] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// clear to no light
|
||||
for (i=0 ; i<size ; i++)
|
||||
blocklights[i] = 0;
|
||||
|
||||
|
||||
// add all the lightmaps
|
||||
lightmap = surf->samples;
|
||||
if (lightmap)
|
||||
{
|
||||
int maps;
|
||||
|
||||
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
|
||||
maps++)
|
||||
{
|
||||
unsigned scale;
|
||||
|
||||
scale = r_drawsurf.lightadj[maps]; // 8.8 fraction
|
||||
for (i=0 ; i<size ; i++)
|
||||
blocklights[i] += lightmap[i] * scale;
|
||||
lightmap += size; // skip to next lightmap
|
||||
}
|
||||
}
|
||||
|
||||
// add all the dynamic lights
|
||||
if (surf->dlightframe == r_framecount)
|
||||
R_AddDynamicLights ();
|
||||
|
||||
// bound, invert, and shift
|
||||
for (i=0 ; i<size ; i++)
|
||||
{
|
||||
int t;
|
||||
|
||||
t = (int)blocklights[i];
|
||||
if (t < 0)
|
||||
t = 0;
|
||||
t = (255*256 - t) >> (8 - VID_CBITS);
|
||||
|
||||
if (t < (1 << 6))
|
||||
t = (1 << 6);
|
||||
|
||||
blocklights[i] = t;
|
||||
}
|
||||
}
|
755
src/client/refresh/soft/r_local.h
Normal file
755
src/client/refresh/soft/r_local.h
Normal file
|
@ -0,0 +1,755 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __R_LOCAL__
|
||||
#define __R_LOCAL__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../ref_shared.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define REF_VERSION "SOFT 0.01"
|
||||
|
||||
// up / down
|
||||
#define PITCH 0
|
||||
|
||||
// left / right
|
||||
#define YAW 1
|
||||
|
||||
// fall over
|
||||
#define ROLL 2
|
||||
|
||||
|
||||
/*
|
||||
|
||||
skins will be outline flood filled and mip mapped
|
||||
pics and sprites with alpha will be outline flood filled
|
||||
pic won't be mip mapped
|
||||
|
||||
model skin
|
||||
sprite frame
|
||||
wall texture
|
||||
pic
|
||||
|
||||
*/
|
||||
|
||||
typedef struct image_s
|
||||
{
|
||||
char name[MAX_QPATH]; // game path, including extension
|
||||
imagetype_t type;
|
||||
int width, height;
|
||||
qboolean transparent; // true if any 255 pixels in image
|
||||
int registration_sequence; // 0 = free
|
||||
byte *pixels[4]; // mip levels
|
||||
} image_t;
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
typedef unsigned char pixel_t;
|
||||
typedef int shift20_t;
|
||||
typedef int zvalue_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
rserr_ok,
|
||||
|
||||
rserr_invalid_fullscreen,
|
||||
rserr_invalid_mode,
|
||||
|
||||
rserr_unknown
|
||||
} rserr_t;
|
||||
|
||||
extern viddef_t vid;
|
||||
extern pixel_t *vid_buffer; // invisible buffer
|
||||
extern pixel_t *vid_colormap; // 256 * VID_GRADES size
|
||||
extern pixel_t *vid_alphamap; // 256 * 256 translucency map
|
||||
extern char shift_size; // shift size in fixed-point
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vrect_t vrect; // subwindow in video for refresh
|
||||
// FIXME: not need vrect next field here?
|
||||
vrect_t aliasvrect; // scaled Alias version
|
||||
shift20_t vrectright, vrectbottom; // right & bottom screen coords
|
||||
shift20_t aliasvrectright, aliasvrectbottom; // scaled Alias versions
|
||||
float vrectrightedge; // rightmost right edge we care about,
|
||||
// for use in edge list
|
||||
float fvrectx, fvrecty; // for floating-point compares
|
||||
float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping
|
||||
shift20_t vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20
|
||||
shift20_t vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20
|
||||
float fvrectright_adj, fvrectbottom_adj; // right and bottom edges, for clamping
|
||||
float fvrectright; // rightmost edge, for Alias clamping
|
||||
float fvrectbottom; // bottommost edge, for Alias clamping
|
||||
float horizontalFieldOfView; // at Z = 1.0, this many X is visible
|
||||
// 2.0 = 90 degrees
|
||||
float xOrigin; // should probably always be 0.5
|
||||
float yOrigin; // between be around 0.3 to 0.5
|
||||
|
||||
vec3_t vieworg;
|
||||
vec3_t viewangles;
|
||||
|
||||
int ambientlight;
|
||||
} oldrefdef_t;
|
||||
|
||||
extern oldrefdef_t r_refdef;
|
||||
|
||||
#include "r_model.h"
|
||||
|
||||
/*
|
||||
====================================================
|
||||
|
||||
CONSTANTS
|
||||
|
||||
====================================================
|
||||
*/
|
||||
|
||||
#define VID_CBITS 6
|
||||
#define VID_GRADES (1 << VID_CBITS)
|
||||
|
||||
|
||||
// r_shared.h: general refresh-related stuff shared between the refresh and the
|
||||
// driver
|
||||
|
||||
|
||||
#define MAXVERTS 64 // max points in a surface polygon
|
||||
#define MAXWORKINGVERTS (MAXVERTS+4) // max points in an intermediate
|
||||
// polygon (while processing)
|
||||
|
||||
#define WARP_WIDTH 320
|
||||
#define WARP_HEIGHT 240
|
||||
|
||||
#define PARTICLE_Z_CLIP 8.0
|
||||
|
||||
#define TRANSPARENT_COLOR 0xFF
|
||||
|
||||
#define TURB_TEX_SIZE 64 // base turbulent texture size
|
||||
|
||||
#define CYCLE 128 // turbulent cycle size
|
||||
|
||||
#define SCANBUFFERPAD 0x1000
|
||||
|
||||
#define DS_SPAN_LIST_END -128
|
||||
|
||||
#define NUMSTACKEDGES 2000
|
||||
#define MINEDGES NUMSTACKEDGES
|
||||
#define NUMSTACKSURFACES 1000
|
||||
#define MINSURFACES NUMSTACKSURFACES
|
||||
#define MAXSPANS 3000
|
||||
|
||||
// flags in finalvert_t.flags
|
||||
#define ALIAS_LEFT_CLIP 0x0001
|
||||
#define ALIAS_TOP_CLIP 0x0002
|
||||
#define ALIAS_RIGHT_CLIP 0x0004
|
||||
#define ALIAS_BOTTOM_CLIP 0x0008
|
||||
#define ALIAS_Z_CLIP 0x0010
|
||||
#define ALIAS_XY_CLIP_MASK 0x000F
|
||||
|
||||
#define SURFCACHE_SIZE_AT_320X240 1024*768
|
||||
|
||||
#define BMODEL_FULLY_CLIPPED 0x10 // value returned by R_BmodelCheckBBox ()
|
||||
// if bbox is trivially rejected
|
||||
|
||||
#define XCENTERING (1.0 / 2.0)
|
||||
#define YCENTERING (1.0 / 2.0)
|
||||
|
||||
#define CLIP_EPSILON 0.001
|
||||
|
||||
#define BACKFACE_EPSILON 0.01
|
||||
|
||||
#define NEAR_CLIP 0.01
|
||||
|
||||
|
||||
#define MAXALIASVERTS 2000 // TODO: tune this
|
||||
#define ALIAS_Z_CLIP_PLANE 4
|
||||
|
||||
// turbulence stuff
|
||||
#define AMP 8*0x10000
|
||||
#define AMP2 3
|
||||
#define SPEED 20
|
||||
|
||||
|
||||
/*
|
||||
====================================================
|
||||
|
||||
TYPES
|
||||
|
||||
====================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float u, v;
|
||||
float s, t;
|
||||
float zi;
|
||||
} emitpoint_t;
|
||||
|
||||
/*
|
||||
** if you change this structure be sure to change the #defines
|
||||
** listed after it!
|
||||
*/
|
||||
typedef struct finalvert_s {
|
||||
int u, v, s, t;
|
||||
int l;
|
||||
int zi;
|
||||
int flags;
|
||||
float xyz[3]; // eye space
|
||||
} finalvert_t;
|
||||
|
||||
#define FINALVERT_V0 0
|
||||
#define FINALVERT_V1 4
|
||||
#define FINALVERT_V2 8
|
||||
#define FINALVERT_V3 12
|
||||
#define FINALVERT_V4 16
|
||||
#define FINALVERT_V5 20
|
||||
#define FINALVERT_FLAGS 24
|
||||
#define FINALVERT_X 28
|
||||
#define FINALVERT_Y 32
|
||||
#define FINALVERT_Z 36
|
||||
#define FINALVERT_SIZE 40
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *pskin;
|
||||
int skinwidth;
|
||||
int skinheight;
|
||||
} affinetridesc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte *surfdat; // destination for generated surface
|
||||
int rowbytes; // destination logical width in bytes
|
||||
msurface_t *surf; // description for surface to generate
|
||||
fixed8_t lightadj[MAXLIGHTMAPS]; // adjust for lightmap levels for dynamic lighting
|
||||
image_t *image;
|
||||
int surfmip; // mipmapped ratio of surface texels / world pixels
|
||||
int surfwidth; // in mipmapped texels
|
||||
int surfheight; // in mipmapped texels
|
||||
} drawsurf_t;
|
||||
|
||||
typedef struct {
|
||||
int ambientlight;
|
||||
int shadelight;
|
||||
float *plightvec;
|
||||
} alight_t;
|
||||
|
||||
// clipped bmodel edges
|
||||
typedef struct bedge_s
|
||||
{
|
||||
mvertex_t *v[2];
|
||||
struct bedge_s *pnext;
|
||||
} bedge_t;
|
||||
|
||||
typedef struct clipplane_s
|
||||
{
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
struct clipplane_s *next;
|
||||
byte leftedge;
|
||||
byte rightedge;
|
||||
byte reserved[2];
|
||||
} clipplane_t;
|
||||
|
||||
typedef struct surfcache_s
|
||||
{
|
||||
struct surfcache_s *next;
|
||||
struct surfcache_s **owner; // NULL is an empty chunk of memory
|
||||
int lightadj[MAXLIGHTMAPS]; // checked for strobe flush
|
||||
int dlight;
|
||||
int size; // including header
|
||||
unsigned width;
|
||||
unsigned height; // DEBUG only needed for debug
|
||||
float mipscale;
|
||||
image_t *image;
|
||||
byte data[4]; // width*height elements
|
||||
} surfcache_t;
|
||||
|
||||
typedef struct espan_s
|
||||
{
|
||||
int u, v, count;
|
||||
struct espan_s *pnext;
|
||||
} espan_t;
|
||||
extern espan_t *vid_polygon_spans; // space for spans in r_poly
|
||||
|
||||
// used by the polygon drawer (R_POLY.C) and sprite setup code (R_SPRITE.C)
|
||||
typedef struct
|
||||
{
|
||||
int nump;
|
||||
emitpoint_t *pverts;
|
||||
byte *pixels; // image
|
||||
int pixel_width; // image width
|
||||
int pixel_height; // image height
|
||||
vec3_t vup, vright, vpn; // in worldspace, for plane eq
|
||||
float dist;
|
||||
float s_offset, t_offset;
|
||||
float viewer_position[3];
|
||||
void (*drawspanlet)(void);
|
||||
int stipple_parity;
|
||||
} polydesc_t;
|
||||
|
||||
// FIXME: compress, make a union if that will help
|
||||
// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
|
||||
typedef struct surf_s
|
||||
{
|
||||
struct surf_s *next; // active surface stack in r_edge.c
|
||||
struct surf_s *prev; // used in r_edge.c for active surf stack
|
||||
struct espan_s *spans; // pointer to linked list of spans to draw
|
||||
int key; // sorting key (BSP order)
|
||||
shift20_t last_u; // set during tracing
|
||||
int spanstate; // 0 = not in span
|
||||
// 1 = in span
|
||||
// -1 = in inverted span (end before
|
||||
// start)
|
||||
int flags; // currentface flags
|
||||
msurface_t *msurf;
|
||||
entity_t *entity;
|
||||
float nearzi; // nearest 1/z on surface, for mipmapping
|
||||
qboolean insubmodel;
|
||||
float d_ziorigin, d_zistepu, d_zistepv;
|
||||
|
||||
int pad[2]; // to 64 bytes
|
||||
} surf_t;
|
||||
|
||||
typedef struct edge_s
|
||||
{
|
||||
shift20_t u;
|
||||
shift20_t u_step;
|
||||
struct edge_s *prev, *next;
|
||||
unsigned short surfs[2];
|
||||
struct edge_s *nextremove;
|
||||
float nearzi;
|
||||
medge_t *owner;
|
||||
} edge_t;
|
||||
|
||||
|
||||
/*
|
||||
====================================================
|
||||
|
||||
VARS
|
||||
|
||||
====================================================
|
||||
*/
|
||||
extern int d_spanpixcount;
|
||||
extern int r_framecount; // sequence # of current frame since Quake
|
||||
// started
|
||||
extern float r_aliasuvscale; // scale-up factor for screen u and v
|
||||
// on Alias vertices passed to driver
|
||||
extern qboolean r_dowarp;
|
||||
|
||||
extern affinetridesc_t r_affinetridesc;
|
||||
|
||||
extern vec3_t r_pright, r_pup, r_ppn;
|
||||
|
||||
void D_DrawSurfaces(void);
|
||||
void R_DrawParticle(void);
|
||||
void D_ViewChanged(void);
|
||||
void D_WarpScreen(void);
|
||||
void R_PolysetUpdateTables(void);
|
||||
|
||||
//=======================================================================//
|
||||
|
||||
// callbacks to Quake
|
||||
|
||||
extern drawsurf_t r_drawsurf;
|
||||
|
||||
void R_DrawSurface(void);
|
||||
|
||||
extern int c_surf;
|
||||
|
||||
extern pixel_t *r_warpbuffer;
|
||||
|
||||
extern float scale_for_mip;
|
||||
|
||||
extern qboolean d_roverwrapped;
|
||||
extern surfcache_t *sc_rover;
|
||||
extern surfcache_t *d_initial_rover;
|
||||
|
||||
extern float d_sdivzstepu, d_tdivzstepu, d_zistepu;
|
||||
extern float d_sdivzstepv, d_tdivzstepv, d_zistepv;
|
||||
extern float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
|
||||
|
||||
extern int sadjust, tadjust;
|
||||
extern int bbextents, bbextentt;
|
||||
|
||||
|
||||
void D_DrawSpans16(espan_t *pspans);
|
||||
void D_DrawZSpans(espan_t *pspans);
|
||||
void Turbulent8(espan_t *pspan);
|
||||
void NonTurbulent8(espan_t *pspan); //PGM
|
||||
|
||||
surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel);
|
||||
|
||||
extern int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
|
||||
|
||||
extern int d_pix_min, d_pix_max, d_pix_shift;
|
||||
|
||||
extern pixel_t *d_viewbuffer;
|
||||
extern zvalue_t *d_pzbuffer;
|
||||
extern unsigned int d_zrowbytes, d_zwidth;
|
||||
|
||||
extern int d_minmip;
|
||||
extern float d_scalemip[3];
|
||||
|
||||
//===================================================================
|
||||
|
||||
extern int cachewidth;
|
||||
extern pixel_t *cacheblock;
|
||||
extern int r_screenwidth;
|
||||
|
||||
extern int r_drawnpolycount;
|
||||
|
||||
extern int *sintable;
|
||||
extern int *intsintable;
|
||||
extern int *blanktable; // PGM
|
||||
|
||||
extern vec3_t vup, base_vup;
|
||||
extern vec3_t vpn, base_vpn;
|
||||
extern vec3_t vright, base_vright;
|
||||
|
||||
extern surf_t *surfaces, *surface_p, *surf_max;
|
||||
|
||||
// surfaces are generated in back to front order by the bsp, so if a surf
|
||||
// pointer is greater than another one, it should be drawn in front
|
||||
// surfaces[1] is the background, and is used as the active surface stack.
|
||||
// surfaces[0] is a dummy, because index 0 is used to indicate no surface
|
||||
// attached to an edge_t
|
||||
|
||||
//===================================================================
|
||||
|
||||
extern vec3_t sxformaxis[4]; // s axis transformed into viewspace
|
||||
extern vec3_t txformaxis[4]; // t axis transformed into viewspac
|
||||
|
||||
extern float xcenter, ycenter;
|
||||
extern float xscale, yscale;
|
||||
extern float xscaleinv, yscaleinv;
|
||||
extern float xscaleshrink, yscaleshrink;
|
||||
|
||||
extern void TransformVector(vec3_t in, vec3_t out);
|
||||
extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
|
||||
fixed8_t endvertu, fixed8_t endvertv);
|
||||
|
||||
extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
|
||||
|
||||
//===========================================================================
|
||||
|
||||
extern cvar_t *sw_aliasstats;
|
||||
extern cvar_t *sw_clearcolor;
|
||||
extern cvar_t *sw_drawflat;
|
||||
extern cvar_t *sw_draworder;
|
||||
extern cvar_t *sw_maxedges;
|
||||
extern cvar_t *sw_maxsurfs;
|
||||
extern cvar_t *sw_mipcap;
|
||||
extern cvar_t *sw_mipscale;
|
||||
extern cvar_t *sw_mode;
|
||||
extern cvar_t *sw_reportsurfout;
|
||||
extern cvar_t *sw_reportedgeout;
|
||||
extern cvar_t *sw_stipplealpha;
|
||||
extern cvar_t *sw_surfcacheoverride;
|
||||
extern cvar_t *sw_waterwarp;
|
||||
|
||||
extern cvar_t *r_fullbright;
|
||||
extern cvar_t *r_lefthand;
|
||||
extern cvar_t *r_drawentities;
|
||||
extern cvar_t *r_drawworld;
|
||||
extern cvar_t *r_dspeeds;
|
||||
extern cvar_t *r_lerpmodels;
|
||||
|
||||
extern cvar_t *r_speeds;
|
||||
|
||||
extern cvar_t *r_lightlevel; //FIXME HACK
|
||||
|
||||
extern cvar_t *vid_fullscreen;
|
||||
extern cvar_t *vid_gamma;
|
||||
|
||||
|
||||
extern clipplane_t view_clipplanes[4];
|
||||
extern int *pfrustum_indexes[4];
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void R_RenderWorld(void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
extern mplane_t screenedge[4];
|
||||
|
||||
extern vec3_t r_origin;
|
||||
|
||||
extern entity_t r_worldentity;
|
||||
extern model_t *currentmodel;
|
||||
extern entity_t *currententity;
|
||||
extern vec3_t modelorg;
|
||||
extern vec3_t r_entorigin;
|
||||
|
||||
extern float verticalFieldOfView;
|
||||
extern float xOrigin, yOrigin;
|
||||
|
||||
extern int r_visframecount;
|
||||
|
||||
extern msurface_t *r_alpha_surfaces;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void R_ClearPolyList(void);
|
||||
void R_DrawPolyList(void);
|
||||
|
||||
//
|
||||
// current entity info
|
||||
//
|
||||
extern qboolean insubmodel;
|
||||
|
||||
void R_DrawAlphaSurfaces(void);
|
||||
|
||||
void R_DrawSprite(void);
|
||||
void R_DrawBeam(entity_t *e);
|
||||
|
||||
void R_RenderFace(msurface_t *fa, int clipflags);
|
||||
void R_RenderBmodelFace(bedge_t *pedges, msurface_t *psurf);
|
||||
void R_TransformPlane(mplane_t *p, float *normal, float *dist);
|
||||
void R_TransformFrustum(void);
|
||||
void R_DrawSurfaceBlock16(void);
|
||||
void R_DrawSurfaceBlock8(void);
|
||||
|
||||
void R_GenSkyTile(void *pdest);
|
||||
void R_GenSkyTile16(void *pdest);
|
||||
void R_Surf8Patch(void);
|
||||
void R_Surf16Patch(void);
|
||||
void R_DrawSubmodelPolygons(model_t *pmodel, int clipflags, mnode_t *topnode);
|
||||
void R_DrawSolidClippedSubmodelPolygons(model_t *pmodel, mnode_t *topnode);
|
||||
|
||||
void R_AddPolygonEdges(emitpoint_t *pverts, int numverts, int miplevel);
|
||||
surf_t *R_GetSurf(void);
|
||||
void R_AliasDrawModel(void);
|
||||
void R_BeginEdgeFrame(void);
|
||||
void R_ScanEdges(void);
|
||||
void D_DrawSurfaces(void);
|
||||
void R_InsertNewEdges(edge_t *edgestoadd, edge_t *edgelist);
|
||||
void R_StepActiveU(edge_t *pedge);
|
||||
void R_RemoveEdges(edge_t *pedge);
|
||||
void R_PushDlights(model_t *model);
|
||||
|
||||
extern void R_Surf8Start(void);
|
||||
extern void R_Surf8End(void);
|
||||
extern void R_Surf16Start(void);
|
||||
extern void R_Surf16End(void);
|
||||
extern void R_EdgeCodeStart (void);
|
||||
extern void R_EdgeCodeEnd (void);
|
||||
|
||||
extern void R_RotateBmodel (void);
|
||||
|
||||
extern int c_faceclip;
|
||||
extern int r_polycount;
|
||||
extern int r_wholepolycount;
|
||||
|
||||
extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
|
||||
|
||||
extern int sadjust, tadjust;
|
||||
extern int bbextents, bbextentt;
|
||||
|
||||
extern mvertex_t *r_ptverts, *r_ptvertsmax;
|
||||
|
||||
extern float entity_rotation[3][3];
|
||||
extern int r_currentkey;
|
||||
extern int r_currentbkey;
|
||||
|
||||
void R_InitTurb (void);
|
||||
|
||||
void R_DrawParticles (void);
|
||||
|
||||
extern int r_amodels_drawn;
|
||||
extern edge_t *auxedges;
|
||||
extern int r_numallocatededges;
|
||||
extern edge_t *r_edges, *edge_p, *edge_max;
|
||||
|
||||
extern edge_t **newedges;
|
||||
extern edge_t **removeedges;
|
||||
|
||||
typedef struct {
|
||||
pixel_t *pdest;
|
||||
zvalue_t *pz;
|
||||
int count;
|
||||
pixel_t *ptex;
|
||||
int sfrac, tfrac, light, zi;
|
||||
} spanpackage_t;
|
||||
extern spanpackage_t *triangle_spans;
|
||||
|
||||
extern byte **warp_rowptr;
|
||||
extern int *warp_column;
|
||||
extern espan_t *edge_basespans;
|
||||
extern finalvert_t *finalverts;
|
||||
|
||||
extern int r_aliasblendcolor;
|
||||
|
||||
extern float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
|
||||
|
||||
extern int r_outofsurfaces;
|
||||
extern int r_outofedges;
|
||||
|
||||
extern mvertex_t *r_pcurrentvertbase;
|
||||
extern int r_maxvalidedgeoffset;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
finalvert_t *a, *b, *c;
|
||||
} aliastriangleparms_t;
|
||||
|
||||
extern aliastriangleparms_t aliastriangleparms;
|
||||
|
||||
void R_DrawTriangle( void );
|
||||
//void R_DrawTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2);
|
||||
void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2);
|
||||
|
||||
|
||||
extern float r_time1;
|
||||
extern float da_time1, da_time2;
|
||||
extern float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
|
||||
extern float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
|
||||
extern int r_frustum_indexes[4*6];
|
||||
extern int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
|
||||
extern qboolean r_surfsonstack;
|
||||
|
||||
extern mleaf_t *r_viewleaf;
|
||||
extern int r_viewcluster, r_oldviewcluster;
|
||||
|
||||
extern int r_clipflags;
|
||||
extern int r_dlightframecount;
|
||||
extern qboolean r_fov_greater_than_90;
|
||||
|
||||
extern image_t *r_notexture_mip;
|
||||
extern model_t *r_worldmodel;
|
||||
|
||||
void R_PrintAliasStats (void);
|
||||
void R_PrintTimes (void);
|
||||
void R_PrintDSpeeds (void);
|
||||
void R_AnimateLight (void);
|
||||
void R_LightPoint (vec3_t p, vec3_t color);
|
||||
void R_SetupFrame (void);
|
||||
void R_cshift_f (void);
|
||||
void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1);
|
||||
void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip);
|
||||
void R_SplitEntityOnNode2 (mnode_t *node);
|
||||
|
||||
extern refdef_t r_newrefdef;
|
||||
|
||||
extern surfcache_t *sc_rover, *sc_base;
|
||||
|
||||
extern void *colormap;
|
||||
|
||||
//====================================================================
|
||||
|
||||
float R_DLightPoint (vec3_t p);
|
||||
|
||||
void R_NewMap (void);
|
||||
void R_Register (void);
|
||||
void R_UnRegister (void);
|
||||
void Draw_InitLocal(void);
|
||||
qboolean R_Init(void);
|
||||
void R_Shutdown(void);
|
||||
void R_InitCaches(void);
|
||||
void D_FlushCaches(void);
|
||||
|
||||
void R_ScreenShot_f( void );
|
||||
void R_BeginRegistration (char *map);
|
||||
struct model_s *R_RegisterModel (char *name);
|
||||
void R_EndRegistration (void);
|
||||
|
||||
void R_RenderFrame (refdef_t *fd);
|
||||
|
||||
struct image_s *Draw_FindPic (char *name);
|
||||
|
||||
void Draw_GetPicSize (int *w, int *h, char *name);
|
||||
void Draw_PicScaled (int x, int y, char *name, float factor);
|
||||
void Draw_StretchPic (int x, int y, int w, int h, char *name);
|
||||
void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data);
|
||||
void Draw_CharScaled (int x, int y, int c, float scale);
|
||||
void Draw_TileClear (int x, int y, int w, int h, char *name);
|
||||
void Draw_Fill (int x, int y, int w, int h, int c);
|
||||
void Draw_FadeScreen (void);
|
||||
|
||||
void Draw_GetPalette (void);
|
||||
|
||||
void R_BeginFrame( float camera_separation );
|
||||
|
||||
void R_SetPalette( const unsigned char *palette );
|
||||
|
||||
extern unsigned d_8to24table[256]; // base
|
||||
|
||||
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
|
||||
void Sys_SetFPCW (void);
|
||||
|
||||
void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height);
|
||||
|
||||
void R_InitImages(void);
|
||||
void R_ShutdownImages(void);
|
||||
image_t *R_FindImage(char *name, imagetype_t type);
|
||||
void R_FreeUnusedImages(void);
|
||||
|
||||
void R_GammaCorrectAndSetPalette(const unsigned char *pal);
|
||||
|
||||
extern mtexinfo_t *sky_texinfo[6];
|
||||
|
||||
void R_InitSkyBox(void);
|
||||
|
||||
typedef struct swstate_s
|
||||
{
|
||||
qboolean fullscreen;
|
||||
int prev_mode; // last valid SW mode
|
||||
|
||||
unsigned char gammatable[256];
|
||||
unsigned char currentpalette[1024];
|
||||
|
||||
} swstate_t;
|
||||
|
||||
void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha );
|
||||
|
||||
extern swstate_t sw_state;
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
|
||||
IMPORTED FUNCTIONS
|
||||
|
||||
====================================================================
|
||||
*/
|
||||
extern refimport_t ri;
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
|
||||
IMPLEMENTATION FUNCTIONS
|
||||
|
||||
====================================================================
|
||||
*/
|
||||
void SWimp_BeginFrame(float camera_separation);
|
||||
void SWimp_EndFrame(void);
|
||||
int SWimp_Init(void);
|
||||
void SWimp_SetPalette(const unsigned char *palette);
|
||||
void SWimp_Shutdown(void );
|
||||
rserr_t SWimp_SetMode(int *pwidth, int *pheight, int mode, qboolean fullscreen);
|
||||
|
||||
#endif
|
2073
src/client/refresh/soft/r_main.c
Normal file
2073
src/client/refresh/soft/r_main.c
Normal file
File diff suppressed because it is too large
Load diff
433
src/client/refresh/soft/r_misc.c
Normal file
433
src/client/refresh/soft/r_misc.c
Normal file
|
@ -0,0 +1,433 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_misc.c
|
||||
#include "SDL.h"
|
||||
#include "r_local.h"
|
||||
|
||||
#define NUM_MIPS 4
|
||||
|
||||
cvar_t *sw_mipcap;
|
||||
cvar_t *sw_mipscale;
|
||||
|
||||
surfcache_t *d_initial_rover;
|
||||
qboolean d_roverwrapped;
|
||||
int d_minmip;
|
||||
float d_scalemip[NUM_MIPS-1];
|
||||
|
||||
static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
|
||||
|
||||
extern int d_aflatcolor;
|
||||
|
||||
int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
|
||||
|
||||
int d_pix_min, d_pix_max, d_pix_shift;
|
||||
|
||||
/*
|
||||
================
|
||||
D_Patch
|
||||
================
|
||||
*/
|
||||
void D_Patch (void)
|
||||
{
|
||||
}
|
||||
/*
|
||||
================
|
||||
D_ViewChanged
|
||||
================
|
||||
*/
|
||||
unsigned char *alias_colormap;
|
||||
|
||||
void D_ViewChanged (void)
|
||||
{
|
||||
scale_for_mip = xscale;
|
||||
if (yscale > xscale)
|
||||
scale_for_mip = yscale;
|
||||
|
||||
d_zrowbytes = vid.width * 2;
|
||||
d_zwidth = vid.width;
|
||||
|
||||
d_pix_min = r_refdef.vrect.width / 320;
|
||||
if (d_pix_min < 1)
|
||||
d_pix_min = 1;
|
||||
|
||||
d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
|
||||
d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
|
||||
if (d_pix_max < 1)
|
||||
d_pix_max = 1;
|
||||
|
||||
d_vrectx = r_refdef.vrect.x;
|
||||
d_vrecty = r_refdef.vrect.y;
|
||||
d_vrectright_particle = r_refdef.vrectright - d_pix_max;
|
||||
d_vrectbottom_particle =
|
||||
r_refdef.vrectbottom - d_pix_max;
|
||||
|
||||
/*
|
||||
** clear Z-buffer and color-buffers if we're doing the gallery
|
||||
*/
|
||||
if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
|
||||
{
|
||||
memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof(zvalue_t) );
|
||||
Draw_Fill( r_newrefdef.x, r_newrefdef.y, r_newrefdef.width, r_newrefdef.height,( int ) sw_clearcolor->value & 0xff );
|
||||
}
|
||||
|
||||
alias_colormap = vid_colormap;
|
||||
|
||||
D_Patch ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintTimes
|
||||
=============
|
||||
*/
|
||||
void R_PrintTimes (void)
|
||||
{
|
||||
int r_time2;
|
||||
int ms;
|
||||
|
||||
r_time2 = SDL_GetTicks();
|
||||
|
||||
ms = r_time2 - r_time1;
|
||||
|
||||
R_Printf(PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n",
|
||||
ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
|
||||
c_surf = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintDSpeeds
|
||||
=============
|
||||
*/
|
||||
void R_PrintDSpeeds (void)
|
||||
{
|
||||
int ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time;
|
||||
|
||||
r_time2 = SDL_GetTicks();
|
||||
|
||||
da_time = (da_time2 - da_time1);
|
||||
dp_time = (dp_time2 - dp_time1);
|
||||
rw_time = (rw_time2 - rw_time1);
|
||||
db_time = (db_time2 - db_time1);
|
||||
se_time = (se_time2 - se_time1);
|
||||
de_time = (de_time2 - de_time1);
|
||||
ms = (r_time2 - r_time1);
|
||||
|
||||
R_Printf(PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n",
|
||||
ms, dp_time, rw_time, db_time, se_time, de_time, da_time);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintAliasStats
|
||||
=============
|
||||
*/
|
||||
void R_PrintAliasStats (void)
|
||||
{
|
||||
R_Printf(PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
R_TransformFrustum
|
||||
===================
|
||||
*/
|
||||
void R_TransformFrustum (void)
|
||||
{
|
||||
int i;
|
||||
vec3_t v, v2;
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
v[0] = screenedge[i].normal[2];
|
||||
v[1] = -screenedge[i].normal[0];
|
||||
v[2] = screenedge[i].normal[1];
|
||||
|
||||
v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
|
||||
v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
|
||||
v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
|
||||
|
||||
VectorCopy (v2, view_clipplanes[i].normal);
|
||||
|
||||
view_clipplanes[i].dist = DotProduct (modelorg, v2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
TransformVector
|
||||
================
|
||||
*/
|
||||
void TransformVector (vec3_t in, vec3_t out)
|
||||
{
|
||||
out[0] = DotProduct(in,vright);
|
||||
out[1] = DotProduct(in,vup);
|
||||
out[2] = DotProduct(in,vpn);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_TransformPlane
|
||||
================
|
||||
*/
|
||||
void R_TransformPlane (mplane_t *p, float *normal, float *dist)
|
||||
{
|
||||
float d;
|
||||
|
||||
d = DotProduct (r_origin, p->normal);
|
||||
*dist = p->dist - d;
|
||||
// TODO: when we have rotating entities, this will need to use the view matrix
|
||||
TransformVector (p->normal, normal);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_SetUpFrustumIndexes
|
||||
===============
|
||||
*/
|
||||
void R_SetUpFrustumIndexes (void)
|
||||
{
|
||||
int i, j, *pindex;
|
||||
|
||||
pindex = r_frustum_indexes;
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
if (view_clipplanes[i].normal[j] < 0)
|
||||
{
|
||||
pindex[j] = j;
|
||||
pindex[j+3] = j+3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pindex[j] = j+3;
|
||||
pindex[j+3] = j;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: do just once at start
|
||||
pfrustum_indexes[i] = pindex;
|
||||
pindex += 6;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ViewChanged
|
||||
|
||||
Called every time the vid structure or r_refdef changes.
|
||||
Guaranteed to be called before the first refresh
|
||||
===============
|
||||
*/
|
||||
void R_ViewChanged (vrect_t *vr)
|
||||
{
|
||||
int i;
|
||||
|
||||
r_refdef.vrect = *vr;
|
||||
|
||||
r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);;
|
||||
verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI);
|
||||
|
||||
r_refdef.fvrectx = (float)r_refdef.vrect.x;
|
||||
r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
|
||||
r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<shift_size) + (1<<(shift_size-1)) - 1;
|
||||
r_refdef.fvrecty = (float)r_refdef.vrect.y;
|
||||
r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
|
||||
r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
|
||||
r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<shift_size) + (1<<(shift_size-1)) - 1;
|
||||
r_refdef.fvrectright = (float)r_refdef.vrectright;
|
||||
r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
|
||||
r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
|
||||
r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
|
||||
r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
|
||||
r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
|
||||
|
||||
r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
|
||||
r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
|
||||
r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
|
||||
r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
|
||||
r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
|
||||
r_refdef.aliasvrect.width;
|
||||
r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
|
||||
r_refdef.aliasvrect.height;
|
||||
|
||||
xOrigin = r_refdef.xOrigin;
|
||||
yOrigin = r_refdef.yOrigin;
|
||||
|
||||
// values for perspective projection
|
||||
// if math were exact, the values would range from 0.5 to to range+0.5
|
||||
// hopefully they wll be in the 0.000001 to range+.999999 and truncate
|
||||
// the polygon rasterization will never render in the first row or column
|
||||
// but will definately render in the [range] row and column, so adjust the
|
||||
// buffer origin to get an exact edge to edge fill
|
||||
xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
|
||||
r_refdef.vrect.x - 0.5;
|
||||
aliasxcenter = xcenter * r_aliasuvscale;
|
||||
ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
|
||||
r_refdef.vrect.y - 0.5;
|
||||
aliasycenter = ycenter * r_aliasuvscale;
|
||||
|
||||
xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
|
||||
aliasxscale = xscale * r_aliasuvscale;
|
||||
xscaleinv = 1.0 / xscale;
|
||||
|
||||
yscale = xscale;
|
||||
aliasyscale = yscale * r_aliasuvscale;
|
||||
yscaleinv = 1.0 / yscale;
|
||||
xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
|
||||
yscaleshrink = xscaleshrink;
|
||||
|
||||
// left side clip
|
||||
screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
|
||||
screenedge[0].normal[1] = 0;
|
||||
screenedge[0].normal[2] = 1;
|
||||
screenedge[0].type = PLANE_ANYZ;
|
||||
|
||||
// right side clip
|
||||
screenedge[1].normal[0] =
|
||||
1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
|
||||
screenedge[1].normal[1] = 0;
|
||||
screenedge[1].normal[2] = 1;
|
||||
screenedge[1].type = PLANE_ANYZ;
|
||||
|
||||
// top side clip
|
||||
screenedge[2].normal[0] = 0;
|
||||
screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
|
||||
screenedge[2].normal[2] = 1;
|
||||
screenedge[2].type = PLANE_ANYZ;
|
||||
|
||||
// bottom side clip
|
||||
screenedge[3].normal[0] = 0;
|
||||
screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
|
||||
screenedge[3].normal[2] = 1;
|
||||
screenedge[3].type = PLANE_ANYZ;
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
VectorNormalize (screenedge[i].normal);
|
||||
|
||||
D_ViewChanged ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_SetupFrame
|
||||
===============
|
||||
*/
|
||||
void R_SetupFrame (void)
|
||||
{
|
||||
int i;
|
||||
vrect_t vrect;
|
||||
|
||||
if (r_fullbright->modified)
|
||||
{
|
||||
r_fullbright->modified = false;
|
||||
D_FlushCaches (); // so all lighting changes
|
||||
}
|
||||
|
||||
r_framecount++;
|
||||
|
||||
|
||||
// build the transformation matrix for the given view angles
|
||||
VectorCopy (r_refdef.vieworg, modelorg);
|
||||
VectorCopy (r_refdef.vieworg, r_origin);
|
||||
|
||||
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
|
||||
|
||||
// current viewleaf
|
||||
if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
|
||||
{
|
||||
r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel);
|
||||
r_viewcluster = r_viewleaf->cluster;
|
||||
}
|
||||
|
||||
if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
|
||||
r_dowarp = true;
|
||||
else
|
||||
r_dowarp = false;
|
||||
|
||||
if (r_dowarp)
|
||||
{
|
||||
// warp into off screen buffer
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH;
|
||||
vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT;
|
||||
|
||||
d_viewbuffer = r_warpbuffer;
|
||||
r_screenwidth = WARP_WIDTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
vrect.x = r_newrefdef.x;
|
||||
vrect.y = r_newrefdef.y;
|
||||
vrect.width = r_newrefdef.width;
|
||||
vrect.height = r_newrefdef.height;
|
||||
|
||||
d_viewbuffer = vid_buffer;
|
||||
r_screenwidth = vid.width;
|
||||
}
|
||||
|
||||
R_ViewChanged (&vrect);
|
||||
|
||||
// start off with just the four screen edge clip planes
|
||||
R_TransformFrustum ();
|
||||
R_SetUpFrustumIndexes ();
|
||||
|
||||
// save base values
|
||||
VectorCopy (vpn, base_vpn);
|
||||
VectorCopy (vright, base_vright);
|
||||
VectorCopy (vup, base_vup);
|
||||
|
||||
// clear frame counts
|
||||
c_faceclip = 0;
|
||||
d_spanpixcount = 0;
|
||||
r_polycount = 0;
|
||||
r_drawnpolycount = 0;
|
||||
r_wholepolycount = 0;
|
||||
r_amodels_drawn = 0;
|
||||
r_outofsurfaces = 0;
|
||||
r_outofedges = 0;
|
||||
|
||||
// d_setup
|
||||
d_roverwrapped = false;
|
||||
d_initial_rover = sc_rover;
|
||||
|
||||
d_minmip = sw_mipcap->value;
|
||||
if (d_minmip > 3)
|
||||
d_minmip = 3;
|
||||
else if (d_minmip < 0)
|
||||
d_minmip = 0;
|
||||
|
||||
for (i=0 ; i<(NUM_MIPS-1) ; i++)
|
||||
d_scalemip[i] = basemip[i] * sw_mipscale->value;
|
||||
|
||||
d_aflatcolor = 0;
|
||||
}
|
1265
src/client/refresh/soft/r_model.c
Normal file
1265
src/client/refresh/soft/r_model.c
Normal file
File diff suppressed because it is too large
Load diff
249
src/client/refresh/soft/r_model.h
Normal file
249
src/client/refresh/soft/r_model.h
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __MODEL__
|
||||
#define __MODEL__
|
||||
|
||||
/*
|
||||
|
||||
d*_t structures are on-disk representations
|
||||
m*_t structures are in-memory
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
BRUSH MODELS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// in memory representation
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
vec3_t position;
|
||||
} mvertex_t;
|
||||
|
||||
#define SIDE_FRONT 0
|
||||
#define SIDE_BACK 1
|
||||
#define SIDE_ON 2
|
||||
|
||||
|
||||
// plane_t structure
|
||||
typedef struct mplane_s
|
||||
{
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
byte type; // for texture axis selection and fast side tests
|
||||
byte signbits; // signx + signy<<1 + signz<<1
|
||||
byte pad[2];
|
||||
} mplane_t;
|
||||
|
||||
|
||||
// FIXME: differentiate from texinfo SURF_ flags
|
||||
#define SURF_PLANEBACK 0x02
|
||||
#define SURF_DRAWSKY 0x04 // sky brush face
|
||||
#define SURF_DRAWTURB 0x10
|
||||
#define SURF_DRAWBACKGROUND 0x40
|
||||
#define SURF_DRAWSKYBOX 0x80 // sky box
|
||||
|
||||
#define SURF_FLOW 0x100 //PGM
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short v[2];
|
||||
unsigned int cachededgeoffset;
|
||||
} medge_t;
|
||||
|
||||
typedef struct mtexinfo_s
|
||||
{
|
||||
float vecs[2][4];
|
||||
float mipadjust;
|
||||
image_t *image;
|
||||
int flags;
|
||||
int numframes;
|
||||
struct mtexinfo_s *next; // animation chain
|
||||
} mtexinfo_t;
|
||||
|
||||
typedef struct msurface_s
|
||||
{
|
||||
int visframe; // should be drawn when node is crossed
|
||||
|
||||
int dlightframe;
|
||||
int dlightbits;
|
||||
|
||||
mplane_t *plane;
|
||||
int flags;
|
||||
|
||||
int firstedge; // look up in model->surfedges[], negative numbers
|
||||
int numedges; // are backwards edges
|
||||
|
||||
// surface generation data
|
||||
struct surfcache_s *cachespots[MIPLEVELS];
|
||||
|
||||
short texturemins[2];
|
||||
short extents[2];
|
||||
|
||||
mtexinfo_t *texinfo;
|
||||
|
||||
// lighting info
|
||||
byte styles[MAXLIGHTMAPS];
|
||||
byte *samples; // [numstyles*surfsize]
|
||||
|
||||
struct msurface_s *nextalphasurface;
|
||||
} msurface_t;
|
||||
|
||||
|
||||
#define CONTENTS_NODE -1
|
||||
typedef struct mnode_s
|
||||
{
|
||||
// common with leaf
|
||||
int contents; // CONTENTS_NODE, to differentiate from leafs
|
||||
int visframe; // node needs to be traversed if current
|
||||
|
||||
short minmaxs[6]; // for bounding box culling
|
||||
|
||||
struct mnode_s *parent;
|
||||
|
||||
// node specific
|
||||
mplane_t *plane;
|
||||
struct mnode_s *children[2];
|
||||
|
||||
unsigned short firstsurface;
|
||||
unsigned short numsurfaces;
|
||||
} mnode_t;
|
||||
|
||||
typedef struct mleaf_s
|
||||
{
|
||||
// common with node
|
||||
int contents; // wil be something other than CONTENTS_NODE
|
||||
int visframe; // node needs to be traversed if current
|
||||
|
||||
short minmaxs[6]; // for bounding box culling
|
||||
|
||||
struct mnode_s *parent;
|
||||
|
||||
// leaf specific
|
||||
int cluster;
|
||||
int area;
|
||||
|
||||
msurface_t **firstmarksurface;
|
||||
int nummarksurfaces;
|
||||
int key; // BSP sequence number for leaf's contents
|
||||
} mleaf_t;
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
//
|
||||
// Whole model
|
||||
//
|
||||
|
||||
typedef struct model_s
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
|
||||
int registration_sequence;
|
||||
|
||||
modtype_t type;
|
||||
int numframes;
|
||||
|
||||
int flags;
|
||||
|
||||
//
|
||||
// volume occupied by the model graphics
|
||||
//
|
||||
vec3_t mins, maxs;
|
||||
|
||||
//
|
||||
// solid volume for clipping (sent from server)
|
||||
//
|
||||
qboolean clipbox;
|
||||
vec3_t clipmins, clipmaxs;
|
||||
|
||||
//
|
||||
// brush model
|
||||
//
|
||||
int firstmodelsurface, nummodelsurfaces;
|
||||
|
||||
int numsubmodels;
|
||||
dmodel_t *submodels;
|
||||
|
||||
int numplanes;
|
||||
mplane_t *planes;
|
||||
|
||||
int numleafs; // number of visible leafs, not counting 0
|
||||
mleaf_t *leafs;
|
||||
|
||||
int numvertexes;
|
||||
mvertex_t *vertexes;
|
||||
|
||||
int numedges;
|
||||
medge_t *edges;
|
||||
|
||||
int numnodes;
|
||||
int firstnode;
|
||||
mnode_t *nodes;
|
||||
|
||||
int numtexinfo;
|
||||
mtexinfo_t *texinfo;
|
||||
|
||||
int numsurfaces;
|
||||
msurface_t *surfaces;
|
||||
|
||||
int numsurfedges;
|
||||
int *surfedges;
|
||||
|
||||
int nummarksurfaces;
|
||||
msurface_t **marksurfaces;
|
||||
|
||||
dvis_t *vis;
|
||||
|
||||
byte *lightdata;
|
||||
|
||||
// for alias models and sprites
|
||||
image_t *skins[MAX_MD2SKINS];
|
||||
void *extradata;
|
||||
int extradatasize;
|
||||
} model_t;
|
||||
|
||||
//============================================================================
|
||||
|
||||
void Mod_Init(void);
|
||||
void Mod_ClearAll(void);
|
||||
model_t *Mod_ForName(char *name, qboolean crash);
|
||||
void *Mod_Extradata(model_t *mod); // handles caching
|
||||
void Mod_TouchModel(char *name);
|
||||
|
||||
mleaf_t *Mod_PointInLeaf(float *p, model_t *model);
|
||||
byte *Mod_ClusterPVS(int cluster, model_t *model);
|
||||
|
||||
void Mod_Modellist_f(void);
|
||||
void Mod_FreeAll(void);
|
||||
void Mod_Free(model_t *mod);
|
||||
|
||||
extern int registration_sequence;
|
||||
|
||||
#endif // __MODEL__
|
190
src/client/refresh/soft/r_part.c
Normal file
190
src/client/refresh/soft/r_part.c
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "r_local.h"
|
||||
|
||||
vec3_t r_pright, r_pup, r_ppn;
|
||||
|
||||
#define PARTICLE_33 0
|
||||
#define PARTICLE_66 1
|
||||
#define PARTICLE_OPAQUE 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
particle_t *particle;
|
||||
int level;
|
||||
int color;
|
||||
} partparms_t;
|
||||
|
||||
static partparms_t partparms;
|
||||
|
||||
/*
|
||||
** R_DrawParticle
|
||||
**
|
||||
** Yes, this is amazingly slow, but it's the C reference
|
||||
** implementation and should be both robust and vaguely
|
||||
** understandable. The only time this path should be
|
||||
** executed is if we're debugging on x86 or if we're
|
||||
** recompiling and deploying on a non-x86 platform.
|
||||
**
|
||||
** To minimize error and improve readability I went the
|
||||
** function pointer route. This exacts some overhead, but
|
||||
** it pays off in clean and easy to understand code.
|
||||
*/
|
||||
void R_DrawParticle( void )
|
||||
{
|
||||
particle_t *pparticle = partparms.particle;
|
||||
int level = partparms.level;
|
||||
vec3_t local, transformed;
|
||||
float zi;
|
||||
byte *pdest;
|
||||
zvalue_t *pz;
|
||||
int color = pparticle->color;
|
||||
int i, izi, pix, count, u, v;
|
||||
|
||||
/*
|
||||
** transform the particle
|
||||
*/
|
||||
VectorSubtract (pparticle->origin, r_origin, local);
|
||||
|
||||
transformed[0] = DotProduct(local, r_pright);
|
||||
transformed[1] = DotProduct(local, r_pup);
|
||||
transformed[2] = DotProduct(local, r_ppn);
|
||||
|
||||
if (transformed[2] < PARTICLE_Z_CLIP)
|
||||
return;
|
||||
|
||||
/*
|
||||
** project the point
|
||||
*/
|
||||
// FIXME: preadjust xcenter and ycenter
|
||||
zi = 1.0 / transformed[2];
|
||||
u = (int)(xcenter + zi * transformed[0] + 0.5);
|
||||
v = (int)(ycenter - zi * transformed[1] + 0.5);
|
||||
|
||||
if ((v > d_vrectbottom_particle) ||
|
||||
(u > d_vrectright_particle) ||
|
||||
(v < d_vrecty) ||
|
||||
(u < d_vrectx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** compute addresses of zbuffer, framebuffer, and
|
||||
** compute the Z-buffer reference value.
|
||||
*/
|
||||
pz = d_pzbuffer + (d_zwidth * v) + u;
|
||||
pdest = d_viewbuffer + r_screenwidth * v + u;
|
||||
izi = (int)(zi * 0x8000);
|
||||
|
||||
/*
|
||||
** determine the screen area covered by the particle,
|
||||
** which also means clamping to a min and max
|
||||
*/
|
||||
pix = izi >> d_pix_shift;
|
||||
if (pix < d_pix_min)
|
||||
pix = d_pix_min;
|
||||
else if (pix > d_pix_max)
|
||||
pix = d_pix_max;
|
||||
|
||||
/*
|
||||
** render the appropriate pixels
|
||||
*/
|
||||
count = pix;
|
||||
|
||||
switch (level) {
|
||||
case PARTICLE_33 :
|
||||
for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
|
||||
{
|
||||
//FIXME--do it in blocks of 8?
|
||||
for (i=0 ; i<pix ; i++)
|
||||
{
|
||||
if (pz[i] <= izi)
|
||||
{
|
||||
pz[i] = izi;
|
||||
pdest[i] = vid_alphamap[color + ((int)pdest[i]<<8)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PARTICLE_66 :
|
||||
for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
|
||||
{
|
||||
for (i=0 ; i<pix ; i++)
|
||||
{
|
||||
if (pz[i] <= izi)
|
||||
{
|
||||
pz[i] = izi;
|
||||
pdest[i] = vid_alphamap[(color<<8) + (int)pdest[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: //100
|
||||
for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
|
||||
{
|
||||
for (i=0 ; i<pix ; i++)
|
||||
{
|
||||
if (pz[i] <= izi)
|
||||
{
|
||||
pz[i] = izi;
|
||||
pdest[i] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** R_DrawParticles
|
||||
**
|
||||
** Responsible for drawing all of the particles in the particle list
|
||||
** throughout the world. Doesn't care if we're using the C path or
|
||||
** if we're using the asm path, it simply assigns a function pointer
|
||||
** and goes.
|
||||
*/
|
||||
void R_DrawParticles (void)
|
||||
{
|
||||
particle_t *p;
|
||||
int i;
|
||||
|
||||
VectorScale( vright, xscaleshrink, r_pright );
|
||||
VectorScale( vup, yscaleshrink, r_pup );
|
||||
VectorCopy( vpn, r_ppn );
|
||||
|
||||
for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
|
||||
{
|
||||
|
||||
if ( p->alpha > 0.66 )
|
||||
partparms.level = PARTICLE_OPAQUE;
|
||||
else if ( p->alpha > 0.33 )
|
||||
partparms.level = PARTICLE_66;
|
||||
else
|
||||
partparms.level = PARTICLE_33;
|
||||
|
||||
partparms.particle = p;
|
||||
partparms.color = p->color;
|
||||
|
||||
R_DrawParticle();
|
||||
}
|
||||
}
|
1261
src/client/refresh/soft/r_poly.c
Normal file
1261
src/client/refresh/soft/r_poly.c
Normal file
File diff suppressed because it is too large
Load diff
1143
src/client/refresh/soft/r_polyse.c
Normal file
1143
src/client/refresh/soft/r_polyse.c
Normal file
File diff suppressed because it is too large
Load diff
839
src/client/refresh/soft/r_rast.c
Normal file
839
src/client/refresh/soft/r_rast.c
Normal file
|
@ -0,0 +1,839 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_rast.c
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
#define MAXLEFTCLIPEDGES 100
|
||||
|
||||
#define FULLY_CLIPPED_CACHED 0x80000000
|
||||
#define FRAMECOUNT_MASK 0x7FFFFFFF
|
||||
|
||||
unsigned int cacheoffset;
|
||||
|
||||
int c_faceclip; // number of faces clipped
|
||||
|
||||
|
||||
clipplane_t *entity_clipplanes;
|
||||
clipplane_t view_clipplanes[4];
|
||||
clipplane_t world_clipplanes[16];
|
||||
|
||||
medge_t *r_pedge;
|
||||
|
||||
qboolean r_leftclipped, r_rightclipped;
|
||||
static qboolean makeleftedge, makerightedge;
|
||||
qboolean r_nearzionly;
|
||||
|
||||
int *sintable;
|
||||
int *intsintable;
|
||||
int *blanktable; // PGM
|
||||
|
||||
mvertex_t r_leftenter, r_leftexit;
|
||||
mvertex_t r_rightenter, r_rightexit;
|
||||
|
||||
int r_emitted;
|
||||
float r_nearzi;
|
||||
float r_u1, r_v1, r_lzi1;
|
||||
int r_ceilv1;
|
||||
|
||||
qboolean r_lastvertvalid;
|
||||
int r_skyframe;
|
||||
|
||||
msurface_t *r_skyfaces;
|
||||
mplane_t r_skyplanes[6];
|
||||
mtexinfo_t r_skytexinfo[6];
|
||||
mvertex_t *r_skyverts;
|
||||
medge_t *r_skyedges;
|
||||
int *r_skysurfedges;
|
||||
|
||||
// I just copied this data from a box map...
|
||||
int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128};
|
||||
|
||||
int box_surfedges[24] = { 1,2,3,4, -1,5,6,7, 8,9,-6,10, -2,-7,-9,11,
|
||||
12,-3,-11,-8, -12,-10,-5,-4};
|
||||
int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4};
|
||||
|
||||
int box_faces[6] = {0,0,2,2,2,0};
|
||||
|
||||
vec3_t box_vecs[6][2] = {
|
||||
{ {0,-1,0}, {-1,0,0} },
|
||||
{ {0,1,0}, {0,0,-1} },
|
||||
{ {0,-1,0}, {1,0,0} },
|
||||
{ {1,0,0}, {0,0,-1} },
|
||||
{ {0,-1,0}, {0,0,-1} },
|
||||
{ {-1,0,0}, {0,0,-1} }
|
||||
};
|
||||
|
||||
float box_verts[8][3] = {
|
||||
{-1,-1,-1},
|
||||
{-1,1,-1},
|
||||
{1,1,-1},
|
||||
{1,-1,-1},
|
||||
{-1,-1,1},
|
||||
{-1,1,1},
|
||||
{1,-1,1},
|
||||
{1,1,1}
|
||||
};
|
||||
|
||||
// down, west, up, north, east, south
|
||||
// {"rt", "bk", "lf", "ft", "up", "dn"};
|
||||
|
||||
/*
|
||||
================
|
||||
R_InitSkyBox
|
||||
|
||||
================
|
||||
*/
|
||||
void R_InitSkyBox (void)
|
||||
{
|
||||
int i;
|
||||
extern model_t *loadmodel;
|
||||
|
||||
r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces;
|
||||
loadmodel->numsurfaces += 6;
|
||||
r_skyverts = loadmodel->vertexes + loadmodel->numvertexes;
|
||||
loadmodel->numvertexes += 8;
|
||||
r_skyedges = loadmodel->edges + loadmodel->numedges;
|
||||
loadmodel->numedges += 12;
|
||||
r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges;
|
||||
loadmodel->numsurfedges += 24;
|
||||
if (loadmodel->numsurfaces > MAX_MAP_FACES
|
||||
|| loadmodel->numvertexes > MAX_MAP_VERTS
|
||||
|| loadmodel->numedges > MAX_MAP_EDGES)
|
||||
ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow");
|
||||
|
||||
memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces));
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
r_skyplanes[i].normal[skybox_planes[i*2]] = 1;
|
||||
r_skyplanes[i].dist = skybox_planes[i*2+1];
|
||||
|
||||
VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]);
|
||||
VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]);
|
||||
|
||||
r_skyfaces[i].plane = &r_skyplanes[i];
|
||||
r_skyfaces[i].numedges = 4;
|
||||
r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX;
|
||||
r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4;
|
||||
r_skyfaces[i].texinfo = &r_skytexinfo[i];
|
||||
r_skyfaces[i].texturemins[0] = -128;
|
||||
r_skyfaces[i].texturemins[1] = -128;
|
||||
r_skyfaces[i].extents[0] = 256;
|
||||
r_skyfaces[i].extents[1] = 256;
|
||||
}
|
||||
|
||||
for (i=0 ; i<24 ; i++)
|
||||
if (box_surfedges[i] > 0)
|
||||
r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i];
|
||||
else
|
||||
r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]);
|
||||
|
||||
for(i=0 ; i<12 ; i++)
|
||||
{
|
||||
r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0];
|
||||
r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1];
|
||||
r_skyedges[i].cachededgeoffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_EmitSkyBox
|
||||
================
|
||||
*/
|
||||
void R_EmitSkyBox (void)
|
||||
{
|
||||
int i, j;
|
||||
int oldkey;
|
||||
|
||||
if (insubmodel)
|
||||
return; // submodels should never have skies
|
||||
if (r_skyframe == r_framecount)
|
||||
return; // already set this frame
|
||||
|
||||
r_skyframe = r_framecount;
|
||||
|
||||
// set the eight fake vertexes
|
||||
for (i=0 ; i<8 ; i++)
|
||||
for (j=0 ; j<3 ; j++)
|
||||
r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128;
|
||||
|
||||
// set the six fake planes
|
||||
for (i=0 ; i<6 ; i++)
|
||||
if (skybox_planes[i*2+1] > 0)
|
||||
r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128;
|
||||
else
|
||||
r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128;
|
||||
|
||||
// fix texture offseets
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]);
|
||||
r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]);
|
||||
}
|
||||
|
||||
// emit the six faces
|
||||
oldkey = r_currentkey;
|
||||
r_currentkey = 0x7ffffff0;
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
R_RenderFace (r_skyfaces + i, 15);
|
||||
}
|
||||
r_currentkey = oldkey; // bsp sorting order
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_EmitEdge
|
||||
================
|
||||
*/
|
||||
void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
|
||||
{
|
||||
edge_t *edge, *pcheck;
|
||||
int u_check;
|
||||
float u, u_step;
|
||||
vec3_t local, transformed;
|
||||
float *world;
|
||||
int v, v2, ceilv0;
|
||||
float scale, lzi0, u0, v0;
|
||||
int side;
|
||||
|
||||
if (r_lastvertvalid)
|
||||
{
|
||||
u0 = r_u1;
|
||||
v0 = r_v1;
|
||||
lzi0 = r_lzi1;
|
||||
ceilv0 = r_ceilv1;
|
||||
}
|
||||
else
|
||||
{
|
||||
world = &pv0->position[0];
|
||||
|
||||
// transform and project
|
||||
VectorSubtract (world, modelorg, local);
|
||||
TransformVector (local, transformed);
|
||||
|
||||
if (transformed[2] < NEAR_CLIP)
|
||||
transformed[2] = NEAR_CLIP;
|
||||
|
||||
lzi0 = 1.0 / transformed[2];
|
||||
|
||||
// FIXME: build x/yscale into transform?
|
||||
scale = xscale * lzi0;
|
||||
u0 = (xcenter + scale*transformed[0]);
|
||||
if (u0 < r_refdef.fvrectx_adj)
|
||||
u0 = r_refdef.fvrectx_adj;
|
||||
if (u0 > r_refdef.fvrectright_adj)
|
||||
u0 = r_refdef.fvrectright_adj;
|
||||
|
||||
scale = yscale * lzi0;
|
||||
v0 = (ycenter - scale*transformed[1]);
|
||||
if (v0 < r_refdef.fvrecty_adj)
|
||||
v0 = r_refdef.fvrecty_adj;
|
||||
if (v0 > r_refdef.fvrectbottom_adj)
|
||||
v0 = r_refdef.fvrectbottom_adj;
|
||||
|
||||
ceilv0 = (int) ceil(v0);
|
||||
}
|
||||
|
||||
world = &pv1->position[0];
|
||||
|
||||
// transform and project
|
||||
VectorSubtract (world, modelorg, local);
|
||||
TransformVector (local, transformed);
|
||||
|
||||
if (transformed[2] < NEAR_CLIP)
|
||||
transformed[2] = NEAR_CLIP;
|
||||
|
||||
r_lzi1 = 1.0 / transformed[2];
|
||||
|
||||
scale = xscale * r_lzi1;
|
||||
r_u1 = (xcenter + scale*transformed[0]);
|
||||
if (r_u1 < r_refdef.fvrectx_adj)
|
||||
r_u1 = r_refdef.fvrectx_adj;
|
||||
if (r_u1 > r_refdef.fvrectright_adj)
|
||||
r_u1 = r_refdef.fvrectright_adj;
|
||||
|
||||
scale = yscale * r_lzi1;
|
||||
r_v1 = (ycenter - scale*transformed[1]);
|
||||
if (r_v1 < r_refdef.fvrecty_adj)
|
||||
r_v1 = r_refdef.fvrecty_adj;
|
||||
if (r_v1 > r_refdef.fvrectbottom_adj)
|
||||
r_v1 = r_refdef.fvrectbottom_adj;
|
||||
|
||||
if (r_lzi1 > lzi0)
|
||||
lzi0 = r_lzi1;
|
||||
|
||||
if (lzi0 > r_nearzi) // for mipmap finding
|
||||
r_nearzi = lzi0;
|
||||
|
||||
// for right edges, all we want is the effect on 1/z
|
||||
if (r_nearzionly)
|
||||
return;
|
||||
|
||||
r_emitted = 1;
|
||||
|
||||
r_ceilv1 = (int) ceil(r_v1);
|
||||
|
||||
|
||||
// create the edge
|
||||
if (ceilv0 == r_ceilv1)
|
||||
{
|
||||
// we cache unclipped horizontal edges as fully clipped
|
||||
if (cacheoffset != 0x7FFFFFFF)
|
||||
{
|
||||
cacheoffset = FULLY_CLIPPED_CACHED |
|
||||
(r_framecount & FRAMECOUNT_MASK);
|
||||
}
|
||||
|
||||
return; // horizontal edge
|
||||
}
|
||||
|
||||
side = ceilv0 > r_ceilv1;
|
||||
|
||||
edge = edge_p++;
|
||||
|
||||
edge->owner = r_pedge;
|
||||
|
||||
edge->nearzi = lzi0;
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
// trailing edge (go from p1 to p2)
|
||||
v = ceilv0;
|
||||
v2 = r_ceilv1 - 1;
|
||||
|
||||
edge->surfs[0] = surface_p - surfaces;
|
||||
edge->surfs[1] = 0;
|
||||
|
||||
u_step = ((r_u1 - u0) / (r_v1 - v0));
|
||||
u = u0 + ((float)v - v0) * u_step;
|
||||
}
|
||||
else
|
||||
{
|
||||
// leading edge (go from p2 to p1)
|
||||
v2 = ceilv0 - 1;
|
||||
v = r_ceilv1;
|
||||
|
||||
edge->surfs[0] = 0;
|
||||
edge->surfs[1] = surface_p - surfaces;
|
||||
|
||||
u_step = ((u0 - r_u1) / (v0 - r_v1));
|
||||
u = r_u1 + ((float)v - r_v1) * u_step;
|
||||
}
|
||||
|
||||
edge->u_step = u_step*(1<<shift_size);
|
||||
edge->u = u*(1<<shift_size) + (1<<shift_size) - 1;
|
||||
|
||||
// we need to do this to avoid stepping off the edges if a very nearly
|
||||
// horizontal edge is less than epsilon above a scan, and numeric error causes
|
||||
// it to incorrectly extend to the scan, and the extension of the line goes off
|
||||
// the edge of the screen
|
||||
// FIXME: is this actually needed?
|
||||
if (edge->u < r_refdef.vrect_x_adj_shift20)
|
||||
edge->u = r_refdef.vrect_x_adj_shift20;
|
||||
if (edge->u > r_refdef.vrectright_adj_shift20)
|
||||
edge->u = r_refdef.vrectright_adj_shift20;
|
||||
|
||||
//
|
||||
// sort the edge in normally
|
||||
//
|
||||
u_check = edge->u;
|
||||
if (edge->surfs[0])
|
||||
u_check++; // sort trailers after leaders
|
||||
|
||||
if (!newedges[v] || newedges[v]->u >= u_check)
|
||||
{
|
||||
edge->next = newedges[v];
|
||||
newedges[v] = edge;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcheck = newedges[v];
|
||||
while (pcheck->next && pcheck->next->u < u_check)
|
||||
pcheck = pcheck->next;
|
||||
edge->next = pcheck->next;
|
||||
pcheck->next = edge;
|
||||
}
|
||||
|
||||
edge->nextremove = removeedges[v2];
|
||||
removeedges[v2] = edge;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_ClipEdge
|
||||
================
|
||||
*/
|
||||
void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
|
||||
{
|
||||
if (clip)
|
||||
{
|
||||
do
|
||||
{
|
||||
float d0, d1, f;
|
||||
mvertex_t clipvert;
|
||||
|
||||
d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
|
||||
d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
|
||||
|
||||
if (d0 >= 0)
|
||||
{
|
||||
// point 0 is unclipped
|
||||
if (d1 >= 0)
|
||||
{
|
||||
// both points are unclipped
|
||||
continue;
|
||||
}
|
||||
|
||||
// only point 1 is clipped
|
||||
// we don't cache clipped edges
|
||||
cacheoffset = 0x7FFFFFFF;
|
||||
|
||||
f = d0 / (d0 - d1);
|
||||
clipvert.position[0] = pv0->position[0] +
|
||||
f * (pv1->position[0] - pv0->position[0]);
|
||||
clipvert.position[1] = pv0->position[1] +
|
||||
f * (pv1->position[1] - pv0->position[1]);
|
||||
clipvert.position[2] = pv0->position[2] +
|
||||
f * (pv1->position[2] - pv0->position[2]);
|
||||
|
||||
if (clip->leftedge)
|
||||
{
|
||||
r_leftclipped = true;
|
||||
r_leftexit = clipvert;
|
||||
}
|
||||
else if (clip->rightedge)
|
||||
{
|
||||
r_rightclipped = true;
|
||||
r_rightexit = clipvert;
|
||||
}
|
||||
|
||||
R_ClipEdge (pv0, &clipvert, clip->next);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// point 0 is clipped
|
||||
if (d1 < 0)
|
||||
{
|
||||
// both points are clipped
|
||||
// we do cache fully clipped edges
|
||||
if (!r_leftclipped)
|
||||
cacheoffset = FULLY_CLIPPED_CACHED |
|
||||
(r_framecount & FRAMECOUNT_MASK);
|
||||
return;
|
||||
}
|
||||
|
||||
// only point 0 is clipped
|
||||
r_lastvertvalid = false;
|
||||
|
||||
// we don't cache partially clipped edges
|
||||
cacheoffset = 0x7FFFFFFF;
|
||||
|
||||
f = d0 / (d0 - d1);
|
||||
clipvert.position[0] = pv0->position[0] +
|
||||
f * (pv1->position[0] - pv0->position[0]);
|
||||
clipvert.position[1] = pv0->position[1] +
|
||||
f * (pv1->position[1] - pv0->position[1]);
|
||||
clipvert.position[2] = pv0->position[2] +
|
||||
f * (pv1->position[2] - pv0->position[2]);
|
||||
|
||||
if (clip->leftedge)
|
||||
{
|
||||
r_leftclipped = true;
|
||||
r_leftenter = clipvert;
|
||||
}
|
||||
else if (clip->rightedge)
|
||||
{
|
||||
r_rightclipped = true;
|
||||
r_rightenter = clipvert;
|
||||
}
|
||||
|
||||
R_ClipEdge (&clipvert, pv1, clip->next);
|
||||
return;
|
||||
}
|
||||
} while ((clip = clip->next) != NULL);
|
||||
}
|
||||
|
||||
// add the edge
|
||||
R_EmitEdge (pv0, pv1);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_EmitCachedEdge
|
||||
================
|
||||
*/
|
||||
void R_EmitCachedEdge (void)
|
||||
{
|
||||
edge_t *pedge_t;
|
||||
|
||||
pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
|
||||
|
||||
if (!pedge_t->surfs[0])
|
||||
pedge_t->surfs[0] = surface_p - surfaces;
|
||||
else
|
||||
pedge_t->surfs[1] = surface_p - surfaces;
|
||||
|
||||
if (pedge_t->nearzi > r_nearzi) // for mipmap finding
|
||||
r_nearzi = pedge_t->nearzi;
|
||||
|
||||
r_emitted = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RenderFace
|
||||
================
|
||||
*/
|
||||
void R_RenderFace (msurface_t *fa, int clipflags)
|
||||
{
|
||||
int i;
|
||||
unsigned mask;
|
||||
mplane_t *pplane;
|
||||
float distinv;
|
||||
vec3_t p_normal;
|
||||
medge_t *pedges, tedge;
|
||||
clipplane_t *pclip;
|
||||
|
||||
// translucent surfaces are not drawn by the edge renderer
|
||||
if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
||||
{
|
||||
fa->nextalphasurface = r_alpha_surfaces;
|
||||
r_alpha_surfaces = fa;
|
||||
return;
|
||||
}
|
||||
|
||||
// sky surfaces encountered in the world will cause the
|
||||
// environment box surfaces to be emited
|
||||
if ( fa->texinfo->flags & SURF_SKY )
|
||||
{
|
||||
R_EmitSkyBox ();
|
||||
return;
|
||||
}
|
||||
|
||||
// skip out if no more surfs
|
||||
if ((surface_p) >= surf_max)
|
||||
{
|
||||
r_outofsurfaces++;
|
||||
return;
|
||||
}
|
||||
|
||||
// ditto if not enough edges left, or switch to auxedges if possible
|
||||
if ((edge_p + fa->numedges + 4) >= edge_max)
|
||||
{
|
||||
r_outofedges += fa->numedges;
|
||||
return;
|
||||
}
|
||||
|
||||
c_faceclip++;
|
||||
|
||||
// set up clip planes
|
||||
pclip = NULL;
|
||||
|
||||
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
|
||||
{
|
||||
if (clipflags & mask)
|
||||
{
|
||||
view_clipplanes[i].next = pclip;
|
||||
pclip = &view_clipplanes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// push the edges through
|
||||
r_emitted = 0;
|
||||
r_nearzi = 0;
|
||||
r_nearzionly = false;
|
||||
makeleftedge = makerightedge = false;
|
||||
pedges = currentmodel->edges;
|
||||
r_lastvertvalid = false;
|
||||
|
||||
for (i=0 ; i<fa->numedges ; i++)
|
||||
{
|
||||
int lindex;
|
||||
|
||||
lindex = currentmodel->surfedges[fa->firstedge + i];
|
||||
|
||||
if (lindex > 0)
|
||||
{
|
||||
r_pedge = &pedges[lindex];
|
||||
|
||||
// if the edge is cached, we can just reuse the edge
|
||||
if (!insubmodel)
|
||||
{
|
||||
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
|
||||
{
|
||||
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
|
||||
r_framecount)
|
||||
{
|
||||
r_lastvertvalid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((((unsigned long)edge_p - (unsigned long)r_edges) >
|
||||
r_pedge->cachededgeoffset) &&
|
||||
(((edge_t *)((unsigned long)r_edges +
|
||||
r_pedge->cachededgeoffset))->owner == r_pedge))
|
||||
{
|
||||
R_EmitCachedEdge ();
|
||||
r_lastvertvalid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assume it's cacheable
|
||||
cacheoffset = (byte *)edge_p - (byte *)r_edges;
|
||||
r_leftclipped = r_rightclipped = false;
|
||||
R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
|
||||
&r_pcurrentvertbase[r_pedge->v[1]],
|
||||
pclip);
|
||||
r_pedge->cachededgeoffset = cacheoffset;
|
||||
|
||||
if (r_leftclipped)
|
||||
makeleftedge = true;
|
||||
if (r_rightclipped)
|
||||
makerightedge = true;
|
||||
r_lastvertvalid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lindex = -lindex;
|
||||
r_pedge = &pedges[lindex];
|
||||
// if the edge is cached, we can just reuse the edge
|
||||
if (!insubmodel)
|
||||
{
|
||||
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
|
||||
{
|
||||
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
|
||||
r_framecount)
|
||||
{
|
||||
r_lastvertvalid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's cached if the cached edge is valid and is owned
|
||||
// by this medge_t
|
||||
if ((((unsigned long)edge_p - (unsigned long)r_edges) >
|
||||
r_pedge->cachededgeoffset) &&
|
||||
(((edge_t *)((unsigned long)r_edges +
|
||||
r_pedge->cachededgeoffset))->owner == r_pedge))
|
||||
{
|
||||
R_EmitCachedEdge ();
|
||||
r_lastvertvalid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assume it's cacheable
|
||||
cacheoffset = (byte *)edge_p - (byte *)r_edges;
|
||||
r_leftclipped = r_rightclipped = false;
|
||||
R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
|
||||
&r_pcurrentvertbase[r_pedge->v[0]],
|
||||
pclip);
|
||||
r_pedge->cachededgeoffset = cacheoffset;
|
||||
|
||||
if (r_leftclipped)
|
||||
makeleftedge = true;
|
||||
if (r_rightclipped)
|
||||
makerightedge = true;
|
||||
r_lastvertvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if there was a clip off the left edge, add that edge too
|
||||
// FIXME: faster to do in screen space?
|
||||
// FIXME: share clipped edges?
|
||||
if (makeleftedge)
|
||||
{
|
||||
r_pedge = &tedge;
|
||||
r_lastvertvalid = false;
|
||||
R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
|
||||
}
|
||||
|
||||
// if there was a clip off the right edge, get the right r_nearzi
|
||||
if (makerightedge)
|
||||
{
|
||||
r_pedge = &tedge;
|
||||
r_lastvertvalid = false;
|
||||
r_nearzionly = true;
|
||||
R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
|
||||
}
|
||||
|
||||
// if no edges made it out, return without posting the surface
|
||||
if (!r_emitted)
|
||||
return;
|
||||
|
||||
r_polycount++;
|
||||
|
||||
surface_p->msurf = fa;
|
||||
surface_p->nearzi = r_nearzi;
|
||||
surface_p->flags = fa->flags;
|
||||
surface_p->insubmodel = insubmodel;
|
||||
surface_p->spanstate = 0;
|
||||
surface_p->entity = currententity;
|
||||
surface_p->key = r_currentkey++;
|
||||
surface_p->spans = NULL;
|
||||
|
||||
pplane = fa->plane;
|
||||
// FIXME: cache this?
|
||||
TransformVector (pplane->normal, p_normal);
|
||||
// FIXME: cache this?
|
||||
distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
|
||||
|
||||
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
|
||||
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
|
||||
surface_p->d_ziorigin = p_normal[2] * distinv -
|
||||
xcenter * surface_p->d_zistepu -
|
||||
ycenter * surface_p->d_zistepv;
|
||||
|
||||
surface_p++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RenderBmodelFace
|
||||
================
|
||||
*/
|
||||
void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
|
||||
{
|
||||
int i;
|
||||
unsigned mask;
|
||||
mplane_t *pplane;
|
||||
float distinv;
|
||||
vec3_t p_normal;
|
||||
medge_t tedge;
|
||||
clipplane_t *pclip;
|
||||
|
||||
if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
||||
{
|
||||
psurf->nextalphasurface = r_alpha_surfaces;
|
||||
r_alpha_surfaces = psurf;
|
||||
return;
|
||||
}
|
||||
|
||||
// skip out if no more surfs
|
||||
if (surface_p >= surf_max)
|
||||
{
|
||||
r_outofsurfaces++;
|
||||
return;
|
||||
}
|
||||
|
||||
// ditto if not enough edges left, or switch to auxedges if possible
|
||||
if ((edge_p + psurf->numedges + 4) >= edge_max)
|
||||
{
|
||||
r_outofedges += psurf->numedges;
|
||||
return;
|
||||
}
|
||||
|
||||
c_faceclip++;
|
||||
|
||||
// this is a dummy to give the caching mechanism someplace to write to
|
||||
r_pedge = &tedge;
|
||||
|
||||
// set up clip planes
|
||||
pclip = NULL;
|
||||
|
||||
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
|
||||
{
|
||||
if (r_clipflags & mask)
|
||||
{
|
||||
view_clipplanes[i].next = pclip;
|
||||
pclip = &view_clipplanes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// push the edges through
|
||||
r_emitted = 0;
|
||||
r_nearzi = 0;
|
||||
r_nearzionly = false;
|
||||
makeleftedge = makerightedge = false;
|
||||
// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
|
||||
// can be used?
|
||||
r_lastvertvalid = false;
|
||||
|
||||
for ( ; pedges ; pedges = pedges->pnext)
|
||||
{
|
||||
r_leftclipped = r_rightclipped = false;
|
||||
R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
|
||||
|
||||
if (r_leftclipped)
|
||||
makeleftedge = true;
|
||||
if (r_rightclipped)
|
||||
makerightedge = true;
|
||||
}
|
||||
|
||||
// if there was a clip off the left edge, add that edge too
|
||||
// FIXME: faster to do in screen space?
|
||||
// FIXME: share clipped edges?
|
||||
if (makeleftedge)
|
||||
{
|
||||
r_pedge = &tedge;
|
||||
R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
|
||||
}
|
||||
|
||||
// if there was a clip off the right edge, get the right r_nearzi
|
||||
if (makerightedge)
|
||||
{
|
||||
r_pedge = &tedge;
|
||||
r_nearzionly = true;
|
||||
R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
|
||||
}
|
||||
|
||||
// if no edges made it out, return without posting the surface
|
||||
if (!r_emitted)
|
||||
return;
|
||||
|
||||
r_polycount++;
|
||||
|
||||
surface_p->msurf = psurf;
|
||||
surface_p->nearzi = r_nearzi;
|
||||
surface_p->flags = psurf->flags;
|
||||
surface_p->insubmodel = true;
|
||||
surface_p->spanstate = 0;
|
||||
surface_p->entity = currententity;
|
||||
surface_p->key = r_currentbkey;
|
||||
surface_p->spans = NULL;
|
||||
|
||||
pplane = psurf->plane;
|
||||
// FIXME: cache this?
|
||||
TransformVector (pplane->normal, p_normal);
|
||||
// FIXME: cache this?
|
||||
distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
|
||||
|
||||
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
|
||||
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
|
||||
surface_p->d_ziorigin = p_normal[2] * distinv -
|
||||
xcenter * surface_p->d_zistepu -
|
||||
ycenter * surface_p->d_zistepv;
|
||||
|
||||
surface_p++;
|
||||
}
|
564
src/client/refresh/soft/r_scan.c
Normal file
564
src/client/refresh/soft/r_scan.c
Normal file
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// d_scan.c
|
||||
//
|
||||
// Portable C scan-level rasterization code, all pixel depths.
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
pixel_t *r_turb_pbase, *r_turb_pdest;
|
||||
int r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
|
||||
int *r_turb_turb;
|
||||
int r_turb_spancount;
|
||||
|
||||
void D_DrawTurbulent8Span (void);
|
||||
|
||||
byte **warp_rowptr;
|
||||
int *warp_column;
|
||||
espan_t *edge_basespans;
|
||||
|
||||
/*
|
||||
=============
|
||||
D_WarpScreen
|
||||
|
||||
this performs a slight compression of the screen at the same time as
|
||||
the sine warp, to keep the edges from wrapping
|
||||
=============
|
||||
*/
|
||||
void D_WarpScreen (void)
|
||||
{
|
||||
int w, h;
|
||||
int u,v;
|
||||
pixel_t *dest;
|
||||
int *turb;
|
||||
byte **row;
|
||||
|
||||
static int cached_width, cached_height;
|
||||
|
||||
//
|
||||
// these are constant over resolutions, and can be saved
|
||||
//
|
||||
w = r_newrefdef.width;
|
||||
h = r_newrefdef.height;
|
||||
if (w != cached_width || h != cached_height)
|
||||
{
|
||||
cached_width = w;
|
||||
cached_height = h;
|
||||
for (v=0 ; v<h+AMP2*2 ; v++)
|
||||
{
|
||||
int v2;
|
||||
|
||||
v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height);
|
||||
warp_rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2);
|
||||
}
|
||||
|
||||
for (u=0 ; u<w+AMP2*2 ; u++)
|
||||
{
|
||||
int u2;
|
||||
|
||||
u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width);
|
||||
warp_column[u] = u2;
|
||||
}
|
||||
}
|
||||
|
||||
turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
|
||||
dest = vid_buffer + r_newrefdef.y * vid.width + r_newrefdef.x;
|
||||
|
||||
for (v=0 ; v<h ; v++, dest += vid.width)
|
||||
{
|
||||
int *col;
|
||||
|
||||
col = warp_column + turb[v];
|
||||
row = warp_rowptr + v;
|
||||
for (u=0 ; u<w ; u++)
|
||||
{
|
||||
dest[u] = row[turb[u]][col[u]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
D_DrawTurbulent8Span
|
||||
=============
|
||||
*/
|
||||
void D_DrawTurbulent8Span (void)
|
||||
{
|
||||
do
|
||||
{
|
||||
int sturb, tturb;
|
||||
sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
|
||||
tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
|
||||
*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
|
||||
r_turb_s += r_turb_sstep;
|
||||
r_turb_t += r_turb_tstep;
|
||||
} while (--r_turb_spancount > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Turbulent8
|
||||
=============
|
||||
*/
|
||||
void Turbulent8 (espan_t *pspan)
|
||||
{
|
||||
int snext, tnext;
|
||||
float spancountminus1;
|
||||
float sdivz16stepu, tdivz16stepu, zi16stepu;
|
||||
|
||||
r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
|
||||
|
||||
r_turb_sstep = 0; // keep compiler happy
|
||||
r_turb_tstep = 0; // ditto
|
||||
|
||||
r_turb_pbase = (unsigned char *)cacheblock;
|
||||
|
||||
sdivz16stepu = d_sdivzstepu * 16;
|
||||
tdivz16stepu = d_tdivzstepu * 16;
|
||||
zi16stepu = d_zistepu * 16;
|
||||
|
||||
do
|
||||
{
|
||||
int count;
|
||||
float sdivz, tdivz, zi, z, du, dv;
|
||||
|
||||
r_turb_pdest = d_viewbuffer + (r_screenwidth * pspan->v) + pspan->u;
|
||||
|
||||
count = pspan->count;
|
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u;
|
||||
dv = (float)pspan->v;
|
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
|
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
r_turb_s = (int)(sdivz * z) + sadjust;
|
||||
if (r_turb_s > bbextents)
|
||||
r_turb_s = bbextents;
|
||||
else if (r_turb_s < 0)
|
||||
r_turb_s = 0;
|
||||
|
||||
r_turb_t = (int)(tdivz * z) + tadjust;
|
||||
if (r_turb_t > bbextentt)
|
||||
r_turb_t = bbextentt;
|
||||
else if (r_turb_t < 0)
|
||||
r_turb_t = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 16)
|
||||
r_turb_spancount = 16;
|
||||
else
|
||||
r_turb_spancount = count;
|
||||
|
||||
count -= r_turb_spancount;
|
||||
|
||||
if (count)
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz16stepu;
|
||||
tdivz += tdivz16stepu;
|
||||
zi += zi16stepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 16)
|
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 16)
|
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
r_turb_sstep = (snext - r_turb_s) >> 4;
|
||||
r_turb_tstep = (tnext - r_turb_t) >> 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(r_turb_spancount - 1);
|
||||
sdivz += d_sdivzstepu * spancountminus1;
|
||||
tdivz += d_tdivzstepu * spancountminus1;
|
||||
zi += d_zistepu * spancountminus1;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 16)
|
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 16)
|
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
if (r_turb_spancount > 1)
|
||||
{
|
||||
r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
|
||||
r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
r_turb_s = r_turb_s & ((CYCLE<<16)-1);
|
||||
r_turb_t = r_turb_t & ((CYCLE<<16)-1);
|
||||
|
||||
D_DrawTurbulent8Span ();
|
||||
|
||||
r_turb_s = snext;
|
||||
r_turb_t = tnext;
|
||||
|
||||
} while (count > 0);
|
||||
|
||||
} while ((pspan = pspan->pnext) != NULL);
|
||||
}
|
||||
|
||||
//====================
|
||||
//PGM
|
||||
/*
|
||||
=============
|
||||
NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures
|
||||
but the turbulence is automatically 0.
|
||||
=============
|
||||
*/
|
||||
void NonTurbulent8 (espan_t *pspan)
|
||||
{
|
||||
int snext, tnext;
|
||||
float spancountminus1;
|
||||
float sdivz16stepu, tdivz16stepu, zi16stepu;
|
||||
|
||||
r_turb_turb = blanktable;
|
||||
|
||||
r_turb_sstep = 0; // keep compiler happy
|
||||
r_turb_tstep = 0; // ditto
|
||||
|
||||
r_turb_pbase = (unsigned char *)cacheblock;
|
||||
|
||||
sdivz16stepu = d_sdivzstepu * 16;
|
||||
tdivz16stepu = d_tdivzstepu * 16;
|
||||
zi16stepu = d_zistepu * 16;
|
||||
|
||||
do
|
||||
{
|
||||
int count;
|
||||
float sdivz, tdivz, zi, z, dv, du;
|
||||
|
||||
r_turb_pdest = d_viewbuffer + (r_screenwidth * pspan->v) + pspan->u;
|
||||
|
||||
count = pspan->count;
|
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u;
|
||||
dv = (float)pspan->v;
|
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
|
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
r_turb_s = (int)(sdivz * z) + sadjust;
|
||||
if (r_turb_s > bbextents)
|
||||
r_turb_s = bbextents;
|
||||
else if (r_turb_s < 0)
|
||||
r_turb_s = 0;
|
||||
|
||||
r_turb_t = (int)(tdivz * z) + tadjust;
|
||||
if (r_turb_t > bbextentt)
|
||||
r_turb_t = bbextentt;
|
||||
else if (r_turb_t < 0)
|
||||
r_turb_t = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 16)
|
||||
r_turb_spancount = 16;
|
||||
else
|
||||
r_turb_spancount = count;
|
||||
|
||||
count -= r_turb_spancount;
|
||||
|
||||
if (count)
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz16stepu;
|
||||
tdivz += tdivz16stepu;
|
||||
zi += zi16stepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 16)
|
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 16)
|
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
r_turb_sstep = (snext - r_turb_s) >> 4;
|
||||
r_turb_tstep = (tnext - r_turb_t) >> 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(r_turb_spancount - 1);
|
||||
sdivz += d_sdivzstepu * spancountminus1;
|
||||
tdivz += d_tdivzstepu * spancountminus1;
|
||||
zi += d_zistepu * spancountminus1;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 16)
|
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 16)
|
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
if (r_turb_spancount > 1)
|
||||
{
|
||||
r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
|
||||
r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
r_turb_s = r_turb_s & ((CYCLE<<16)-1);
|
||||
r_turb_t = r_turb_t & ((CYCLE<<16)-1);
|
||||
|
||||
D_DrawTurbulent8Span ();
|
||||
|
||||
r_turb_s = snext;
|
||||
r_turb_t = tnext;
|
||||
|
||||
} while (count > 0);
|
||||
|
||||
} while ((pspan = pspan->pnext) != NULL);
|
||||
}
|
||||
//PGM
|
||||
//====================
|
||||
|
||||
/*
|
||||
=============
|
||||
D_DrawSpans16
|
||||
|
||||
FIXME: actually make this subdivide by 16 instead of 8!!!
|
||||
=============
|
||||
*/
|
||||
void D_DrawSpans16 (espan_t *pspan)
|
||||
{
|
||||
int spancount;
|
||||
unsigned char *pbase;
|
||||
int snext, tnext, sstep, tstep;
|
||||
float spancountminus1;
|
||||
float sdivz8stepu, tdivz8stepu, zi8stepu;
|
||||
|
||||
sstep = 0; // keep compiler happy
|
||||
tstep = 0; // ditto
|
||||
|
||||
pbase = (unsigned char *)cacheblock;
|
||||
|
||||
sdivz8stepu = d_sdivzstepu * 8;
|
||||
tdivz8stepu = d_tdivzstepu * 8;
|
||||
zi8stepu = d_zistepu * 8;
|
||||
|
||||
do
|
||||
{
|
||||
pixel_t *pdest;
|
||||
int count, s, t;
|
||||
float sdivz, tdivz, zi, z, du, dv;
|
||||
|
||||
pdest = d_viewbuffer + (r_screenwidth * pspan->v) + pspan->u;
|
||||
|
||||
count = pspan->count;
|
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u;
|
||||
dv = (float)pspan->v;
|
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
|
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
s = (int)(sdivz * z) + sadjust;
|
||||
if (s > bbextents)
|
||||
s = bbextents;
|
||||
else if (s < 0)
|
||||
s = 0;
|
||||
|
||||
t = (int)(tdivz * z) + tadjust;
|
||||
if (t > bbextentt)
|
||||
t = bbextentt;
|
||||
else if (t < 0)
|
||||
t = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 8)
|
||||
spancount = 8;
|
||||
else
|
||||
spancount = count;
|
||||
|
||||
count -= spancount;
|
||||
|
||||
if (count)
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz8stepu;
|
||||
tdivz += tdivz8stepu;
|
||||
zi += zi8stepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 8)
|
||||
snext = 8; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 8)
|
||||
tnext = 8; // guard against round-off error on <0 steps
|
||||
|
||||
sstep = (snext - s) >> 3;
|
||||
tstep = (tnext - t) >> 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(spancount - 1);
|
||||
sdivz += d_sdivzstepu * spancountminus1;
|
||||
tdivz += d_tdivzstepu * spancountminus1;
|
||||
zi += d_zistepu * spancountminus1;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 8)
|
||||
snext = 8; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 8)
|
||||
tnext = 8; // guard against round-off error on <0 steps
|
||||
|
||||
if (spancount > 1)
|
||||
{
|
||||
sstep = (snext - s) / (spancount - 1);
|
||||
tstep = (tnext - t) / (spancount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
|
||||
s += sstep;
|
||||
t += tstep;
|
||||
} while (--spancount > 0);
|
||||
|
||||
s = snext;
|
||||
t = tnext;
|
||||
|
||||
} while (count > 0);
|
||||
|
||||
} while ((pspan = pspan->pnext) != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
D_DrawZSpans
|
||||
=============
|
||||
*/
|
||||
void D_DrawZSpans (espan_t *pspan)
|
||||
{
|
||||
int izistep;
|
||||
|
||||
// FIXME: check for clamping/range problems
|
||||
// we count on FP exceptions being turned off to avoid range problems
|
||||
izistep = (int)(d_zistepu * 0x8000 * 0x10000);
|
||||
|
||||
do
|
||||
{
|
||||
int count;
|
||||
int izi;
|
||||
zvalue_t *pdest;
|
||||
float zi;
|
||||
float du, dv;
|
||||
|
||||
pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
|
||||
|
||||
count = pspan->count;
|
||||
|
||||
// calculate the initial 1/z
|
||||
du = (float)pspan->u;
|
||||
dv = (float)pspan->v;
|
||||
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
|
||||
// we count on FP exceptions being turned off to avoid range problems
|
||||
izi = (int)(zi * 0x8000 * 0x10000);
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
*pdest++ = izi >> 16;
|
||||
izi += izistep;
|
||||
count--;
|
||||
}
|
||||
} while ((pspan = pspan->pnext) != NULL);
|
||||
}
|
113
src/client/refresh/soft/r_sprite.c
Normal file
113
src/client/refresh/soft/r_sprite.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_sprite.c
|
||||
#include "r_local.h"
|
||||
|
||||
extern polydesc_t r_polydesc;
|
||||
|
||||
void R_BuildPolygonFromSurface(msurface_t *fa);
|
||||
void R_PolygonCalculateGradients (void);
|
||||
|
||||
extern void R_PolyChooseSpanletRoutine( float alpha, qboolean isturbulent );
|
||||
|
||||
extern vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
|
||||
|
||||
extern void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured );
|
||||
|
||||
/*
|
||||
** R_DrawSprite
|
||||
**
|
||||
** Draw currententity / currentmodel as a single texture
|
||||
** mapped polygon
|
||||
*/
|
||||
void R_DrawSprite (void)
|
||||
{
|
||||
vec5_t *pverts;
|
||||
vec3_t left, up, right, down;
|
||||
dsprite_t *s_psprite;
|
||||
dsprframe_t *s_psprframe;
|
||||
|
||||
|
||||
s_psprite = (dsprite_t *)currentmodel->extradata;
|
||||
currententity->frame %= s_psprite->numframes;
|
||||
|
||||
s_psprframe = &s_psprite->frames[currententity->frame];
|
||||
|
||||
r_polydesc.pixels = currentmodel->skins[currententity->frame]->pixels[0];
|
||||
r_polydesc.pixel_width = s_psprframe->width;
|
||||
r_polydesc.pixel_height = s_psprframe->height;
|
||||
r_polydesc.dist = 0;
|
||||
|
||||
// generate the sprite's axes, completely parallel to the viewplane.
|
||||
VectorCopy (vup, r_polydesc.vup);
|
||||
VectorCopy (vright, r_polydesc.vright);
|
||||
VectorCopy (vpn, r_polydesc.vpn);
|
||||
|
||||
// build the sprite poster in worldspace
|
||||
VectorScale (r_polydesc.vright,
|
||||
s_psprframe->width - s_psprframe->origin_x, right);
|
||||
VectorScale (r_polydesc.vup,
|
||||
s_psprframe->height - s_psprframe->origin_y, up);
|
||||
VectorScale (r_polydesc.vright,
|
||||
-s_psprframe->origin_x, left);
|
||||
VectorScale (r_polydesc.vup,
|
||||
-s_psprframe->origin_y, down);
|
||||
|
||||
// invert UP vector for sprites
|
||||
VectorInverse( r_polydesc.vup );
|
||||
|
||||
pverts = r_clip_verts[0];
|
||||
|
||||
pverts[0][0] = r_entorigin[0] + up[0] + left[0];
|
||||
pverts[0][1] = r_entorigin[1] + up[1] + left[1];
|
||||
pverts[0][2] = r_entorigin[2] + up[2] + left[2];
|
||||
pverts[0][3] = 0;
|
||||
pverts[0][4] = 0;
|
||||
|
||||
pverts[1][0] = r_entorigin[0] + up[0] + right[0];
|
||||
pverts[1][1] = r_entorigin[1] + up[1] + right[1];
|
||||
pverts[1][2] = r_entorigin[2] + up[2] + right[2];
|
||||
pverts[1][3] = s_psprframe->width;
|
||||
pverts[1][4] = 0;
|
||||
|
||||
pverts[2][0] = r_entorigin[0] + down[0] + right[0];
|
||||
pverts[2][1] = r_entorigin[1] + down[1] + right[1];
|
||||
pverts[2][2] = r_entorigin[2] + down[2] + right[2];
|
||||
pverts[2][3] = s_psprframe->width;
|
||||
pverts[2][4] = s_psprframe->height;
|
||||
|
||||
pverts[3][0] = r_entorigin[0] + down[0] + left[0];
|
||||
pverts[3][1] = r_entorigin[1] + down[1] + left[1];
|
||||
pverts[3][2] = r_entorigin[2] + down[2] + left[2];
|
||||
pverts[3][3] = 0;
|
||||
pverts[3][4] = s_psprframe->height;
|
||||
|
||||
r_polydesc.nump = 4;
|
||||
r_polydesc.s_offset = ( r_polydesc.pixel_width >> 1);
|
||||
r_polydesc.t_offset = ( r_polydesc.pixel_height >> 1);
|
||||
VectorCopy( modelorg, r_polydesc.viewer_position );
|
||||
|
||||
r_polydesc.stipple_parity = 1;
|
||||
if ( currententity->flags & RF_TRANSLUCENT )
|
||||
R_ClipAndDrawPoly ( currententity->alpha, false, true );
|
||||
else
|
||||
R_ClipAndDrawPoly ( 1.0F, false, true );
|
||||
r_polydesc.stipple_parity = 0;
|
||||
}
|
628
src/client/refresh/soft/r_surf.c
Normal file
628
src/client/refresh/soft/r_surf.c
Normal file
|
@ -0,0 +1,628 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_surf.c: surface-related refresh code
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
drawsurf_t r_drawsurf;
|
||||
|
||||
int lightleft, sourcesstep, blocksize, sourcetstep;
|
||||
int lightdelta, lightdeltastep;
|
||||
int lightright, lightleftstep, lightrightstep, blockdivshift;
|
||||
unsigned blockdivmask;
|
||||
void *prowdestbase;
|
||||
unsigned char *pbasesource;
|
||||
int surfrowbytes; // used by ASM files
|
||||
unsigned *r_lightptr;
|
||||
int r_stepback;
|
||||
int r_lightwidth;
|
||||
int r_numhblocks, r_numvblocks;
|
||||
unsigned char *r_source, *r_sourcemax;
|
||||
|
||||
void R_DrawSurfaceBlock8_mip0 (void);
|
||||
void R_DrawSurfaceBlock8_mip1 (void);
|
||||
void R_DrawSurfaceBlock8_mip2 (void);
|
||||
void R_DrawSurfaceBlock8_mip3 (void);
|
||||
|
||||
static void (*surfmiptable[4])(void) = {
|
||||
R_DrawSurfaceBlock8_mip0,
|
||||
R_DrawSurfaceBlock8_mip1,
|
||||
R_DrawSurfaceBlock8_mip2,
|
||||
R_DrawSurfaceBlock8_mip3
|
||||
};
|
||||
|
||||
void R_BuildLightMap (void);
|
||||
extern unsigned blocklights[1024]; // allow some very large lightmaps
|
||||
|
||||
float surfscale;
|
||||
qboolean r_cache_thrash; // set if surface cache is thrashing
|
||||
|
||||
int sc_size;
|
||||
surfcache_t *sc_rover, *sc_base;
|
||||
|
||||
/*
|
||||
===============
|
||||
R_TextureAnimation
|
||||
|
||||
Returns the proper texture for a given time and base texture
|
||||
===============
|
||||
*/
|
||||
image_t *R_TextureAnimation (mtexinfo_t *tex)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (!tex->next)
|
||||
return tex->image;
|
||||
|
||||
c = currententity->frame % tex->numframes;
|
||||
while (c)
|
||||
{
|
||||
tex = tex->next;
|
||||
c--;
|
||||
}
|
||||
|
||||
return tex->image;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_DrawSurface
|
||||
===============
|
||||
*/
|
||||
void R_DrawSurface (void)
|
||||
{
|
||||
unsigned char *basetptr;
|
||||
int smax, tmax, twidth;
|
||||
int u;
|
||||
int soffset, basetoffset, texwidth;
|
||||
int horzblockstep;
|
||||
unsigned char *pcolumndest;
|
||||
void (*pblockdrawer)(void);
|
||||
image_t *mt;
|
||||
|
||||
surfrowbytes = r_drawsurf.rowbytes;
|
||||
|
||||
mt = r_drawsurf.image;
|
||||
|
||||
r_source = mt->pixels[r_drawsurf.surfmip];
|
||||
|
||||
// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
|
||||
// from a source range of 0 - 255
|
||||
|
||||
texwidth = mt->width >> r_drawsurf.surfmip;
|
||||
|
||||
blocksize = 16 >> r_drawsurf.surfmip;
|
||||
blockdivshift = 4 - r_drawsurf.surfmip;
|
||||
blockdivmask = (1 << blockdivshift) - 1;
|
||||
|
||||
r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
|
||||
|
||||
r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
|
||||
r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
|
||||
|
||||
//==============================
|
||||
|
||||
pblockdrawer = surfmiptable[r_drawsurf.surfmip];
|
||||
// TODO: only needs to be set when there is a display settings change
|
||||
horzblockstep = blocksize;
|
||||
|
||||
smax = mt->width >> r_drawsurf.surfmip;
|
||||
twidth = texwidth;
|
||||
tmax = mt->height >> r_drawsurf.surfmip;
|
||||
sourcetstep = texwidth;
|
||||
r_stepback = tmax * twidth;
|
||||
|
||||
r_sourcemax = r_source + (tmax * smax);
|
||||
|
||||
soffset = r_drawsurf.surf->texturemins[0];
|
||||
basetoffset = r_drawsurf.surf->texturemins[1];
|
||||
|
||||
// << 16 components are to guarantee positive values for %
|
||||
soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
|
||||
basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip)
|
||||
+ (tmax << 16)) % tmax) * twidth)];
|
||||
|
||||
pcolumndest = r_drawsurf.surfdat;
|
||||
|
||||
for (u=0 ; u<r_numhblocks; u++)
|
||||
{
|
||||
r_lightptr = blocklights + u;
|
||||
|
||||
prowdestbase = pcolumndest;
|
||||
|
||||
pbasesource = basetptr + soffset;
|
||||
|
||||
(*pblockdrawer)();
|
||||
|
||||
soffset = soffset + blocksize;
|
||||
if (soffset >= smax)
|
||||
soffset = 0;
|
||||
|
||||
pcolumndest += horzblockstep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSurfaceBlock8_mip0
|
||||
================
|
||||
*/
|
||||
void R_DrawSurfaceBlock8_mip0 (void)
|
||||
{
|
||||
int v, i, b, lightstep, lighttemp, light;
|
||||
unsigned char pix, *psource, *prowdest;
|
||||
|
||||
psource = pbasesource;
|
||||
prowdest = prowdestbase;
|
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++)
|
||||
{
|
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0];
|
||||
lightright = r_lightptr[1];
|
||||
r_lightptr += r_lightwidth;
|
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 4;
|
||||
lightrightstep = (r_lightptr[1] - lightright) >> 4;
|
||||
|
||||
for (i=0 ; i<16 ; i++)
|
||||
{
|
||||
lighttemp = lightleft - lightright;
|
||||
lightstep = lighttemp >> 4;
|
||||
|
||||
light = lightright;
|
||||
|
||||
for (b=15; b>=0; b--)
|
||||
{
|
||||
pix = psource[b];
|
||||
prowdest[b] = ((unsigned char *)vid_colormap)
|
||||
[(light & 0xFF00) + pix];
|
||||
light += lightstep;
|
||||
}
|
||||
|
||||
psource += sourcetstep;
|
||||
lightright += lightrightstep;
|
||||
lightleft += lightleftstep;
|
||||
prowdest += surfrowbytes;
|
||||
}
|
||||
|
||||
if (psource >= r_sourcemax)
|
||||
psource -= r_stepback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSurfaceBlock8_mip1
|
||||
================
|
||||
*/
|
||||
void R_DrawSurfaceBlock8_mip1 (void)
|
||||
{
|
||||
int v, i, b, lightstep, lighttemp, light;
|
||||
unsigned char pix, *psource, *prowdest;
|
||||
|
||||
psource = pbasesource;
|
||||
prowdest = prowdestbase;
|
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++)
|
||||
{
|
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0];
|
||||
lightright = r_lightptr[1];
|
||||
r_lightptr += r_lightwidth;
|
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 3;
|
||||
lightrightstep = (r_lightptr[1] - lightright) >> 3;
|
||||
|
||||
for (i=0 ; i<8 ; i++)
|
||||
{
|
||||
lighttemp = lightleft - lightright;
|
||||
lightstep = lighttemp >> 3;
|
||||
|
||||
light = lightright;
|
||||
|
||||
for (b=7; b>=0; b--)
|
||||
{
|
||||
pix = psource[b];
|
||||
prowdest[b] = ((unsigned char *)vid_colormap)
|
||||
[(light & 0xFF00) + pix];
|
||||
light += lightstep;
|
||||
}
|
||||
|
||||
psource += sourcetstep;
|
||||
lightright += lightrightstep;
|
||||
lightleft += lightleftstep;
|
||||
prowdest += surfrowbytes;
|
||||
}
|
||||
|
||||
if (psource >= r_sourcemax)
|
||||
psource -= r_stepback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSurfaceBlock8_mip2
|
||||
================
|
||||
*/
|
||||
void R_DrawSurfaceBlock8_mip2 (void)
|
||||
{
|
||||
int v, i, b, lightstep, lighttemp, light;
|
||||
unsigned char pix, *psource, *prowdest;
|
||||
|
||||
psource = pbasesource;
|
||||
prowdest = prowdestbase;
|
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++)
|
||||
{
|
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0];
|
||||
lightright = r_lightptr[1];
|
||||
r_lightptr += r_lightwidth;
|
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 2;
|
||||
lightrightstep = (r_lightptr[1] - lightright) >> 2;
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
lighttemp = lightleft - lightright;
|
||||
lightstep = lighttemp >> 2;
|
||||
|
||||
light = lightright;
|
||||
|
||||
for (b=3; b>=0; b--)
|
||||
{
|
||||
pix = psource[b];
|
||||
prowdest[b] = ((unsigned char *)vid_colormap)
|
||||
[(light & 0xFF00) + pix];
|
||||
light += lightstep;
|
||||
}
|
||||
|
||||
psource += sourcetstep;
|
||||
lightright += lightrightstep;
|
||||
lightleft += lightleftstep;
|
||||
prowdest += surfrowbytes;
|
||||
}
|
||||
|
||||
if (psource >= r_sourcemax)
|
||||
psource -= r_stepback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSurfaceBlock8_mip3
|
||||
================
|
||||
*/
|
||||
void R_DrawSurfaceBlock8_mip3 (void)
|
||||
{
|
||||
int v, i, b, lightstep, lighttemp, light;
|
||||
unsigned char pix, *psource, *prowdest;
|
||||
|
||||
psource = pbasesource;
|
||||
prowdest = prowdestbase;
|
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++)
|
||||
{
|
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0];
|
||||
lightright = r_lightptr[1];
|
||||
r_lightptr += r_lightwidth;
|
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 1;
|
||||
lightrightstep = (r_lightptr[1] - lightright) >> 1;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
lighttemp = lightleft - lightright;
|
||||
lightstep = lighttemp >> 1;
|
||||
|
||||
light = lightright;
|
||||
|
||||
for (b=1; b>=0; b--)
|
||||
{
|
||||
pix = psource[b];
|
||||
prowdest[b] = ((unsigned char *)vid_colormap)
|
||||
[(light & 0xFF00) + pix];
|
||||
light += lightstep;
|
||||
}
|
||||
|
||||
psource += sourcetstep;
|
||||
lightright += lightrightstep;
|
||||
lightleft += lightleftstep;
|
||||
prowdest += surfrowbytes;
|
||||
}
|
||||
|
||||
if (psource >= r_sourcemax)
|
||||
psource -= r_stepback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_InitCaches
|
||||
|
||||
================
|
||||
*/
|
||||
void R_InitCaches (void)
|
||||
{
|
||||
int size;
|
||||
|
||||
// calculate size to allocate
|
||||
if (sw_surfcacheoverride->value)
|
||||
{
|
||||
size = sw_surfcacheoverride->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
int pix;
|
||||
size = SURFCACHE_SIZE_AT_320X240;
|
||||
|
||||
pix = vid.width*vid.height;
|
||||
if (pix > 64000)
|
||||
size += (pix-64000)*3;
|
||||
}
|
||||
|
||||
// round up to page size
|
||||
size = (size + 8191) & ~8191;
|
||||
|
||||
R_Printf(PRINT_ALL,"%ik surface cache\n", size/1024);
|
||||
|
||||
sc_size = size;
|
||||
sc_base = (surfcache_t *)malloc(size);
|
||||
sc_rover = sc_base;
|
||||
|
||||
sc_base->next = NULL;
|
||||
sc_base->owner = NULL;
|
||||
sc_base->size = sc_size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
D_FlushCaches
|
||||
==================
|
||||
*/
|
||||
void D_FlushCaches (void)
|
||||
{
|
||||
surfcache_t *c;
|
||||
|
||||
if (!sc_base)
|
||||
return;
|
||||
|
||||
for (c = sc_base ; c ; c = c->next)
|
||||
{
|
||||
if (c->owner)
|
||||
*c->owner = NULL;
|
||||
}
|
||||
|
||||
sc_rover = sc_base;
|
||||
sc_base->next = NULL;
|
||||
sc_base->owner = NULL;
|
||||
sc_base->size = sc_size;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
D_SCAlloc
|
||||
=================
|
||||
*/
|
||||
surfcache_t *D_SCAlloc (int width, int size)
|
||||
{
|
||||
surfcache_t *new;
|
||||
qboolean wrapped_this_time;
|
||||
|
||||
if ((width < 0) || (width > 256))
|
||||
ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache width %d\n", width);
|
||||
|
||||
if ((size <= 0) || (size > 0x10000))
|
||||
ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache size %d\n", size);
|
||||
|
||||
// Add header size
|
||||
size += ((char*)sc_base->data - (char*)sc_base);
|
||||
size = (size + 3) & ~3;
|
||||
if (size > sc_size)
|
||||
ri.Sys_Error (ERR_FATAL,"D_SCAlloc: %i > cache size of %i",size, sc_size);
|
||||
|
||||
// if there is not size bytes after the rover, reset to the start
|
||||
wrapped_this_time = false;
|
||||
|
||||
if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
|
||||
{
|
||||
if (sc_rover)
|
||||
{
|
||||
wrapped_this_time = true;
|
||||
}
|
||||
sc_rover = sc_base;
|
||||
}
|
||||
|
||||
// colect and free surfcache_t blocks until the rover block is large enough
|
||||
new = sc_rover;
|
||||
if (sc_rover->owner)
|
||||
*sc_rover->owner = NULL;
|
||||
|
||||
while (new->size < size)
|
||||
{
|
||||
// free another
|
||||
sc_rover = sc_rover->next;
|
||||
if (!sc_rover)
|
||||
ri.Sys_Error (ERR_FATAL,"D_SCAlloc: hit the end of memory");
|
||||
if (sc_rover->owner)
|
||||
*sc_rover->owner = NULL;
|
||||
|
||||
new->size += sc_rover->size;
|
||||
new->next = sc_rover->next;
|
||||
}
|
||||
|
||||
// create a fragment out of any leftovers
|
||||
if (new->size - size > 256)
|
||||
{
|
||||
sc_rover = (surfcache_t *)( (byte *)new + size);
|
||||
sc_rover->size = new->size - size;
|
||||
sc_rover->next = new->next;
|
||||
sc_rover->width = 0;
|
||||
sc_rover->owner = NULL;
|
||||
new->next = sc_rover;
|
||||
new->size = size;
|
||||
}
|
||||
else
|
||||
sc_rover = new->next;
|
||||
|
||||
new->width = width;
|
||||
// DEBUG
|
||||
if (width > 0)
|
||||
new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
|
||||
|
||||
new->owner = NULL; // should be set properly after return
|
||||
|
||||
if (d_roverwrapped)
|
||||
{
|
||||
if (wrapped_this_time || (sc_rover >= d_initial_rover))
|
||||
r_cache_thrash = true;
|
||||
}
|
||||
else if (wrapped_this_time)
|
||||
{
|
||||
d_roverwrapped = true;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// if the num is not a power of 2, assume it will not repeat
|
||||
|
||||
int MaskForNum (int num)
|
||||
{
|
||||
if (num==128)
|
||||
return 127;
|
||||
if (num==64)
|
||||
return 63;
|
||||
if (num==32)
|
||||
return 31;
|
||||
if (num==16)
|
||||
return 15;
|
||||
return 255;
|
||||
}
|
||||
|
||||
int D_log2 (int num)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = 0;
|
||||
|
||||
while (num>>=1)
|
||||
c++;
|
||||
return c;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
D_CacheSurface
|
||||
================
|
||||
*/
|
||||
surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
|
||||
{
|
||||
surfcache_t *cache;
|
||||
|
||||
//
|
||||
// if the surface is animating or flashing, flush the cache
|
||||
//
|
||||
r_drawsurf.image = R_TextureAnimation (surface->texinfo);
|
||||
r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
|
||||
r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
|
||||
r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
|
||||
r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
|
||||
|
||||
//
|
||||
// see if the cache holds apropriate data
|
||||
//
|
||||
cache = surface->cachespots[miplevel];
|
||||
|
||||
if (cache && !cache->dlight && surface->dlightframe != r_framecount
|
||||
&& cache->image == r_drawsurf.image
|
||||
&& cache->lightadj[0] == r_drawsurf.lightadj[0]
|
||||
&& cache->lightadj[1] == r_drawsurf.lightadj[1]
|
||||
&& cache->lightadj[2] == r_drawsurf.lightadj[2]
|
||||
&& cache->lightadj[3] == r_drawsurf.lightadj[3] )
|
||||
return cache;
|
||||
|
||||
//
|
||||
// determine shape of surface
|
||||
//
|
||||
surfscale = 1.0 / (1<<miplevel);
|
||||
r_drawsurf.surfmip = miplevel;
|
||||
r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
|
||||
r_drawsurf.rowbytes = r_drawsurf.surfwidth;
|
||||
r_drawsurf.surfheight = surface->extents[1] >> miplevel;
|
||||
|
||||
//
|
||||
// allocate memory if needed
|
||||
//
|
||||
if (!cache) // if a texture just animated, don't reallocate it
|
||||
{
|
||||
cache = D_SCAlloc (r_drawsurf.surfwidth,
|
||||
r_drawsurf.surfwidth * r_drawsurf.surfheight);
|
||||
surface->cachespots[miplevel] = cache;
|
||||
cache->owner = &surface->cachespots[miplevel];
|
||||
cache->mipscale = surfscale;
|
||||
}
|
||||
|
||||
if (surface->dlightframe == r_framecount)
|
||||
cache->dlight = 1;
|
||||
else
|
||||
cache->dlight = 0;
|
||||
|
||||
r_drawsurf.surfdat = (pixel_t *)cache->data;
|
||||
|
||||
cache->image = r_drawsurf.image;
|
||||
cache->lightadj[0] = r_drawsurf.lightadj[0];
|
||||
cache->lightadj[1] = r_drawsurf.lightadj[1];
|
||||
cache->lightadj[2] = r_drawsurf.lightadj[2];
|
||||
cache->lightadj[3] = r_drawsurf.lightadj[3];
|
||||
|
||||
//
|
||||
// draw and light the surface texture
|
||||
//
|
||||
r_drawsurf.surf = surface;
|
||||
|
||||
c_surf++;
|
||||
|
||||
// calculate the lightings
|
||||
R_BuildLightMap ();
|
||||
|
||||
// rasterize the surface into the cache
|
||||
R_DrawSurface ();
|
||||
|
||||
return cache;
|
||||
}
|
|
@ -290,7 +290,7 @@ S_RegisterSound(char *name)
|
|||
{
|
||||
sfx_t *sfx;
|
||||
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -310,8 +310,6 @@ struct sfx_s *
|
|||
S_RegisterSexedSound(entity_state_t *ent, char *base)
|
||||
{
|
||||
int n;
|
||||
char *p;
|
||||
int len;
|
||||
struct sfx_s *sfx;
|
||||
char model[MAX_QPATH];
|
||||
char sexedFilename[MAX_QPATH];
|
||||
|
@ -323,6 +321,7 @@ S_RegisterSexedSound(entity_state_t *ent, char *base)
|
|||
|
||||
if (cl.configstrings[n][0])
|
||||
{
|
||||
char *p;
|
||||
p = strchr(cl.configstrings[n], '\\');
|
||||
|
||||
if (p)
|
||||
|
@ -351,6 +350,8 @@ S_RegisterSexedSound(entity_state_t *ent, char *base)
|
|||
|
||||
if (!sfx)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* no, so see if it exists */
|
||||
len = FS_LoadFile(&sexedFilename[1], NULL);
|
||||
|
||||
|
@ -622,7 +623,7 @@ S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx,
|
|||
sfxcache_t *sc;
|
||||
playsound_t *ps, *sort;
|
||||
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -724,7 +725,7 @@ S_StartLocalSound(char *sound)
|
|||
{
|
||||
sfx_t *sfx;
|
||||
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -748,7 +749,7 @@ S_StopAllSounds(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -828,7 +829,7 @@ void
|
|||
S_RawSamples(int samples, int rate, int width,
|
||||
int channels, byte *data, float volume)
|
||||
{
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -862,7 +863,7 @@ void
|
|||
S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
|
||||
{
|
||||
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -984,7 +985,7 @@ S_SoundList(void)
|
|||
void
|
||||
S_SoundInfo_f(void)
|
||||
{
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
Com_Printf("Sound system not started\n");
|
||||
return;
|
||||
|
@ -1086,7 +1087,7 @@ S_Shutdown(void)
|
|||
int i;
|
||||
sfx_t *sfx;
|
||||
|
||||
if (!sound_started)
|
||||
if (sound_started == SS_NOT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,6 @@ wavinfo_t
|
|||
GetWavinfo(char *name, byte *wav, int wavlength)
|
||||
{
|
||||
wavinfo_t info;
|
||||
int i;
|
||||
int format;
|
||||
int samples;
|
||||
|
||||
|
@ -156,7 +155,7 @@ GetWavinfo(char *name, byte *wav, int wavlength)
|
|||
data_p += 32;
|
||||
info.loopstart = GetLittleLong();
|
||||
|
||||
/* if the next chunk is a LIST chunk,
|
||||
/* if the next chunk is a LIST chunk,
|
||||
look for a cue length marker */
|
||||
FindNextChunk("LIST");
|
||||
|
||||
|
@ -165,7 +164,9 @@ GetWavinfo(char *name, byte *wav, int wavlength)
|
|||
if (((data_p - wav) + 32 <= wavlength) &&
|
||||
!strncmp((const char *)data_p + 28, "mark", 4))
|
||||
{
|
||||
/* this is not a proper parse,
|
||||
int i;
|
||||
|
||||
/* this is not a proper parse,
|
||||
but it works with cooledit... */
|
||||
data_p += 24;
|
||||
i = GetLittleLong(); /* samples in loop */
|
||||
|
|
|
@ -373,9 +373,13 @@ target_explosion_explode(edict_t *self)
|
|||
void
|
||||
use_target_explosion(edict_t *self, edict_t *other /* unused */, edict_t *activator)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
self->activator = activator;
|
||||
|
||||
if (!self || !activator)
|
||||
if (!activator)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -488,7 +488,7 @@ ClientObituary(edict_t *self, edict_t *inflictor /* unused */,
|
|||
return;
|
||||
}
|
||||
|
||||
if (coop->value && attacker->client)
|
||||
if (coop->value && attacker && attacker->client)
|
||||
{
|
||||
meansOfDeath |= MOD_FRIENDLY_FIRE;
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ SV_LinkEdict(edict_t *ent)
|
|||
|
||||
/* set the abs box */
|
||||
if ((ent->solid == SOLID_BSP) &&
|
||||
(ent->s.angles[0] || ent->s.angles[1] ||
|
||||
(ent->s.angles[0] || ent->s.angles[1] ||
|
||||
ent->s.angles[2]))
|
||||
{
|
||||
/* expand for rotation */
|
||||
|
@ -527,18 +527,18 @@ typedef struct
|
|||
|
||||
/*
|
||||
* Returns a headnode that can be used for testing or clipping an
|
||||
* object of mins/maxs size. Offset is filled in to contain the
|
||||
* object of mins/maxs size. Offset is filled in to contain the
|
||||
* adjustment that must be added to the testing object's origin
|
||||
* to get a point to use with the returned hull.
|
||||
*/
|
||||
int
|
||||
SV_HullForEntity(edict_t *ent)
|
||||
{
|
||||
cmodel_t *model;
|
||||
|
||||
/* decide which clipping hull to use, based on the size */
|
||||
if (ent->solid == SOLID_BSP)
|
||||
{
|
||||
cmodel_t *model;
|
||||
|
||||
/* explicit hulls in the BSP model */
|
||||
model = sv.models[ent->s.modelindex];
|
||||
|
||||
|
|
Loading…
Reference in a new issue