* deleted asm code
* added support 2k+ resolutions
* SDL2 support
This commit is contained in:
Denis Pauk 2017-12-09 13:30:52 +02:00
parent 430e21eab0
commit c43e944a3d
32 changed files with 14911 additions and 42 deletions

138
Makefile
View file

@ -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)

View file

@ -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;
}

View file

@ -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)))

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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);

File diff suppressed because it is too large Load diff

View 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();
}
}

View 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;
}
}

View 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);
}

View 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;
}
}
}

File diff suppressed because it is too large Load diff

View 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));
}
}

View 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;
}
}

View 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

File diff suppressed because it is too large Load diff

View 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;
}

File diff suppressed because it is too large Load diff

View 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__

View 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();
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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++;
}

View 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);
}

View 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;
}

View 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;
}

View file

@ -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;
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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];